📄 pthread.c
字号:
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));#ifndef HAVE_Z_NODELETEextern void *__dso_handle __attribute__ ((weak));#endif/* 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#if HP_TIMING_AVAIL __pthread_initial_thread.p_cpuclock_offset = _dl_cpuclock_offset;#endif}void__pthread_init_max_stacksize(void){ struct rlimit limit; size_t max_stack; getrlimit(RLIMIT_STACK, &limit);#ifdef FLOATING_STACKS if (limit.rlim_cur == RLIM_INFINITY) limit.rlim_cur = ARCH_STACK_MAX_SIZE;# ifdef NEED_SEPARATE_REGISTER_STACK max_stack = limit.rlim_cur / 2;# else max_stack = limit.rlim_cur;# endif#else /* Play with the stack size limit to make sure that no stack ever grows beyond STACK_SIZE minus one page (to act as a guard page). */# ifdef NEED_SEPARATE_REGISTER_STACK /* STACK_SIZE bytes hold both the main stack and register backing store. The rlimit value applies to each individually. */ max_stack = STACK_SIZE/2 - __getpagesize ();# else max_stack = STACK_SIZE - __getpagesize();# endif if (limit.rlim_cur > max_stack) { limit.rlim_cur = max_stack; __libc_setrlimit(RLIMIT_STACK, &limit); }#endif __pthread_max_stacksize = max_stack;}static void pthread_initialize(void){ struct sigaction sa; sigset_t mask; /* 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#ifdef FLOATING_STACKS /* We don't need to know the bottom of the stack. Give the pointer some value to signal that initialization happened. */ __pthread_initial_thread_bos = (void *) -1l;#else /* Determine stack size limits . */ __pthread_init_max_stacksize ();# ifdef _STACK_GROWS_UP /* The initial thread already has all the stack it needs */ __pthread_initial_thread_bos = (char *) ((long)CURRENT_STACK_FRAME &~ (STACK_SIZE - 1));# else /* 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));# endif#endif /* Update the descriptor for the initial thread. */ __pthread_initial_thread.p_pid = __getpid(); /* Likewise for the resolver state _res. */ __pthread_initial_thread.p_resp = &_res;#ifdef __SIGRTMIN /* Initialize real-time signals. */ init_rtsigs ();#endif /* Setup signal handlers for the initial thread. Since signal handlers are shared between threads, these settings will be inherited by all other threads. */ sa.sa_handler = pthread_handle_sigrestart; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; __libc_sigaction(__pthread_sig_restart, &sa, NULL); sa.sa_handler = pthread_handle_sigcancel; // sa.sa_flags = 0; __libc_sigaction(__pthread_sig_cancel, &sa, NULL); if (__pthread_sig_debug > 0) { sa.sa_handler = pthread_handle_sigdebug; sigemptyset(&sa.sa_mask); // sa.sa_flags = 0; __libc_sigaction(__pthread_sig_debug, &sa, NULL); } /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */ sigemptyset(&mask); sigaddset(&mask, __pthread_sig_restart); sigprocmask(SIG_BLOCK, &mask, NULL); /* Register an exit function to kill all other threads. */ /* Do it early so that user-registered atexit functions are called before pthread_*exit_process. */#ifndef HAVE_Z_NODELETE if (__builtin_expect (&__dso_handle != NULL, 1)) __cxa_atexit ((void (*) (void *)) pthread_atexit_process, NULL, __dso_handle); else#endif on_exit (pthread_onexit_process, NULL); /* How many processors. */ __pthread_smp_kernel = is_smp_system ();}void __pthread_initialize(void){ pthread_initialize();}int __pthread_initialize_manager(void){ int manager_pipe[2]; int pid; struct pthread_request request;#ifndef HAVE_Z_NODELETE if (__builtin_expect (&__dso_handle != NULL, 1)) __cxa_atexit ((void (*) (void *)) pthread_atexit_retcode, NULL, __dso_handle);#endif if (__pthread_max_stacksize == 0) __pthread_init_max_stacksize (); /* If basic initialization not done yet (e.g. we're called from a constructor run before our constructor), do it now */ if (__pthread_initial_thread_bos == NULL) pthread_initialize(); /* Setup stack for thread manager */ __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE); if (__pthread_manager_thread_bos == NULL) return -1; __pthread_manager_thread_tos = __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE; /* Setup pipe to communicate with thread manager */ if (__libc_pipe(manager_pipe) == -1) { free(__pthread_manager_thread_bos); return -1; } /* Start the thread manager */ pid = 0; if (__builtin_expect (__pthread_initial_thread.p_report_events, 0)) { /* It's a bit more complicated. We have to report the creation of the manager thread. */ int idx = __td_eventword (TD_CREATE); uint32_t mask = __td_eventmask (TD_CREATE); if ((mask & (__pthread_threads_events.event_bits[idx] | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx])) != 0) { __pthread_lock(__pthread_manager_thread.p_lock, NULL);#ifdef NEED_SEPARATE_REGISTER_STACK pid = __clone2(__pthread_manager_event, (void **) __pthread_manager_thread_bos, THREAD_MANAGER_STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]);#elif _STACK_GROWS_UP pid = __clone(__pthread_manager_event, (void **) __pthread_manager_thread_bos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]);#else pid = __clone(__pthread_manager_event, (void **) __pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]);#endif if (pid != -1) { /* Now fill in the information about the new thread in the newly created thread's data structure. We cannot let the new thread do this since we don't know whether it was already scheduled when we send the event. */ __pthread_manager_thread.p_eventbuf.eventdata = &__pthread_manager_thread; __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE; __pthread_last_event = &__pthread_manager_thread; __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; __pthread_manager_thread.p_pid = pid; /* Now call the function which signals the event. */ __linuxthreads_create_event (); } /* Now restart the thread. */ __pthread_unlock(__pthread_manager_thread.p_lock); } } if (__builtin_expect (pid, 0) == 0) {#ifdef NEED_SEPARATE_REGISTER_STACK pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_bos, THREAD_MANAGER_STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]);#elif _STACK_GROWS_UP pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_bos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]);#else pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]);#endif } if (__builtin_expect (pid, 0) == -1) { free(__pthread_manager_thread_bos); __libc_close(manager_pipe[0]); __libc_close(manager_pipe[1]); return -1; } __pthread_manager_request = manager_pipe[1]; /* writing end */ __pthread_manager_reader = manager_pipe[0]; /* reading end */ __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; __pthread_manager_thread.p_pid = pid; /* Make gdb aware of new thread manager */ if (__builtin_expect (__pthread_threads_debug, 0) && __pthread_sig_debug > 0) { raise(__pthread_sig_debug); /* We suspend ourself and gdb will wake us up when it is ready to handle us. */ __pthread_wait_for_restart_signal(thread_self()); } /* Synchronize debugging of the thread manager */ request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); return 0;}/* Thread creation */int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg){ pthread_descr self = thread_self(); struct pthread_request request; int retval; if (__builtin_expect (__pthread_manager_request, 0) < 0) { if (__pthread_initialize_manager() < 0) return EAGAIN; } request.req_thread = self; request.req_kind = REQ_CREATE; request.req_args.create.attr = attr; request.req_args.create.fn = start_routine; request.req_args.create.arg = arg; sigprocmask(SIG_SETMASK, (const sigset_t *) NULL, &request.req_args.create.mask); TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); retval = THREAD_GETMEM(self, p_retcode); if (__builtin_expect (retval, 0) == 0) *thread = (pthread_t) THREAD_GETMEM(self, p_retval); return retval;}versioned_symbol (libpthread, __pthread_create_2_1, pthread_create, GLIBC_2_1);#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)int __pthread_create_2_0(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg){ /* The ATTR attribute is not really of type `pthread_attr_t *'. It has the old size and access to the new members might crash the program. We convert the struct now. */ pthread_attr_t new_attr; if (attr != NULL) { size_t ps = __getpagesize (); memcpy (&new_attr, attr, (size_t) &(((pthread_attr_t*)NULL)->__guardsize)); new_attr.__guardsize = ps; new_attr.__stackaddr_set = 0; new_attr.__stackaddr = NULL; new_attr.__stacksize = STACK_SIZE - ps; attr = &new_attr; } return __pthread_create_2_1 (thread, attr, start_routine, arg);}compat_symbol (libpthread, __pthread_create_2_0, pthread_create, GLIBC_2_0);#endif/* Simple operations on thread identifiers */pthread_t pthread_self(void){ pthread_descr self = thread_self(); return THREAD_GETMEM(self, p_tid);}int pthread_equal(pthread_t thread1, pthread_t thread2){ return thread1 == thread2;}/* Helper function for thread_self in the case of user-provided stacks */#ifndef THREAD_SELFpthread_descr __pthread_find_self(void){ char * sp = CURRENT_STACK_FRAME; pthread_handle h; /* __pthread_handles[0] is the initial thread, __pthread_handles[1] is the manager threads handled specially in thread_self(), so start at 2 */ h = __pthread_handles + 2; while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++; return h->h_descr;}#elsestatic pthread_descr thread_self_stack(void){ char *sp = CURRENT_STACK_FRAME; pthread_handle h; if (sp >= __pthread_manager_thread_bos && sp < __pthread_manager_thread_tos) return &__pthread_manager_thread; h = __pthread_handles + 2; while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++; return h->h_descr;}#endif/* Thread scheduling */int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param){ pthread_handle handle = thread_handle(thread); pthread_descr th; __pthread_lock(&handle->h_lock, NULL); if (__builtin_expect (invalid_handle(handle, thread), 0)) { __pthread_unlock(&handle->h_lock); return ESRCH; } th = handle->h_descr; if (__builtin_expect (__sched_setscheduler(th->p_pid, policy, param) == -1, 0)) { __pthread_unlock(&handle->h_lock); return errno; } th->p_priority = policy == SCHED_OTHER ? 0 : param->sched_priority; __pthread_unlock(&handle->h_lock); if (__pthread_manager_request >= 0) __pthread_manager_adjust_prio(th->p_priority); return 0;}int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param){ pthread_handle handle = thread_handle(thread); int pid, pol; __pthread_lock(&handle->h_lock, NULL); if (__builtin_expect (invalid_handle(handle, thread), 0)) { __pthread_unlock(&handle->h_lock); return ESRCH; } pid = handle->h_descr->p_pid; __pthread_unlock(&handle->h_lock); pol = __sched_getscheduler(pid); if (__builtin_expect (pol, 0) == -1) return errno; if (__sched_getparam(pid, param) == -1) return errno; *policy = pol; return 0;}int __pthread_yield (void){ /* For now this is equivalent with the POSIX call. */ return sched_yield ();}weak_alias (__pthread_yield, pthread_yield)/* Process-wide exit() request */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -