(root)/
gcc-13.2.0/
libgcc/
generic-morestack-thread.c
       1  /* Thread library support for -fsplit-stack.  */
       2  /* Copyright (C) 2009-2023 Free Software Foundation, Inc.
       3     Contributed by Ian Lance Taylor <iant@google.com>.
       4  
       5  This file is part of GCC.
       6  
       7  GCC is free software; you can redistribute it and/or modify it under
       8  the terms of the GNU General Public License as published by the Free
       9  Software Foundation; either version 3, or (at your option) any later
      10  version.
      11  
      12  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15  for more details.
      16  
      17  Under Section 7 of GPL version 3, you are granted additional
      18  permissions described in the GCC Runtime Library Exception, version
      19  3.1, as published by the Free Software Foundation.
      20  
      21  You should have received a copy of the GNU General Public License and
      22  a copy of the GCC Runtime Library Exception along with this program;
      23  see 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 cannot 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 <signal.h>
      42  #include <pthread.h>
      43  
      44  #include "generic-morestack.h"
      45  
      46  /* We declare the pthread functions we need as weak, so that
      47     libgcc_s.so does not need to be linked against -lpthread.  */
      48  
      49  extern int pthread_once (pthread_once_t *, void (*) (void))
      50    __attribute__ ((weak));
      51  
      52  extern int pthread_key_create (pthread_key_t *, void (*) (void *))
      53    __attribute__ ((weak));
      54  
      55  extern int pthread_setspecific (pthread_key_t, const void *)
      56    __attribute__ ((weak));
      57  
      58  extern int pthread_sigmask (int, const sigset_t *, sigset_t *)
      59    __attribute__ ((weak));
      60  
      61  /* The key for the list of stack segments to free when the thread
      62     exits.  This is created by pthread_key_create.  */
      63  
      64  static pthread_key_t segment_list_key;
      65  
      66  /* Used to only run create_key once.  */
      67  
      68  static pthread_once_t create_key_once = PTHREAD_ONCE_INIT;
      69  
      70  /* Release all the segments for a thread.  This is the destructor
      71     function used by pthread_key_create, and is called when a thread
      72     exits.  */
      73  
      74  static void
      75  free_segments (void* arg)
      76  {
      77    /* We must block signals in case the signal handler tries to split
      78       the stack.  We leave them blocked while the thread exits.  */
      79    if (pthread_sigmask)
      80      {
      81        sigset_t mask;
      82  
      83        sigfillset (&mask);
      84        pthread_sigmask (SIG_BLOCK, &mask, NULL);
      85      }
      86  
      87    __morestack_release_segments ((struct stack_segment **) arg, 1);
      88  }
      89  
      90  /* Set up the key for the list of segments.  This is called via
      91     pthread_once.  */
      92  
      93  static void
      94  create_key (void)
      95  {
      96    int err;
      97  
      98    err = pthread_key_create (&segment_list_key, free_segments);
      99    if (err != 0)
     100      {
     101        static const char msg[] = "pthread_key_create failed: errno ";
     102        __morestack_fail (msg, sizeof msg - 1, err);
     103      }
     104  }
     105  
     106  /* Pass information from the pthread_create wrapper to
     107     stack_split_initialize_thread.  */
     108  
     109  struct pthread_create_args
     110  {
     111    void *(*start_routine) (void *);
     112    void *arg;
     113  };
     114  
     115  /* Initialize a thread.  This is called via pthread_create.  It calls
     116     a target dependent function to set up any required stack guard.  */
     117  
     118  static void* stack_split_initialize_thread (void *)
     119    __attribute__ ((no_split_stack));
     120  
     121  static void *
     122  stack_split_initialize_thread (void *varg)
     123  {
     124    struct pthread_create_args *args = (struct pthread_create_args *) varg;
     125    int err;
     126    void *(*start_routine) (void *);
     127    void *arg;
     128  
     129    __stack_split_initialize ();
     130  
     131    err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments);
     132    if (err != 0)
     133      {
     134        static const char msg[] = "pthread_setspecific failed: errno ";
     135        __morestack_fail (msg, sizeof msg - 1, err);
     136      }
     137  
     138    start_routine = args->start_routine;
     139    arg = args->arg;
     140    free (args);
     141    return (*start_routine) (arg);
     142  }
     143  
     144  /* This function wraps calls to pthread_create to make sure that the
     145     stack guard is initialized for new threads.  FIXME: This hack will
     146     not be necessary if glibc supports -fsplit-stack directly.  */
     147  
     148  int __wrap_pthread_create (pthread_t *, const pthread_attr_t *,
     149  			   void *(*start_routine) (void *), void *)
     150    __attribute__ ((visibility ("hidden")));
     151  
     152  extern int __real_pthread_create (pthread_t *, const pthread_attr_t *,
     153  				  void *(*start_routine) (void *), void *)
     154    __attribute__ ((weak));
     155  
     156  int
     157  __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr,
     158  		       void *(*start_routine) (void *), void *arg)
     159  {
     160    int err;
     161    struct pthread_create_args* args;
     162  
     163    err = pthread_once (&create_key_once, create_key);
     164    if (err != 0)
     165      {
     166        static const char msg[] = "pthread_once failed: errno ";
     167        __morestack_fail (msg, sizeof msg - 1, err);
     168      }
     169  
     170    args = malloc (sizeof (struct pthread_create_args));
     171    if (args == NULL)
     172      return EAGAIN;
     173    args->start_routine = start_routine;
     174    args->arg = arg;
     175    return __real_pthread_create (tid, attr, stack_split_initialize_thread, args);
     176  }
     177  
     178  #endif /* !defined (inhibit_libc) */