xref: /dflybsd-src/contrib/gcc-4.7/libgcc/generic-morestack-thread.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
1*e4b17023SJohn Marino /* Thread library support for -fsplit-stack.  */
2*e4b17023SJohn Marino /* Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
3*e4b17023SJohn Marino    Contributed by Ian Lance Taylor <iant@google.com>.
4*e4b17023SJohn Marino 
5*e4b17023SJohn Marino This file is part of GCC.
6*e4b17023SJohn Marino 
7*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
8*e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
9*e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
10*e4b17023SJohn Marino version.
11*e4b17023SJohn Marino 
12*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13*e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
14*e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15*e4b17023SJohn Marino for more details.
16*e4b17023SJohn Marino 
17*e4b17023SJohn Marino Under Section 7 of GPL version 3, you are granted additional
18*e4b17023SJohn Marino permissions described in the GCC Runtime Library Exception, version
19*e4b17023SJohn Marino 3.1, as published by the Free Software Foundation.
20*e4b17023SJohn Marino 
21*e4b17023SJohn Marino You should have received a copy of the GNU General Public License and
22*e4b17023SJohn Marino a copy of the GCC Runtime Library Exception along with this program;
23*e4b17023SJohn Marino see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24*e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
25*e4b17023SJohn Marino 
26*e4b17023SJohn Marino #include "tconfig.h"
27*e4b17023SJohn Marino #include "tsystem.h"
28*e4b17023SJohn Marino #include "coretypes.h"
29*e4b17023SJohn Marino #include "tm.h"
30*e4b17023SJohn Marino #include "libgcc_tm.h"
31*e4b17023SJohn Marino 
32*e4b17023SJohn Marino /* If inhibit_libc is defined, we can not compile this file.  The
33*e4b17023SJohn Marino    effect is that people will not be able to use -fsplit-stack.  That
34*e4b17023SJohn Marino    is much better than failing the build particularly since people
35*e4b17023SJohn Marino    will want to define inhibit_libc while building a compiler which
36*e4b17023SJohn Marino    can build glibc.  */
37*e4b17023SJohn Marino 
38*e4b17023SJohn Marino #ifndef inhibit_libc
39*e4b17023SJohn Marino 
40*e4b17023SJohn Marino #include <errno.h>
41*e4b17023SJohn Marino #include <pthread.h>
42*e4b17023SJohn Marino 
43*e4b17023SJohn Marino #include "generic-morestack.h"
44*e4b17023SJohn Marino 
45*e4b17023SJohn Marino /* We declare the pthread functions we need as weak, so that
46*e4b17023SJohn Marino    libgcc_s.so does not need to be linked against -lpthread.  */
47*e4b17023SJohn Marino 
48*e4b17023SJohn Marino extern int pthread_once (pthread_once_t *, void (*) (void))
49*e4b17023SJohn Marino   __attribute__ ((weak));
50*e4b17023SJohn Marino 
51*e4b17023SJohn Marino extern int pthread_key_create (pthread_key_t *, void (*) (void *))
52*e4b17023SJohn Marino   __attribute__ ((weak));
53*e4b17023SJohn Marino 
54*e4b17023SJohn Marino extern int pthread_setspecific (pthread_key_t, const void *)
55*e4b17023SJohn Marino   __attribute__ ((weak));
56*e4b17023SJohn Marino 
57*e4b17023SJohn Marino /* The key for the list of stack segments to free when the thread
58*e4b17023SJohn Marino    exits.  This is created by pthread_key_create.  */
59*e4b17023SJohn Marino 
60*e4b17023SJohn Marino static pthread_key_t segment_list_key;
61*e4b17023SJohn Marino 
62*e4b17023SJohn Marino /* Used to only run create_key once.  */
63*e4b17023SJohn Marino 
64*e4b17023SJohn Marino static pthread_once_t create_key_once = PTHREAD_ONCE_INIT;
65*e4b17023SJohn Marino 
66*e4b17023SJohn Marino /* Release all the segments for a thread.  This is the destructor
67*e4b17023SJohn Marino    function used by pthread_key_create, and is called when a thread
68*e4b17023SJohn Marino    exits.  */
69*e4b17023SJohn Marino 
70*e4b17023SJohn Marino static void
free_segments(void * arg)71*e4b17023SJohn Marino free_segments (void* arg)
72*e4b17023SJohn Marino {
73*e4b17023SJohn Marino   __morestack_release_segments ((struct stack_segment **) arg, 1);
74*e4b17023SJohn Marino }
75*e4b17023SJohn Marino 
76*e4b17023SJohn Marino /* Set up the key for the list of segments.  This is called via
77*e4b17023SJohn Marino    pthread_once.  */
78*e4b17023SJohn Marino 
79*e4b17023SJohn Marino static void
create_key(void)80*e4b17023SJohn Marino create_key (void)
81*e4b17023SJohn Marino {
82*e4b17023SJohn Marino   int err;
83*e4b17023SJohn Marino 
84*e4b17023SJohn Marino   err = pthread_key_create (&segment_list_key, free_segments);
85*e4b17023SJohn Marino   if (err != 0)
86*e4b17023SJohn Marino     {
87*e4b17023SJohn Marino       static const char msg[] = "pthread_key_create failed: errno ";
88*e4b17023SJohn Marino       __morestack_fail (msg, sizeof msg - 1, err);
89*e4b17023SJohn Marino     }
90*e4b17023SJohn Marino }
91*e4b17023SJohn Marino 
92*e4b17023SJohn Marino /* Pass information from the pthread_create wrapper to
93*e4b17023SJohn Marino    stack_split_initialize_thread.  */
94*e4b17023SJohn Marino 
95*e4b17023SJohn Marino struct pthread_create_args
96*e4b17023SJohn Marino {
97*e4b17023SJohn Marino   void *(*start_routine) (void *);
98*e4b17023SJohn Marino   void *arg;
99*e4b17023SJohn Marino };
100*e4b17023SJohn Marino 
101*e4b17023SJohn Marino /* Initialize a thread.  This is called via pthread_create.  It calls
102*e4b17023SJohn Marino    a target dependent function to set up any required stack guard.  */
103*e4b17023SJohn Marino 
104*e4b17023SJohn Marino static void* stack_split_initialize_thread (void *)
105*e4b17023SJohn Marino   __attribute__ ((no_split_stack));
106*e4b17023SJohn Marino 
107*e4b17023SJohn Marino static void *
stack_split_initialize_thread(void * varg)108*e4b17023SJohn Marino stack_split_initialize_thread (void *varg)
109*e4b17023SJohn Marino {
110*e4b17023SJohn Marino   struct pthread_create_args *args = (struct pthread_create_args *) varg;
111*e4b17023SJohn Marino   int err;
112*e4b17023SJohn Marino   void *(*start_routine) (void *);
113*e4b17023SJohn Marino   void *arg;
114*e4b17023SJohn Marino 
115*e4b17023SJohn Marino   __stack_split_initialize ();
116*e4b17023SJohn Marino 
117*e4b17023SJohn Marino   err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments);
118*e4b17023SJohn Marino   if (err != 0)
119*e4b17023SJohn Marino     {
120*e4b17023SJohn Marino       static const char msg[] = "pthread_setspecific failed: errno ";
121*e4b17023SJohn Marino       __morestack_fail (msg, sizeof msg - 1, err);
122*e4b17023SJohn Marino     }
123*e4b17023SJohn Marino 
124*e4b17023SJohn Marino   start_routine = args->start_routine;
125*e4b17023SJohn Marino   arg = args->arg;
126*e4b17023SJohn Marino   free (args);
127*e4b17023SJohn Marino   return (*start_routine) (arg);
128*e4b17023SJohn Marino }
129*e4b17023SJohn Marino 
130*e4b17023SJohn Marino /* This function wraps calls to pthread_create to make sure that the
131*e4b17023SJohn Marino    stack guard is initialized for new threads.  FIXME: This hack will
132*e4b17023SJohn Marino    not be necessary if glibc supports -fsplit-stack directly.  */
133*e4b17023SJohn Marino 
134*e4b17023SJohn Marino int __wrap_pthread_create (pthread_t *, const pthread_attr_t *,
135*e4b17023SJohn Marino 			   void *(*start_routine) (void *), void *)
136*e4b17023SJohn Marino   __attribute__ ((visibility ("hidden")));
137*e4b17023SJohn Marino 
138*e4b17023SJohn Marino extern int __real_pthread_create (pthread_t *, const pthread_attr_t *,
139*e4b17023SJohn Marino 				  void *(*start_routine) (void *), void *)
140*e4b17023SJohn Marino   __attribute__ ((weak));
141*e4b17023SJohn Marino 
142*e4b17023SJohn Marino int
__wrap_pthread_create(pthread_t * tid,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)143*e4b17023SJohn Marino __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr,
144*e4b17023SJohn Marino 		       void *(*start_routine) (void *), void *arg)
145*e4b17023SJohn Marino {
146*e4b17023SJohn Marino   int err;
147*e4b17023SJohn Marino   struct pthread_create_args* args;
148*e4b17023SJohn Marino 
149*e4b17023SJohn Marino   err = pthread_once (&create_key_once, create_key);
150*e4b17023SJohn Marino   if (err != 0)
151*e4b17023SJohn Marino     {
152*e4b17023SJohn Marino       static const char msg[] = "pthread_once failed: errno ";
153*e4b17023SJohn Marino       __morestack_fail (msg, sizeof msg - 1, err);
154*e4b17023SJohn Marino     }
155*e4b17023SJohn Marino 
156*e4b17023SJohn Marino   args = malloc (sizeof (struct pthread_create_args));
157*e4b17023SJohn Marino   if (args == NULL)
158*e4b17023SJohn Marino     return EAGAIN;
159*e4b17023SJohn Marino   args->start_routine = start_routine;
160*e4b17023SJohn Marino   args->arg = arg;
161*e4b17023SJohn Marino   return __real_pthread_create (tid, attr, stack_split_initialize_thread, args);
162*e4b17023SJohn Marino }
163*e4b17023SJohn Marino 
164*e4b17023SJohn Marino #endif /* !defined (inhibit_libc) */
165