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