(root)/
glibc-2.38/
htl/
pt-create.c
       1  /* Thread creation.
       2     Copyright (C) 2000-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library;  if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <assert.h>
      20  #include <errno.h>
      21  #include <pthread.h>
      22  #include <signal.h>
      23  #include <resolv.h>
      24  
      25  #include <atomic.h>
      26  #include <hurd/resource.h>
      27  #include <sys/single_threaded.h>
      28  
      29  #include <pt-internal.h>
      30  #include <pthreadP.h>
      31  
      32  #if IS_IN (libpthread)
      33  # include <ctype.h>
      34  #endif
      35  #ifdef HAVE_USELOCALE
      36  # include <locale.h>
      37  #endif
      38  
      39  /* The entry-point for new threads.  */
      40  static void
      41  entry_point (struct __pthread *self, void *(*start_routine) (void *), void *arg)
      42  {
      43    int err;
      44  
      45    ___pthread_self = self;
      46    __resp = &self->res_state;
      47  
      48  #if IS_IN (libpthread)
      49    /* Initialize pointers to locale data.  */
      50    __ctype_init ();
      51  #endif
      52  #ifdef HAVE_USELOCALE
      53    /* A fresh thread needs to be bound to the global locale.  */
      54    uselocale (LC_GLOBAL_LOCALE);
      55  #endif
      56  
      57    __pthread_startup ();
      58  
      59    /* We can now unleash signals.  */
      60    err = __pthread_sigstate (self, SIG_SETMASK, &self->init_sigset, 0, 0);
      61    assert_perror (err);
      62  
      63    if (self->c11)
      64      {
      65        /* The function pointer of the c11 thread start is cast to an incorrect
      66           type on __pthread_create call, however it is casted back to correct
      67           one so the call behavior is well-defined (it is assumed that pointers
      68           to void are able to represent all values of int).  */
      69        int (*start)(void*) = (int (*) (void*)) start_routine;
      70        __pthread_exit ((void*) (uintptr_t) start (arg));
      71      }
      72    else
      73      __pthread_exit (start_routine (arg));
      74  }
      75  
      76  /* Create a thread with attributes given by ATTR, executing
      77     START_ROUTINE with argument ARG.  */
      78  int
      79  __pthread_create (pthread_t * thread, const pthread_attr_t * attr,
      80  		  void *(*start_routine) (void *), void *arg)
      81  {
      82    int err;
      83    struct __pthread *pthread;
      84  
      85    err = __pthread_create_internal (&pthread, attr, start_routine, arg);
      86    if (!err)
      87      *thread = pthread->thread;
      88    else if (err == ENOMEM)
      89      err = EAGAIN;
      90  
      91    return err;
      92  }
      93  weak_alias (__pthread_create, pthread_create)
      94  hidden_def (__pthread_create)
      95  
      96  /* Internal version of pthread_create.  See comment in
      97     pt-internal.h.  */
      98  int
      99  __pthread_create_internal (struct __pthread **thread,
     100  			   const pthread_attr_t * attr,
     101  			   void *(*start_routine) (void *), void *arg)
     102  {
     103    int err;
     104    struct __pthread *pthread;
     105    const struct __pthread_attr *setup;
     106    sigset_t sigset;
     107    size_t stacksize;
     108  
     109    /* Avoid a data race in the multi-threaded case.  */
     110    if (__libc_single_threaded)
     111      __libc_single_threaded = 0;
     112  
     113    /* Allocate a new thread structure.  */
     114    err = __pthread_alloc (&pthread);
     115    if (err)
     116      goto failed;
     117  
     118    if (attr == ATTR_C11_THREAD)
     119      {
     120        attr = NULL;
     121        pthread->c11 = true;
     122      }
     123    else
     124      pthread->c11 = false;
     125  
     126    /* Use the default attributes if ATTR is NULL.  */
     127    setup = attr ? attr : &__pthread_default_attr;
     128  
     129    stacksize = setup->__stacksize;
     130    if (stacksize == 0)
     131      {
     132        struct rlimit rlim;
     133        err = __getrlimit (RLIMIT_STACK, &rlim);
     134        if (err == 0 && rlim.rlim_cur != RLIM_INFINITY)
     135  	stacksize = rlim.rlim_cur;
     136        if (stacksize == 0)
     137  	stacksize = PTHREAD_STACK_DEFAULT;
     138      }
     139  
     140    /* Initialize the thread state.  */
     141    pthread->state = (setup->__detachstate == PTHREAD_CREATE_DETACHED
     142  		    ? PTHREAD_DETACHED : PTHREAD_JOINABLE);
     143  
     144    if (setup->__stackaddr)
     145      {
     146        pthread->stackaddr = setup->__stackaddr;
     147  
     148        /* If the user supplied a stack, it is not our responsibility to
     149           setup a stack guard.  */
     150        pthread->guardsize = 0;
     151        pthread->stack = 0;
     152      }
     153    else
     154      {
     155        /* Allocate a stack.  */
     156        err = __pthread_stack_alloc (&pthread->stackaddr,
     157  				   ((setup->__guardsize + __vm_page_size - 1)
     158  				    / __vm_page_size) * __vm_page_size
     159  				   + stacksize);
     160        if (err)
     161  	goto failed_stack_alloc;
     162  
     163        pthread->guardsize = setup->__guardsize;
     164        pthread->stack = 1;
     165      }
     166  
     167    pthread->stacksize = stacksize;
     168  
     169    /* Allocate the kernel thread and other required resources.  */
     170    err = __pthread_thread_alloc (pthread);
     171    if (err)
     172      goto failed_thread_alloc;
     173  
     174    pthread->tcb = _dl_allocate_tls (NULL);
     175    if (pthread->tcb == NULL)
     176      {
     177        err = ENOMEM;
     178        goto failed_thread_tls_alloc;
     179      }
     180    pthread->tcb->tcb = pthread->tcb;
     181  
     182    /* And initialize the rest of the machine context.  This may include
     183       additional machine- and system-specific initializations that
     184       prove convenient.  */
     185    err = __pthread_setup (pthread, entry_point, start_routine, arg);
     186    if (err)
     187      goto failed_setup;
     188  
     189    /* Initialize the system-specific signal state for the new
     190       thread.  */
     191    err = __pthread_sigstate_init (pthread);
     192    if (err)
     193      goto failed_sigstate;
     194  
     195    /* If the new thread is joinable, add a reference for the caller.  */
     196    if (pthread->state == PTHREAD_JOINABLE)
     197      pthread->nr_refs++;
     198  
     199    /* Set the new thread's signal mask and set the pending signals to
     200       empty.  POSIX says: "The signal mask shall be inherited from the
     201       creating thread.  The set of signals pending for the new thread
     202       shall be empty."  If the current thread is not a pthread then we
     203       just inherit the process' sigmask.  */
     204    if (GL (dl_pthread_num_threads) == 1)
     205      err = __sigprocmask (0, 0, &pthread->init_sigset);
     206    else
     207      err = __pthread_sigstate (_pthread_self (), 0, 0, &pthread->init_sigset, 0);
     208    assert_perror (err);
     209  
     210    if (start_routine)
     211      /* But block the signals for now, until the thread is fully initialized.  */
     212      __sigfillset (&sigset);
     213    else
     214      sigset = pthread->init_sigset;
     215    err = __pthread_sigstate (pthread, SIG_SETMASK, &sigset, 0, 1);
     216    assert_perror (err);
     217  
     218    /* Increase the total number of threads.  We do this before actually
     219       starting the new thread, since the new thread might immediately
     220       call `pthread_exit' which decreases the number of threads and
     221       calls `exit' if the number of threads reaches zero.  Increasing
     222       the number of threads from within the new thread isn't an option
     223       since this thread might return and call `pthread_exit' before the
     224       new thread runs.  */
     225    atomic_fetch_add_relaxed (&__pthread_total, 1);
     226  
     227    /* Store a pointer to this thread in the thread ID lookup table.  We
     228       could use __thread_setid, however, we only lock for reading as no
     229       other thread should be using this entry (we also assume that the
     230       store is atomic).  */
     231    __libc_rwlock_rdlock (GL (dl_pthread_threads_lock));
     232    GL (dl_pthread_threads)[pthread->thread - 1] = pthread;
     233    __libc_rwlock_unlock (GL (dl_pthread_threads_lock));
     234  
     235    /* At this point it is possible to guess our pthread ID.  We have to
     236       make sure that all functions taking a pthread_t argument can
     237       handle the fact that this thread isn't really running yet.  Since
     238       the new thread might be passed its ID through pthread_create (to
     239       avoid calling pthread_self), read it before starting the thread.  */
     240    *thread = pthread;
     241  
     242    /* Schedule the new thread.  */
     243    err = __pthread_thread_start (pthread);
     244    if (err)
     245      goto failed_starting;
     246  
     247  
     248    return 0;
     249  
     250  failed_starting:
     251    /* If joinable, a reference was added for the caller.  */
     252    if (pthread->state == PTHREAD_JOINABLE)
     253      {
     254        __pthread_dealloc (pthread);
     255        __pthread_dealloc_finish (pthread);
     256      }
     257  
     258    __pthread_setid (pthread->thread, NULL);
     259    atomic_fetch_add_relaxed (&__pthread_total, -1);
     260  failed_sigstate:
     261    __pthread_sigstate_destroy (pthread);
     262  failed_setup:
     263    _dl_deallocate_tls (pthread->tcb, 1);
     264    pthread->tcb = NULL;
     265  failed_thread_tls_alloc:
     266    __pthread_thread_terminate (pthread);
     267  
     268    /* __pthread_thread_terminate has taken care of deallocating the stack and
     269       the thread structure.  */
     270    goto failed;
     271  failed_thread_alloc:
     272    if (pthread->stack)
     273      __pthread_stack_dealloc (pthread->stackaddr,
     274  			     ((setup->__guardsize + __vm_page_size - 1)
     275  			      / __vm_page_size) * __vm_page_size + stacksize);
     276  failed_stack_alloc:
     277    __pthread_dealloc (pthread);
     278    __pthread_dealloc_finish (pthread);
     279  failed:
     280    return err;
     281  }