📄 pthread.c
字号:
sigjmp_buf * jmpbuf; if (self == &__pthread_manager_thread) {#ifdef THREAD_SELF /* A new thread might get a cancel signal before it is fully initialized, so that the thread register might still point to the manager thread. Double check that this is really the manager thread. */ pthread_descr real_self = thread_self_stack(); if (real_self == &__pthread_manager_thread) { __pthread_manager_sighandler(sig); return; } /* Oops, thread_self() isn't working yet.. */ self = real_self;# ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr);# endif#else __pthread_manager_sighandler(sig); return;#endif } if (__builtin_expect (__pthread_exit_requested, 0)) { /* Main thread should accumulate times for thread manager and its children, so that timings for main thread account for all threads. */ if (self == __pthread_main_thread) {#ifdef USE_TLS waitpid(__pthread_manager_thread->p_pid, NULL, __WCLONE);#else waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);#endif } _exit(__pthread_exit_code); } if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) pthread_exit(PTHREAD_CANCELED); jmpbuf = THREAD_GETMEM(self, p_cancel_jmp); if (jmpbuf != NULL) { THREAD_SETMEM(self, p_cancel_jmp, NULL); siglongjmp(*jmpbuf, 1); } }}/* Handler for the DEBUG signal. The debugging strategy is as follows: On reception of a REQ_DEBUG request (sent by new threads created to the thread manager under debugging mode), the thread manager throws __pthread_sig_debug to itself. The debugger (if active) intercepts this signal, takes into account new threads and continue execution of the thread manager by propagating the signal because it doesn't know what it is specifically done for. In the current implementation, the thread manager simply discards it. */static void pthread_handle_sigdebug(int sig){ /* Nothing */}/* Reset the state of the thread machinery after a fork(). Close the pipe used for requests and set the main thread to the forked thread. Notice that we can't free the stack segments, as the forked thread may hold pointers into them. */void __pthread_reset_main_thread(){ pthread_descr self = thread_self(); if (__pthread_manager_request != -1) { /* Free the thread manager stack */ free(__pthread_manager_thread_bos); __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL; /* Close the two ends of the pipe */ __libc_close(__pthread_manager_request); __libc_close(__pthread_manager_reader); __pthread_manager_request = __pthread_manager_reader = -1; } /* Update the pid of the main thread */ THREAD_SETMEM(self, p_pid, __getpid()); /* Make the forked thread the main thread */ __pthread_main_thread = self; THREAD_SETMEM(self, p_nextlive, self); THREAD_SETMEM(self, p_prevlive, self); /* Now this thread modifies the global variables. */ THREAD_SETMEM(self, p_errnop, &_errno); THREAD_SETMEM(self, p_h_errnop, &_h_errno);}/* Process-wide exec() request */void __pthread_kill_other_threads_np(void){ struct sigaction sa; /* Terminate all other threads and thread manager */ pthread_onexit_process(0, NULL); /* Make current thread the main thread in case the calling thread changes its mind, does not exec(), and creates new threads instead. */ __pthread_reset_main_thread(); /* Reset the signal handlers behaviour for the signals the implementation uses since this would be passed to the new process. */ sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = SIG_DFL; __libc_sigaction(__pthread_sig_restart, &sa, NULL); __libc_sigaction(__pthread_sig_cancel, &sa, NULL); if (__pthread_sig_debug > 0) __libc_sigaction(__pthread_sig_debug, &sa, NULL);}weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)/* Concurrency symbol level. */static int current_level;int __pthread_setconcurrency(int level){ /* We don't do anything unless we have found a useful interpretation. */ current_level = level; return 0;}weak_alias (__pthread_setconcurrency, pthread_setconcurrency)int __pthread_getconcurrency(void){ return current_level;}weak_alias (__pthread_getconcurrency, pthread_getconcurrency)/* Primitives for controlling thread execution */void __pthread_wait_for_restart_signal(pthread_descr self){ sigset_t mask; sigprocmask(SIG_SETMASK, NULL, &mask); /* Get current signal mask */ sigdelset(&mask, __pthread_sig_restart); /* Unblock the restart signal */ THREAD_SETMEM(self, p_signal, 0); do { sigsuspend(&mask); /* Wait for signal */ } while (THREAD_GETMEM(self, p_signal) !=__pthread_sig_restart); READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */}#ifndef __NR_rt_sigaction/* The _old variants are for 2.0 and early 2.1 kernels which don't have RT signals. On these kernels, we use SIGUSR1 and SIGUSR2 for restart and cancellation. Since the restart signal does not queue, we use an atomic counter to create queuing semantics. This is needed to resolve a rare race condition in pthread_cond_timedwait_relative. */void __pthread_restart_old(pthread_descr th){ if (atomic_increment(&th->p_resume_count) == -1) kill(th->p_pid, __pthread_sig_restart);}void __pthread_suspend_old(pthread_descr self){ if (atomic_decrement(&self->p_resume_count) <= 0) __pthread_wait_for_restart_signal(self);}int__pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime){ sigset_t unblock, initial_mask; int was_signalled = 0; sigjmp_buf jmpbuf; if (atomic_decrement(&self->p_resume_count) == 0) { /* Set up a longjmp handler for the restart signal, unblock the signal and sleep. */ if (sigsetjmp(jmpbuf, 1) == 0) { THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); THREAD_SETMEM(self, p_signal, 0); /* Unblock the restart signal */ sigemptyset(&unblock); sigaddset(&unblock, __pthread_sig_restart); sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); while (1) { struct timeval now; struct timespec reltime; /* Compute a time offset relative to now. */ __gettimeofday (&now, NULL); reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; reltime.tv_sec = abstime->tv_sec - now.tv_sec; if (reltime.tv_nsec < 0) { reltime.tv_nsec += 1000000000; reltime.tv_sec -= 1; } /* Sleep for the required duration. If woken by a signal, resume waiting as required by Single Unix Specification. */ if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) break; } /* Block the restart signal again */ sigprocmask(SIG_SETMASK, &initial_mask, NULL); was_signalled = 0; } else { was_signalled = 1; } THREAD_SETMEM(self, p_signal_jmp, NULL); } /* Now was_signalled is true if we exited the above code due to the delivery of a restart signal. In that case, we know we have been dequeued and resumed and that the resume count is balanced. Otherwise, there are some cases to consider. First, try to bump up the resume count back to zero. If it goes to 1, it means restart() was invoked on this thread. The signal must be consumed and the count bumped down and everything is cool. We can return a 1 to the caller. Otherwise, no restart was delivered yet, so a potential race exists; we return a 0 to the caller which must deal with this race in an appropriate way; for example by atomically removing the thread from consideration for a wakeup---if such a thing fails, it means a restart is being delivered. */ if (!was_signalled) { if (atomic_increment(&self->p_resume_count) != -1) { __pthread_wait_for_restart_signal(self); atomic_decrement(&self->p_resume_count); /* should be zero now! */ /* woke spontaneously and consumed restart signal */ return 1; } /* woke spontaneously but did not consume restart---caller must resolve */ return 0; } /* woken due to restart signal */ return 1;}#endif /* __NR_rt_sigaction */#ifdef __NR_rt_sigactionvoid __pthread_restart_new(pthread_descr th){ /* The barrier is proabably not needed, in which case it still documents our assumptions. The intent is to commit previous writes to shared memory so the woken thread will have a consistent view. Complementary read barriers are present to the suspend functions. */ WRITE_MEMORY_BARRIER(); kill(th->p_pid, __pthread_sig_restart);}int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime){ sigset_t unblock, initial_mask; int was_signalled = 0; sigjmp_buf jmpbuf; if (sigsetjmp(jmpbuf, 1) == 0) { THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); THREAD_SETMEM(self, p_signal, 0); /* Unblock the restart signal */ sigemptyset(&unblock); sigaddset(&unblock, __pthread_sig_restart); sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); while (1) { struct timeval now; struct timespec reltime; /* Compute a time offset relative to now. */ gettimeofday (&now, NULL); reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; reltime.tv_sec = abstime->tv_sec - now.tv_sec; if (reltime.tv_nsec < 0) { reltime.tv_nsec += 1000000000; reltime.tv_sec -= 1; } /* Sleep for the required duration. If woken by a signal, resume waiting as required by Single Unix Specification. */ if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) break; } /* Block the restart signal again */ sigprocmask(SIG_SETMASK, &initial_mask, NULL); was_signalled = 0; } else { was_signalled = 1; } THREAD_SETMEM(self, p_signal_jmp, NULL); /* Now was_signalled is true if we exited the above code due to the delivery of a restart signal. In that case, everything is cool. We have been removed from whatever we were waiting on by the other thread, and consumed its signal. Otherwise we this thread woke up spontaneously, or due to a signal other than restart. This is an ambiguous case that must be resolved by the caller; the thread is still eligible for a restart wakeup so there is a race. */ READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */ return was_signalled;}#endif/* Debugging aid */#ifdef DEBUG_PT#include <stdarg.h>void __pthread_message(char * fmt, ...){ char buffer[1024]; va_list args; sprintf(buffer, "%05d : ", __getpid()); va_start(args, fmt); vsnprintf(buffer + 8, sizeof(buffer) - 8, fmt, args); va_end(args); TEMP_FAILURE_RETRY(__libc_write(2, buffer, strlen(buffer)));}#endif#ifndef __PIC__/* We need a hook to force the cancelation wrappers to be linked in when static libpthread is used. */extern const int __pthread_provide_wrappers;static const int *const __pthread_require_wrappers = &__pthread_provide_wrappers;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -