mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			165 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
| /* Thread library support for -fsplit-stack.  */
 | |
| /* Copyright (C) 2009-2014 Free Software Foundation, Inc.
 | |
|    Contributed by Ian Lance Taylor <iant@google.com>.
 | |
| 
 | |
| 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
 | |
| <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| #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 <errno.h>
 | |
| #include <pthread.h>
 | |
| 
 | |
| #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) */
 |