📄 pthread.c
字号:
/* Linuxthreads - a simple clone()-based implementation of Posix *//* threads for Linux. *//* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) *//* *//* This program is free software; you can redistribute it and/or *//* modify it under the terms of the GNU Library General Public License *//* as published by the Free Software Foundation; either version 2 *//* of the License, or (at your option) any later version. *//* *//* This program 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 Library General Public License for more details. *//* Thread creation, initialization, and basic low-level routines */#include <errno.h>#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <sys/wait.h>#include <sys/resource.h>#include <sys/sysctl.h>#include <shlib-compat.h>#include "pthread.h"#include "internals.h"#include "spinlock.h"#include "restart.h"#include <machine/syscall.h>/* for threading we use processes so we require a few EL/IX level 2 and level 3 syscalls. We only allow this file to see them to preserve the interface. */#if defined(_ELIX_LEVEL) && _ELIX_LEVEL < 3static _syscall1_base(int,pipe,int *,filedes)#endif /* _ELIX_LEVEL < 3 */#if defined(_ELIX_LEVEL) && _ELIX_LEVEL < 2static _syscall2_base(int,setrlimit,int,resource,const struct rlimit *,rlp)int on_exit (void (*fn)(int, void *), void *arg){ register struct _atexit *p; void (*x)(void) = (void (*)(void))fn;/* _REENT_SMALL on_exit() doesn't allow more than the required 32 entries. */#ifndef _REENT_SMALL if ((p = _REENT->_atexit) == NULL) _REENT->_atexit = p = &_REENT->_atexit0; if (p->_ind >= _ATEXIT_SIZE) { if ((p = (struct _atexit *) malloc (sizeof *p)) == NULL) return -1; p->_ind = 0; p->_fntypes = 0; p->_next = _REENT->_atexit; _REENT->_atexit = p; }#else p = &_REENT->_atexit; if (p->_ind >= _ATEXIT_SIZE) return -1;#endif p->_fntypes |= (1 << p->_ind); p->_fnargs[p->_ind] = arg; p->_fns[p->_ind++] = x; return 0;}#endif /* _ELIX_LEVEL < 2 *//* We need the global/static resolver state here. */#include <resolv.h>#undef _res/* FIXME: for now, set up _res here */struct __res_state _res;/* Sanity check. */#if __ASSUME_REALTIME_SIGNALS && !defined __SIGRTMIN# error "This must not happen; new kernel assumed but old headers"#endif/* These variables are used by the setup code. *//* Descriptor of the initial thread */struct _pthread_descr_struct __pthread_initial_thread = { { { &__pthread_initial_thread /* pthread_descr self */ } }, &__pthread_initial_thread, /* pthread_descr p_nextlive */ &__pthread_initial_thread, /* pthread_descr p_prevlive */ NULL, /* pthread_descr p_nextwaiting */ NULL, /* pthread_descr p_nextlock */ PTHREAD_THREADS_MAX, /* pthread_t p_tid */ 0, /* int p_pid */ 0, /* int p_priority */ &__pthread_handles[0].h_lock, /* struct _pthread_fastlock * p_lock */ 0, /* int p_signal */ NULL, /* sigjmp_buf * p_signal_buf */ NULL, /* sigjmp_buf * p_cancel_buf */ 0, /* char p_terminated */ 0, /* char p_detached */ 0, /* char p_exited */ NULL, /* void * p_retval */ 0, /* int p_retval */ NULL, /* pthread_descr p_joining */ NULL, /* struct _pthread_cleanup_buffer * p_cleanup */ 0, /* char p_cancelstate */ 0, /* char p_canceltype */ 0, /* char p_canceled */ &__pthread_initial_thread.p_reent, /* struct _reent *p_reentp */ _REENT_INIT(__pthread_initial_thread.p_reent), /* struct _reent p_reent */ NULL, /* int *p_h_errnop */ 0, /* int p_h_errno */ NULL, /* char * p_in_sighandler */ 0, /* char p_sigwaiting */ PTHREAD_START_ARGS_INITIALIZER(NULL), /* struct pthread_start_args p_start_args */ {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */ {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */ 1, /* int p_userstack */ NULL, /* void * p_guardaddr */ 0, /* size_t p_guardsize */ 0, /* Always index 0 */ 0, /* int p_report_events */ {{{0, }}, 0, NULL}, /* td_eventbuf_t p_eventbuf */ __ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */ 0, /* char p_woken_by_cancel */ 0, /* char p_condvar_avail */ 0, /* char p_sem_avail */ NULL, /* struct pthread_extricate_if *p_extricate */ NULL, /* pthread_readlock_info *p_readlock_list; */ NULL, /* pthread_readlock_info *p_readlock_free; */ 0 /* int p_untracked_readlock_count; */};/* Descriptor of the manager thread; none of this is used but the error variables, the p_pid and p_priority fields, and the address for identification. */struct _pthread_descr_struct __pthread_manager_thread = { { { &__pthread_manager_thread /* pthread_descr self */ } }, NULL, /* pthread_descr p_nextlive */ NULL, /* pthread_descr p_prevlive */ NULL, /* pthread_descr p_nextwaiting */ NULL, /* pthread_descr p_nextlock */ 0, /* int p_tid */ 0, /* int p_pid */ 0, /* int p_priority */ &__pthread_handles[1].h_lock, /* struct _pthread_fastlock * p_lock */ 0, /* int p_signal */ NULL, /* sigjmp_buf * p_signal_buf */ NULL, /* sigjmp_buf * p_cancel_buf */ 0, /* char p_terminated */ 0, /* char p_detached */ 0, /* char p_exited */ NULL, /* void * p_retval */ 0, /* int p_retval */ NULL, /* pthread_descr p_joining */ NULL, /* struct _pthread_cleanup_buffer * p_cleanup */ 0, /* char p_cancelstate */ 0, /* char p_canceltype */ 0, /* char p_canceled */ &__pthread_manager_thread.p_reent, /* struct _reent *p_reentp */ _REENT_INIT(__pthread_manager_thread.p_reent), /* struct _reent p_reent */ NULL, /* int *p_h_errnop */ 0, /* int p_h_errno */ NULL, /* char * p_in_sighandler */ 0, /* char p_sigwaiting */ PTHREAD_START_ARGS_INITIALIZER(__pthread_manager), /* struct pthread_start_args p_start_args */ {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */ {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */ 0, /* int p_userstack */ NULL, /* void * p_guardaddr */ 0, /* size_t p_guardsize */ 1, /* Always index 1 */ 0, /* int p_report_events */ {{{0, }}, 0, NULL}, /* td_eventbuf_t p_eventbuf */ __ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */ 0, /* char p_woken_by_cancel */ 0, /* char p_condvar_avail */ 0, /* char p_sem_avail */ NULL, /* struct pthread_extricate_if *p_extricate */ NULL, /* pthread_readlock_info *p_readlock_list; */ NULL, /* pthread_readlock_info *p_readlock_free; */ 0 /* int p_untracked_readlock_count; */};/* Pointer to the main thread (the father of the thread manager thread) *//* Originally, this is the initial thread, but this changes after fork() */pthread_descr __pthread_main_thread = &__pthread_initial_thread;/* Limit between the stack of the initial thread (above) and the stacks of other threads (below). Aligned on a STACK_SIZE boundary. */char *__pthread_initial_thread_bos;/* File descriptor for sending requests to the thread manager. *//* Initially -1, meaning that the thread manager is not running. */int __pthread_manager_request = -1;/* Other end of the pipe for sending requests to the thread manager. */int __pthread_manager_reader;/* Limits of the thread manager stack */char *__pthread_manager_thread_bos;char *__pthread_manager_thread_tos;/* For process-wide exit() */int __pthread_exit_requested;int __pthread_exit_code;/* Maximum stack size. */size_t __pthread_max_stacksize;/* Nozero if the machine has more than one processor. */int __pthread_smp_kernel;#if !__ASSUME_REALTIME_SIGNALS/* Pointers that select new or old suspend/resume functions based on availability of rt signals. */void (*__pthread_restart)(pthread_descr) = __pthread_restart_old;void (*__pthread_suspend)(pthread_descr) = __pthread_suspend_old;int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_old;#endif /* __ASSUME_REALTIME_SIGNALS *//* Communicate relevant LinuxThreads constants to gdb */const int __pthread_threads_max = PTHREAD_THREADS_MAX;const int __pthread_sizeof_handle = sizeof(struct pthread_handle_struct);const int __pthread_offsetof_descr = offsetof(struct pthread_handle_struct, h_descr);const int __pthread_offsetof_pid = offsetof(struct _pthread_descr_struct, p_pid);const int __linuxthreads_pthread_sizeof_descr = sizeof(struct _pthread_descr_struct);/* Forward declarations */static void pthread_onexit_process(int retcode, void *arg);#ifndef HAVE_Z_NODELETEstatic void pthread_atexit_process(void *arg, int retcode);static void pthread_atexit_retcode(void *arg, int retcode);#endifstatic void pthread_handle_sigcancel(int sig);static void pthread_handle_sigrestart(int sig);static void pthread_handle_sigdebug(int sig);/* CPU clock handling. */#if HP_TIMING_AVAILextern hp_timing_t _dl_cpuclock_offset;#endif/* Signal numbers used for the communication. In these variables we keep track of the used variables. If the platform does not support any real-time signals we will define the values to some unreasonable value which will signal failing of all the functions below. */#ifndef __SIGRTMINstatic int current_rtmin = -1;static int current_rtmax = -1;int __pthread_sig_restart = SIGUSR1;int __pthread_sig_cancel = SIGUSR2;int __pthread_sig_debug;#elsestatic int current_rtmin;static int current_rtmax;#if __SIGRTMAX - __SIGRTMIN >= 3int __pthread_sig_restart = __SIGRTMIN;int __pthread_sig_cancel = __SIGRTMIN + 1;int __pthread_sig_debug = __SIGRTMIN + 2;#elseint __pthread_sig_restart = SIGUSR1;int __pthread_sig_cancel = SIGUSR2;int __pthread_sig_debug;#endifstatic int rtsigs_initialized;#if !__ASSUME_REALTIME_SIGNALS# include "testrtsig.h"#endifstatic voidinit_rtsigs (void){#if !__ASSUME_REALTIME_SIGNALS if (__builtin_expect (!kernel_has_rtsig (), 0)) { current_rtmin = -1; current_rtmax = -1;# if __SIGRTMAX - __SIGRTMIN >= 3 __pthread_sig_restart = SIGUSR1; __pthread_sig_cancel = SIGUSR2; __pthread_sig_debug = 0;# endif } else#endif /* __ASSUME_REALTIME_SIGNALS */ {#if __SIGRTMAX - __SIGRTMIN >= 3 current_rtmin = __SIGRTMIN + 3;# if !__ASSUME_REALTIME_SIGNALS __pthread_restart = __pthread_restart_new; __pthread_suspend = __pthread_wait_for_restart_signal; __pthread_timedsuspend = __pthread_timedsuspend_new;# endif /* __ASSUME_REALTIME_SIGNALS */#else current_rtmin = __SIGRTMIN;#endif current_rtmax = __SIGRTMAX; } rtsigs_initialized = 1;}#endif/* Return number of available real-time signal with highest priority. */int__libc_current_sigrtmin (void){#ifdef __SIGRTMIN if (__builtin_expect (!rtsigs_initialized, 0)) init_rtsigs ();#endif return current_rtmin;}/* Return number of available real-time signal with lowest priority. */int__libc_current_sigrtmax (void){#ifdef __SIGRTMIN if (__builtin_expect (!rtsigs_initialized, 0)) init_rtsigs ();#endif return current_rtmax;}/* Allocate real-time signal with highest/lowest available priority. Please note that we don't use a lock since we assume this function to be called at program start. */int__libc_allocate_rtsig (int high){#ifndef __SIGRTMIN return -1;#else if (__builtin_expect (!rtsigs_initialized, 0)) init_rtsigs (); if (__builtin_expect (current_rtmin == -1, 0) || __builtin_expect (current_rtmin > current_rtmax, 0)) /* We don't have anymore signal available. */ return -1; return high ? current_rtmin++ : current_rtmax--;#endif}/* The function we use to get the kernel revision. */extern int __sysctl (int *name, int nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen);/* Test whether the machine has more than one processor. This is not the best test but good enough. More complicated tests would require `malloc' which is not available at that time. */static intis_smp_system (void){ static const int sysctl_args[] = { CTL_KERN, KERN_VERSION }; char buf[512]; size_t reslen = sizeof (buf); /* Try reading the number using `sysctl' first. */ if (__sysctl ((int *) sysctl_args, sizeof (sysctl_args) / sizeof (sysctl_args[0]), buf, &reslen, NULL, 0) < 0) { /* This was not successful. Now try reading the /proc filesystem. */ int fd = __open ("/proc/sys/kernel/version", O_RDONLY); if (__builtin_expect (fd, 0) == -1 || (reslen = __read (fd, buf, sizeof (buf))) <= 0) /* This also didn't work. We give up and say it's a UP machine. */ buf[0] = '\0'; __close (fd); } return strstr (buf, "SMP") != NULL;}/* Initialize the pthread library. Initialization is split in two functions: - a constructor function that blocks the __pthread_sig_restart signal (must do this very early, since the program could capture the signal
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -