| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- /* Thread creation.
- Copyright (C) 2000-2026 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
- #include <assert.h>
- #include <errno.h>
- #include <pthread.h>
- #include <signal.h>
- #include <resolv.h>
- #include <atomic.h>
- #include <hurd/resource.h>
- #include <sys/single_threaded.h>
- #include <shlib-compat.h>
- #include <ldsodefs.h>
- #include <pt-internal.h>
- #include <pthreadP.h>
- #include <ctype.h>
- #ifdef HAVE_USELOCALE
- # include <locale.h>
- #endif
- /* The entry-point for new threads. */
- static void
- entry_point (struct __pthread *self, void *(*start_routine) (void *), void *arg)
- {
- int err;
- ___pthread_self = self;
- __resp = &self->res_state;
- /* Initialize pointers to locale data. */
- __ctype_init ();
- #ifdef HAVE_USELOCALE
- /* A fresh thread needs to be bound to the global locale. */
- uselocale (LC_GLOBAL_LOCALE);
- #endif
- __pthread_startup ();
- /* We can now unleash signals. */
- err = __pthread_sigstate (self, SIG_SETMASK, &self->init_sigset, 0, 0);
- assert_perror (err);
- if (self->c11)
- {
- /* The function pointer of the c11 thread start is cast to an incorrect
- type on __pthread_create call, however it is casted back to correct
- one so the call behavior is well-defined (it is assumed that pointers
- to void are able to represent all values of int). */
- int (*start)(void*) = (int (*) (void*)) start_routine;
- __pthread_exit ((void*) (uintptr_t) start (arg));
- }
- else
- __pthread_exit (start_routine (arg));
- }
- /* Create a thread with attributes given by ATTR, executing
- START_ROUTINE with argument ARG. */
- int
- __pthread_create (pthread_t * thread, const pthread_attr_t * attr,
- void *(*start_routine) (void *), void *arg)
- {
- /* Avoid a data race in the multi-threaded case. */
- if (__libc_single_threaded)
- __libc_single_threaded = 0;
- return __libc_pthread_create (thread, attr, start_routine, arg);
- }
- versioned_symbol (libc, __pthread_create, pthread_create, GLIBC_2_43);
- #if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_12, GLIBC_2_43)
- compat_symbol (libpthread, __pthread_create, pthread_create, GLIBC_2_12);
- #endif
- hidden_def (__pthread_create)
- /* Version of pthread_create which does not make __libc_single_threaded zero.
- This is notably useful for the signal thread. */
- int
- __libc_pthread_create (pthread_t * thread, const pthread_attr_t * attr,
- void *(*start_routine) (void *), void *arg)
- {
- int err;
- struct __pthread *pthread;
- err = __pthread_create_internal (&pthread, attr, start_routine, arg);
- if (!err)
- *thread = pthread->thread;
- else if (err == ENOMEM)
- err = EAGAIN;
- return err;
- }
- /* Internal version of pthread_create. See comment in
- pt-internal.h. */
- int
- __pthread_create_internal (struct __pthread **thread,
- const pthread_attr_t * attr,
- void *(*start_routine) (void *), void *arg)
- {
- int err;
- struct __pthread *pthread;
- const struct __pthread_attr *setup;
- sigset_t sigset;
- size_t stacksize;
- /* Allocate a new thread structure. */
- err = __pthread_alloc (&pthread);
- if (err)
- goto failed;
- if (attr == ATTR_C11_THREAD)
- {
- attr = NULL;
- pthread->c11 = true;
- }
- else
- pthread->c11 = false;
- /* Use the default attributes if ATTR is NULL. */
- setup = attr ? attr : &__pthread_default_attr;
- stacksize = setup->__stacksize;
- if (stacksize == 0)
- {
- struct rlimit rlim;
- err = __getrlimit (RLIMIT_STACK, &rlim);
- if (err == 0 && rlim.rlim_cur != RLIM_INFINITY)
- stacksize = rlim.rlim_cur;
- if (stacksize == 0)
- stacksize = PTHREAD_STACK_DEFAULT;
- }
- /* Initialize the thread state. */
- pthread->state = (setup->__detachstate == PTHREAD_CREATE_DETACHED
- ? PTHREAD_DETACHED : PTHREAD_JOINABLE);
- if (setup->__stackaddr)
- {
- pthread->stackaddr = setup->__stackaddr;
- /* If the user supplied a stack, it is not our responsibility to
- setup a stack guard. */
- pthread->guardsize = 0;
- pthread->stack = 0;
- }
- else
- {
- /* Allocate a stack. */
- err = __pthread_stack_alloc (&pthread->stackaddr,
- ((setup->__guardsize + __vm_page_size - 1)
- / __vm_page_size) * __vm_page_size
- + stacksize);
- if (err)
- goto failed_stack_alloc;
- pthread->guardsize = setup->__guardsize;
- pthread->stack = 1;
- }
- pthread->stacksize = stacksize;
- /* Allocate the kernel thread and other required resources. */
- err = __pthread_thread_alloc (pthread);
- if (err)
- goto failed_thread_alloc;
- pthread->tcb = _dl_allocate_tls (NULL);
- if (pthread->tcb == NULL)
- {
- err = ENOMEM;
- goto failed_thread_tls_alloc;
- }
- #if TLS_TCB_AT_TP
- pthread->tcb->tcb = pthread->tcb;
- #endif
- /* And initialize the rest of the machine context. This may include
- additional machine- and system-specific initializations that
- prove convenient. */
- err = __pthread_setup (pthread, entry_point, start_routine, arg);
- if (err)
- goto failed_setup;
- /* Initialize the system-specific signal state for the new
- thread. */
- err = __pthread_sigstate_init (pthread);
- if (err)
- goto failed_sigstate;
- /* If the new thread is joinable, add a reference for the caller. */
- if (pthread->state == PTHREAD_JOINABLE)
- pthread->nr_refs++;
- /* Set the new thread's signal mask and set the pending signals to
- empty. POSIX says: "The signal mask shall be inherited from the
- creating thread. The set of signals pending for the new thread
- shall be empty." If the current thread is not a pthread then we
- just inherit the process' sigmask. */
- err = __pthread_sigmask (0, 0, &pthread->init_sigset);
- assert_perror (err);
- if (start_routine)
- /* But block the signals for now, until the thread is fully initialized. */
- __sigfillset (&sigset);
- else
- sigset = pthread->init_sigset;
- err = __pthread_sigstate (pthread, SIG_SETMASK, &sigset, 0, 1);
- assert_perror (err);
- /* Increase the total number of threads. We do this before actually
- starting the new thread, since the new thread might immediately
- call `pthread_exit' which decreases the number of threads and
- calls `exit' if the number of threads reaches zero. Increasing
- the number of threads from within the new thread isn't an option
- since this thread might return and call `pthread_exit' before the
- new thread runs. */
- atomic_fetch_add_relaxed (&__pthread_total, 1);
- /* Store a pointer to this thread in the thread ID lookup table. We
- could use __thread_setid, however, we only lock for reading as no
- other thread should be using this entry (we also assume that the
- store is atomic). */
- __libc_rwlock_rdlock (GL (dl_pthread_threads_lock));
- GL (dl_pthread_threads)[pthread->thread - 1] = pthread;
- __libc_rwlock_unlock (GL (dl_pthread_threads_lock));
- /* At this point it is possible to guess our pthread ID. We have to
- make sure that all functions taking a pthread_t argument can
- handle the fact that this thread isn't really running yet. Since
- the new thread might be passed its ID through pthread_create (to
- avoid calling pthread_self), read it before starting the thread. */
- *thread = pthread;
- /* Schedule the new thread. */
- err = __pthread_thread_start (pthread);
- if (err)
- goto failed_starting;
- return 0;
- failed_starting:
- /* If joinable, a reference was added for the caller. */
- if (pthread->state == PTHREAD_JOINABLE)
- {
- __pthread_dealloc (pthread);
- __pthread_dealloc_finish (pthread);
- }
- __pthread_setid (pthread->thread, NULL);
- atomic_fetch_add_relaxed (&__pthread_total, -1);
- failed_sigstate:
- __pthread_sigstate_destroy (pthread);
- failed_setup:
- _dl_deallocate_tls (pthread->tcb, 1);
- pthread->tcb = NULL;
- failed_thread_tls_alloc:
- __pthread_thread_terminate (pthread);
- /* __pthread_thread_terminate has taken care of deallocating the stack and
- the thread structure. */
- goto failed;
- failed_thread_alloc:
- if (pthread->stack)
- __pthread_stack_dealloc (pthread->stackaddr,
- ((setup->__guardsize + __vm_page_size - 1)
- / __vm_page_size) * __vm_page_size + stacksize);
- failed_stack_alloc:
- __pthread_dealloc (pthread);
- __pthread_dealloc_finish (pthread);
- failed:
- return err;
- }
|