xref: /netbsd-src/external/gpl3/gcc/dist/libgcc/generic-morestack-thread.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
148fb7bfaSmrg /* Thread library support for -fsplit-stack.  */
2*b1e83836Smrg /* Copyright (C) 2009-2022 Free Software Foundation, Inc.
348fb7bfaSmrg    Contributed by Ian Lance Taylor <iant@google.com>.
448fb7bfaSmrg 
548fb7bfaSmrg This file is part of GCC.
648fb7bfaSmrg 
748fb7bfaSmrg GCC is free software; you can redistribute it and/or modify it under
848fb7bfaSmrg the terms of the GNU General Public License as published by the Free
948fb7bfaSmrg Software Foundation; either version 3, or (at your option) any later
1048fb7bfaSmrg version.
1148fb7bfaSmrg 
1248fb7bfaSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1348fb7bfaSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1448fb7bfaSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1548fb7bfaSmrg for more details.
1648fb7bfaSmrg 
1748fb7bfaSmrg Under Section 7 of GPL version 3, you are granted additional
1848fb7bfaSmrg permissions described in the GCC Runtime Library Exception, version
1948fb7bfaSmrg 3.1, as published by the Free Software Foundation.
2048fb7bfaSmrg 
2148fb7bfaSmrg You should have received a copy of the GNU General Public License and
2248fb7bfaSmrg a copy of the GCC Runtime Library Exception along with this program;
2348fb7bfaSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2448fb7bfaSmrg <http://www.gnu.org/licenses/>.  */
2548fb7bfaSmrg 
2648fb7bfaSmrg #include "tconfig.h"
2748fb7bfaSmrg #include "tsystem.h"
2848fb7bfaSmrg #include "coretypes.h"
2948fb7bfaSmrg #include "tm.h"
3048fb7bfaSmrg #include "libgcc_tm.h"
3148fb7bfaSmrg 
3248fb7bfaSmrg /* If inhibit_libc is defined, we cannot compile this file.  The
3348fb7bfaSmrg    effect is that people will not be able to use -fsplit-stack.  That
3448fb7bfaSmrg    is much better than failing the build particularly since people
3548fb7bfaSmrg    will want to define inhibit_libc while building a compiler which
3648fb7bfaSmrg    can build glibc.  */
3748fb7bfaSmrg 
3848fb7bfaSmrg #ifndef inhibit_libc
3948fb7bfaSmrg 
4048fb7bfaSmrg #include <errno.h>
41*b1e83836Smrg #include <signal.h>
4248fb7bfaSmrg #include <pthread.h>
4348fb7bfaSmrg 
4448fb7bfaSmrg #include "generic-morestack.h"
4548fb7bfaSmrg 
4648fb7bfaSmrg /* We declare the pthread functions we need as weak, so that
4748fb7bfaSmrg    libgcc_s.so does not need to be linked against -lpthread.  */
4848fb7bfaSmrg 
4948fb7bfaSmrg extern int pthread_once (pthread_once_t *, void (*) (void))
5048fb7bfaSmrg   __attribute__ ((weak));
5148fb7bfaSmrg 
5248fb7bfaSmrg extern int pthread_key_create (pthread_key_t *, void (*) (void *))
5348fb7bfaSmrg   __attribute__ ((weak));
5448fb7bfaSmrg 
5548fb7bfaSmrg extern int pthread_setspecific (pthread_key_t, const void *)
5648fb7bfaSmrg   __attribute__ ((weak));
5748fb7bfaSmrg 
58*b1e83836Smrg extern int pthread_sigmask (int, const sigset_t *, sigset_t *)
59*b1e83836Smrg   __attribute__ ((weak));
60*b1e83836Smrg 
6148fb7bfaSmrg /* The key for the list of stack segments to free when the thread
6248fb7bfaSmrg    exits.  This is created by pthread_key_create.  */
6348fb7bfaSmrg 
6448fb7bfaSmrg static pthread_key_t segment_list_key;
6548fb7bfaSmrg 
6648fb7bfaSmrg /* Used to only run create_key once.  */
6748fb7bfaSmrg 
6848fb7bfaSmrg static pthread_once_t create_key_once = PTHREAD_ONCE_INIT;
6948fb7bfaSmrg 
7048fb7bfaSmrg /* Release all the segments for a thread.  This is the destructor
7148fb7bfaSmrg    function used by pthread_key_create, and is called when a thread
7248fb7bfaSmrg    exits.  */
7348fb7bfaSmrg 
7448fb7bfaSmrg static void
free_segments(void * arg)7548fb7bfaSmrg free_segments (void* arg)
7648fb7bfaSmrg {
77*b1e83836Smrg   /* We must block signals in case the signal handler tries to split
78*b1e83836Smrg      the stack.  We leave them blocked while the thread exits.  */
79*b1e83836Smrg   if (pthread_sigmask)
80*b1e83836Smrg     {
81*b1e83836Smrg       sigset_t mask;
82*b1e83836Smrg 
83*b1e83836Smrg       sigfillset (&mask);
84*b1e83836Smrg       pthread_sigmask (SIG_BLOCK, &mask, NULL);
85*b1e83836Smrg     }
86*b1e83836Smrg 
8748fb7bfaSmrg   __morestack_release_segments ((struct stack_segment **) arg, 1);
8848fb7bfaSmrg }
8948fb7bfaSmrg 
9048fb7bfaSmrg /* Set up the key for the list of segments.  This is called via
9148fb7bfaSmrg    pthread_once.  */
9248fb7bfaSmrg 
9348fb7bfaSmrg static void
create_key(void)9448fb7bfaSmrg create_key (void)
9548fb7bfaSmrg {
9648fb7bfaSmrg   int err;
9748fb7bfaSmrg 
9848fb7bfaSmrg   err = pthread_key_create (&segment_list_key, free_segments);
9948fb7bfaSmrg   if (err != 0)
10048fb7bfaSmrg     {
10148fb7bfaSmrg       static const char msg[] = "pthread_key_create failed: errno ";
10248fb7bfaSmrg       __morestack_fail (msg, sizeof msg - 1, err);
10348fb7bfaSmrg     }
10448fb7bfaSmrg }
10548fb7bfaSmrg 
10648fb7bfaSmrg /* Pass information from the pthread_create wrapper to
10748fb7bfaSmrg    stack_split_initialize_thread.  */
10848fb7bfaSmrg 
10948fb7bfaSmrg struct pthread_create_args
11048fb7bfaSmrg {
11148fb7bfaSmrg   void *(*start_routine) (void *);
11248fb7bfaSmrg   void *arg;
11348fb7bfaSmrg };
11448fb7bfaSmrg 
11548fb7bfaSmrg /* Initialize a thread.  This is called via pthread_create.  It calls
11648fb7bfaSmrg    a target dependent function to set up any required stack guard.  */
11748fb7bfaSmrg 
11848fb7bfaSmrg static void* stack_split_initialize_thread (void *)
11948fb7bfaSmrg   __attribute__ ((no_split_stack));
12048fb7bfaSmrg 
12148fb7bfaSmrg static void *
stack_split_initialize_thread(void * varg)12248fb7bfaSmrg stack_split_initialize_thread (void *varg)
12348fb7bfaSmrg {
12448fb7bfaSmrg   struct pthread_create_args *args = (struct pthread_create_args *) varg;
12548fb7bfaSmrg   int err;
12648fb7bfaSmrg   void *(*start_routine) (void *);
12748fb7bfaSmrg   void *arg;
12848fb7bfaSmrg 
12948fb7bfaSmrg   __stack_split_initialize ();
13048fb7bfaSmrg 
13148fb7bfaSmrg   err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments);
13248fb7bfaSmrg   if (err != 0)
13348fb7bfaSmrg     {
13448fb7bfaSmrg       static const char msg[] = "pthread_setspecific failed: errno ";
13548fb7bfaSmrg       __morestack_fail (msg, sizeof msg - 1, err);
13648fb7bfaSmrg     }
13748fb7bfaSmrg 
13848fb7bfaSmrg   start_routine = args->start_routine;
13948fb7bfaSmrg   arg = args->arg;
14048fb7bfaSmrg   free (args);
14148fb7bfaSmrg   return (*start_routine) (arg);
14248fb7bfaSmrg }
14348fb7bfaSmrg 
14448fb7bfaSmrg /* This function wraps calls to pthread_create to make sure that the
14548fb7bfaSmrg    stack guard is initialized for new threads.  FIXME: This hack will
14648fb7bfaSmrg    not be necessary if glibc supports -fsplit-stack directly.  */
14748fb7bfaSmrg 
14848fb7bfaSmrg int __wrap_pthread_create (pthread_t *, const pthread_attr_t *,
14948fb7bfaSmrg 			   void *(*start_routine) (void *), void *)
15048fb7bfaSmrg   __attribute__ ((visibility ("hidden")));
15148fb7bfaSmrg 
15248fb7bfaSmrg extern int __real_pthread_create (pthread_t *, const pthread_attr_t *,
15348fb7bfaSmrg 				  void *(*start_routine) (void *), void *)
15448fb7bfaSmrg   __attribute__ ((weak));
15548fb7bfaSmrg 
15648fb7bfaSmrg int
__wrap_pthread_create(pthread_t * tid,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)15748fb7bfaSmrg __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr,
15848fb7bfaSmrg 		       void *(*start_routine) (void *), void *arg)
15948fb7bfaSmrg {
16048fb7bfaSmrg   int err;
16148fb7bfaSmrg   struct pthread_create_args* args;
16248fb7bfaSmrg 
16348fb7bfaSmrg   err = pthread_once (&create_key_once, create_key);
16448fb7bfaSmrg   if (err != 0)
16548fb7bfaSmrg     {
16648fb7bfaSmrg       static const char msg[] = "pthread_once failed: errno ";
16748fb7bfaSmrg       __morestack_fail (msg, sizeof msg - 1, err);
16848fb7bfaSmrg     }
16948fb7bfaSmrg 
17048fb7bfaSmrg   args = malloc (sizeof (struct pthread_create_args));
17148fb7bfaSmrg   if (args == NULL)
17248fb7bfaSmrg     return EAGAIN;
17348fb7bfaSmrg   args->start_routine = start_routine;
17448fb7bfaSmrg   args->arg = arg;
17548fb7bfaSmrg   return __real_pthread_create (tid, attr, stack_split_initialize_thread, args);
17648fb7bfaSmrg }
17748fb7bfaSmrg 
17848fb7bfaSmrg #endif /* !defined (inhibit_libc) */
179