/* Thread library support for -fsplit-stack. */ /* Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Ian Lance Taylor . This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ #include "tconfig.h" #include "tsystem.h" #include "coretypes.h" #include "tm.h" #include "libgcc_tm.h" /* If inhibit_libc is defined, we can not compile this file. The effect is that people will not be able to use -fsplit-stack. That is much better than failing the build particularly since people will want to define inhibit_libc while building a compiler which can build glibc. */ #ifndef inhibit_libc #include #include #include "generic-morestack.h" /* We declare the pthread functions we need as weak, so that libgcc_s.so does not need to be linked against -lpthread. */ extern int pthread_once (pthread_once_t *, void (*) (void)) __attribute__ ((weak)); extern int pthread_key_create (pthread_key_t *, void (*) (void *)) __attribute__ ((weak)); extern int pthread_setspecific (pthread_key_t, const void *) __attribute__ ((weak)); /* The key for the list of stack segments to free when the thread exits. This is created by pthread_key_create. */ static pthread_key_t segment_list_key; /* Used to only run create_key once. */ static pthread_once_t create_key_once = PTHREAD_ONCE_INIT; /* Release all the segments for a thread. This is the destructor function used by pthread_key_create, and is called when a thread exits. */ static void free_segments (void* arg) { __morestack_release_segments ((struct stack_segment **) arg, 1); } /* Set up the key for the list of segments. This is called via pthread_once. */ static void create_key (void) { int err; err = pthread_key_create (&segment_list_key, free_segments); if (err != 0) { static const char msg[] = "pthread_key_create failed: errno "; __morestack_fail (msg, sizeof msg - 1, err); } } /* Pass information from the pthread_create wrapper to stack_split_initialize_thread. */ struct pthread_create_args { void *(*start_routine) (void *); void *arg; }; /* Initialize a thread. This is called via pthread_create. It calls a target dependent function to set up any required stack guard. */ static void* stack_split_initialize_thread (void *) __attribute__ ((no_split_stack)); static void * stack_split_initialize_thread (void *varg) { struct pthread_create_args *args = (struct pthread_create_args *) varg; int err; void *(*start_routine) (void *); void *arg; __stack_split_initialize (); err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments); if (err != 0) { static const char msg[] = "pthread_setspecific failed: errno "; __morestack_fail (msg, sizeof msg - 1, err); } start_routine = args->start_routine; arg = args->arg; free (args); return (*start_routine) (arg); } /* This function wraps calls to pthread_create to make sure that the stack guard is initialized for new threads. FIXME: This hack will not be necessary if glibc supports -fsplit-stack directly. */ int __wrap_pthread_create (pthread_t *, const pthread_attr_t *, void *(*start_routine) (void *), void *) __attribute__ ((visibility ("hidden"))); extern int __real_pthread_create (pthread_t *, const pthread_attr_t *, void *(*start_routine) (void *), void *) __attribute__ ((weak)); int __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { int err; struct pthread_create_args* args; err = pthread_once (&create_key_once, create_key); if (err != 0) { static const char msg[] = "pthread_once failed: errno "; __morestack_fail (msg, sizeof msg - 1, err); } args = malloc (sizeof (struct pthread_create_args)); if (args == NULL) return EAGAIN; args->start_routine = start_routine; args->arg = arg; return __real_pthread_create (tid, attr, stack_split_initialize_thread, args); } #endif /* !defined (inhibit_libc) */