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