📄 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 */#define __FORCE_GLIBC#include <features.h>#define __USE_GNU#include <errno.h>#include <netdb.h> /* for h_errno */#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 "pthread.h"#include "internals.h"#include "spinlock.h"#include "restart.h"#include "debug.h" /* added to linuxthreads -StS *//* Mods for uClibc: Some includes */#include <signal.h>#include <sys/types.h>#include <sys/syscall.h>/* mods for uClibc: getpwd and getpagesize are the syscalls */#define __getpid getpid#define __getpagesize getpagesize/* mods for uClibc: __libc_sigaction is not in any standard headers */extern int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact);/* These variables are used by the setup code. */extern int _errno;extern int _h_errno;/* Descriptor of the initial thread */struct _pthread_descr_struct __pthread_initial_thread = { &__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 */ &_errno, /* int *p_errnop */ 0, /* int p_errno */ &_h_errno, /* int *p_h_errnop */ 0, /* int p_h_errno */ NULL, /* char * p_in_sighandler */ 0, /* char p_sigwaiting */ PTHREAD_START_ARGS_INITIALIZER, /* 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 */ &__pthread_initial_thread, /* pthread_descr p_self */ 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; */#ifdef __UCLIBC_HAS_XLOCALE__ , &__global_locale_data, /* __locale_t locale; */#endif /* __UCLIBC_HAS_XLOCALE__ */};/* 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. */#define manager_thread (&__pthread_manager_thread)struct _pthread_descr_struct __pthread_manager_thread = { 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_errno, /* int *p_errnop */ 0, /* int p_errno */ NULL, /* int *p_h_errnop */ 0, /* int p_h_errno */ NULL, /* char * p_in_sighandler */ 0, /* char p_sigwaiting */ PTHREAD_START_ARGS_INITIALIZER, /* 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 */ &__pthread_manager_thread, /* pthread_descr p_self */ 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; */#ifdef __UCLIBC_HAS_XLOCALE__ , &__global_locale_data, /* __locale_t locale; */#endif /* __UCLIBC_HAS_XLOCALE__ */};/* 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 = NULL;/* For non-MMU systems also remember to stack top of the initial thread. * This is adapted when other stacks are malloc'ed since we don't know * the bounds a-priori. -StS */#ifndef __ARCH_HAS_MMU__char *__pthread_initial_thread_tos = NULL;#endif /* __ARCH_HAS_MMU__ *//* 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 = NULL;char *__pthread_manager_thread_tos = NULL;/* For process-wide exit() */int __pthread_exit_requested = 0;int __pthread_exit_code = 0;/* 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);const int __linuxthreads_initial_report_events;const char __linuxthreads_version[] = VERSION;/* Forward declarations */static void pthread_onexit_process(int retcode, void *arg);static void pthread_handle_sigcancel(int sig);static void pthread_handle_sigrestart(int sig);static void pthread_handle_sigdebug(int sig);int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime);/* 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 __NR_rt_sigactionstatic int current_rtmin = -1;static int current_rtmax = -1;int __pthread_sig_restart = SIGUSR1;int __pthread_sig_cancel = SIGUSR2;int __pthread_sig_debug;#else#if __SIGRTMAX - __SIGRTMIN >= 3static int current_rtmin = __SIGRTMIN + 3;static int current_rtmax = __SIGRTMAX;int __pthread_sig_restart = __SIGRTMIN;int __pthread_sig_cancel = __SIGRTMIN + 1;int __pthread_sig_debug = __SIGRTMIN + 2;void (*__pthread_restart)(pthread_descr) = __pthread_restart_new;void (*__pthread_suspend)(pthread_descr) = __pthread_wait_for_restart_signal;int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_new;#elsestatic int current_rtmin = __SIGRTMIN;static int current_rtmax = __SIGRTMAX;int __pthread_sig_restart = SIGUSR1;int __pthread_sig_cancel = SIGUSR2;int __pthread_sig_debug;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/* Return number of available real-time signal with highest priority. */int __libc_current_sigrtmin (void){ return current_rtmin;}/* Return number of available real-time signal with lowest priority. */int __libc_current_sigrtmax (void){ 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){ if (current_rtmin == -1 || current_rtmin > current_rtmax) /* We don't have anymore signal available. */ return -1; return high ? current_rtmin++ : current_rtmax--;}#endif/* 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 mask with e.g. sigsetjmp before creating the first thread); - a regular function called from pthread_create when needed. */static void pthread_initialize(void) __attribute__((constructor)); /* Do some minimal initialization which has to be done during the startup of the C library. */void __pthread_initialize_minimal(void){ /* If we have special thread_self processing, initialize * that for the main thread now. */#ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_initial_thread, 0);#endif}static void pthread_initialize(void){ struct sigaction sa; sigset_t mask; struct rlimit limit; int max_stack; /* If already done (e.g. by a constructor called earlier!), bail out */ if (__pthread_initial_thread_bos != NULL) return;#ifdef TEST_FOR_COMPARE_AND_SWAP /* Test if compare-and-swap is available */ __pthread_has_cas = compare_and_swap_is_available();#endif /* For the initial stack, reserve at least STACK_SIZE bytes of stack below the current stack address, and align that on a STACK_SIZE boundary. */ __pthread_initial_thread_bos = (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1)); /* Update the descriptor for the initial thread. */ __pthread_initial_thread.p_pid = __getpid(); /* If we have special thread_self processing, initialize that for the main thread now. */#ifdef INIT_THREAD_SELF INIT_THREAD_SELF(&__pthread_initial_thread, 0);#endif /* The errno/h_errno variable of the main thread are the global ones. */ __pthread_initial_thread.p_errnop = &_errno; __pthread_initial_thread.p_h_errnop = &_h_errno;#ifdef __UCLIBC_HAS_XLOCALE__ /* The locale of the main thread is the current locale in use. */ __pthread_initial_thread.locale = __curlocale_var;#endif /* __UCLIBC_HAS_XLOCALE__ */ { /* uClibc-specific stdio initialization for threads. */ FILE *fp; _stdio_user_locking = 0; /* 2 if threading not initialized */ for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) { if (fp->__user_locking != 1) { fp->__user_locking = 0; } } } /* Play with the stack size limit to make sure that no stack ever grows beyond STACK_SIZE minus two pages (one page for the thread descriptor
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -