xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/generic-morestack-thread.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* Thread library support for -fsplit-stack.  */
2*8feb0f0bSmrg /* Copyright (C) 2009-2020 Free Software Foundation, Inc.
31debfc3dSmrg    Contributed by Ian Lance Taylor <iant@google.com>.
41debfc3dSmrg 
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg 
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
81debfc3dSmrg the terms of the GNU General Public License as published by the Free
91debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
101debfc3dSmrg version.
111debfc3dSmrg 
121debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
131debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
141debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
151debfc3dSmrg for more details.
161debfc3dSmrg 
171debfc3dSmrg Under Section 7 of GPL version 3, you are granted additional
181debfc3dSmrg permissions described in the GCC Runtime Library Exception, version
191debfc3dSmrg 3.1, as published by the Free Software Foundation.
201debfc3dSmrg 
211debfc3dSmrg You should have received a copy of the GNU General Public License and
221debfc3dSmrg a copy of the GCC Runtime Library Exception along with this program;
231debfc3dSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
241debfc3dSmrg <http://www.gnu.org/licenses/>.  */
251debfc3dSmrg 
261debfc3dSmrg #include "tconfig.h"
271debfc3dSmrg #include "tsystem.h"
281debfc3dSmrg #include "coretypes.h"
291debfc3dSmrg #include "tm.h"
301debfc3dSmrg #include "libgcc_tm.h"
311debfc3dSmrg 
321debfc3dSmrg /* If inhibit_libc is defined, we cannot compile this file.  The
331debfc3dSmrg    effect is that people will not be able to use -fsplit-stack.  That
341debfc3dSmrg    is much better than failing the build particularly since people
351debfc3dSmrg    will want to define inhibit_libc while building a compiler which
361debfc3dSmrg    can build glibc.  */
371debfc3dSmrg 
381debfc3dSmrg #ifndef inhibit_libc
391debfc3dSmrg 
401debfc3dSmrg #include <errno.h>
411debfc3dSmrg #include <pthread.h>
421debfc3dSmrg 
431debfc3dSmrg #include "generic-morestack.h"
441debfc3dSmrg 
451debfc3dSmrg /* We declare the pthread functions we need as weak, so that
461debfc3dSmrg    libgcc_s.so does not need to be linked against -lpthread.  */
471debfc3dSmrg 
481debfc3dSmrg extern int pthread_once (pthread_once_t *, void (*) (void))
491debfc3dSmrg   __attribute__ ((weak));
501debfc3dSmrg 
511debfc3dSmrg extern int pthread_key_create (pthread_key_t *, void (*) (void *))
521debfc3dSmrg   __attribute__ ((weak));
531debfc3dSmrg 
541debfc3dSmrg extern int pthread_setspecific (pthread_key_t, const void *)
551debfc3dSmrg   __attribute__ ((weak));
561debfc3dSmrg 
571debfc3dSmrg /* The key for the list of stack segments to free when the thread
581debfc3dSmrg    exits.  This is created by pthread_key_create.  */
591debfc3dSmrg 
601debfc3dSmrg static pthread_key_t segment_list_key;
611debfc3dSmrg 
621debfc3dSmrg /* Used to only run create_key once.  */
631debfc3dSmrg 
641debfc3dSmrg static pthread_once_t create_key_once = PTHREAD_ONCE_INIT;
651debfc3dSmrg 
661debfc3dSmrg /* Release all the segments for a thread.  This is the destructor
671debfc3dSmrg    function used by pthread_key_create, and is called when a thread
681debfc3dSmrg    exits.  */
691debfc3dSmrg 
701debfc3dSmrg static void
free_segments(void * arg)711debfc3dSmrg free_segments (void* arg)
721debfc3dSmrg {
731debfc3dSmrg   __morestack_release_segments ((struct stack_segment **) arg, 1);
741debfc3dSmrg }
751debfc3dSmrg 
761debfc3dSmrg /* Set up the key for the list of segments.  This is called via
771debfc3dSmrg    pthread_once.  */
781debfc3dSmrg 
791debfc3dSmrg static void
create_key(void)801debfc3dSmrg create_key (void)
811debfc3dSmrg {
821debfc3dSmrg   int err;
831debfc3dSmrg 
841debfc3dSmrg   err = pthread_key_create (&segment_list_key, free_segments);
851debfc3dSmrg   if (err != 0)
861debfc3dSmrg     {
871debfc3dSmrg       static const char msg[] = "pthread_key_create failed: errno ";
881debfc3dSmrg       __morestack_fail (msg, sizeof msg - 1, err);
891debfc3dSmrg     }
901debfc3dSmrg }
911debfc3dSmrg 
921debfc3dSmrg /* Pass information from the pthread_create wrapper to
931debfc3dSmrg    stack_split_initialize_thread.  */
941debfc3dSmrg 
951debfc3dSmrg struct pthread_create_args
961debfc3dSmrg {
971debfc3dSmrg   void *(*start_routine) (void *);
981debfc3dSmrg   void *arg;
991debfc3dSmrg };
1001debfc3dSmrg 
1011debfc3dSmrg /* Initialize a thread.  This is called via pthread_create.  It calls
1021debfc3dSmrg    a target dependent function to set up any required stack guard.  */
1031debfc3dSmrg 
1041debfc3dSmrg static void* stack_split_initialize_thread (void *)
1051debfc3dSmrg   __attribute__ ((no_split_stack));
1061debfc3dSmrg 
1071debfc3dSmrg static void *
stack_split_initialize_thread(void * varg)1081debfc3dSmrg stack_split_initialize_thread (void *varg)
1091debfc3dSmrg {
1101debfc3dSmrg   struct pthread_create_args *args = (struct pthread_create_args *) varg;
1111debfc3dSmrg   int err;
1121debfc3dSmrg   void *(*start_routine) (void *);
1131debfc3dSmrg   void *arg;
1141debfc3dSmrg 
1151debfc3dSmrg   __stack_split_initialize ();
1161debfc3dSmrg 
1171debfc3dSmrg   err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments);
1181debfc3dSmrg   if (err != 0)
1191debfc3dSmrg     {
1201debfc3dSmrg       static const char msg[] = "pthread_setspecific failed: errno ";
1211debfc3dSmrg       __morestack_fail (msg, sizeof msg - 1, err);
1221debfc3dSmrg     }
1231debfc3dSmrg 
1241debfc3dSmrg   start_routine = args->start_routine;
1251debfc3dSmrg   arg = args->arg;
1261debfc3dSmrg   free (args);
1271debfc3dSmrg   return (*start_routine) (arg);
1281debfc3dSmrg }
1291debfc3dSmrg 
1301debfc3dSmrg /* This function wraps calls to pthread_create to make sure that the
1311debfc3dSmrg    stack guard is initialized for new threads.  FIXME: This hack will
1321debfc3dSmrg    not be necessary if glibc supports -fsplit-stack directly.  */
1331debfc3dSmrg 
1341debfc3dSmrg int __wrap_pthread_create (pthread_t *, const pthread_attr_t *,
1351debfc3dSmrg 			   void *(*start_routine) (void *), void *)
1361debfc3dSmrg   __attribute__ ((visibility ("hidden")));
1371debfc3dSmrg 
1381debfc3dSmrg extern int __real_pthread_create (pthread_t *, const pthread_attr_t *,
1391debfc3dSmrg 				  void *(*start_routine) (void *), void *)
1401debfc3dSmrg   __attribute__ ((weak));
1411debfc3dSmrg 
1421debfc3dSmrg int
__wrap_pthread_create(pthread_t * tid,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)1431debfc3dSmrg __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr,
1441debfc3dSmrg 		       void *(*start_routine) (void *), void *arg)
1451debfc3dSmrg {
1461debfc3dSmrg   int err;
1471debfc3dSmrg   struct pthread_create_args* args;
1481debfc3dSmrg 
1491debfc3dSmrg   err = pthread_once (&create_key_once, create_key);
1501debfc3dSmrg   if (err != 0)
1511debfc3dSmrg     {
1521debfc3dSmrg       static const char msg[] = "pthread_once failed: errno ";
1531debfc3dSmrg       __morestack_fail (msg, sizeof msg - 1, err);
1541debfc3dSmrg     }
1551debfc3dSmrg 
1561debfc3dSmrg   args = malloc (sizeof (struct pthread_create_args));
1571debfc3dSmrg   if (args == NULL)
1581debfc3dSmrg     return EAGAIN;
1591debfc3dSmrg   args->start_routine = start_routine;
1601debfc3dSmrg   args->arg = arg;
1611debfc3dSmrg   return __real_pthread_create (tid, attr, stack_split_initialize_thread, args);
1621debfc3dSmrg }
1631debfc3dSmrg 
1641debfc3dSmrg #endif /* !defined (inhibit_libc) */
165