📄 manager.c
字号:
new_thread->p_eventbuf.eventnum = TD_CREATE; __pthread_last_event = new_thread; /* We have to set the PID here since the callback function in the debug library will need it and we cannot guarantee the child got scheduled before the debugger. */ new_thread->p_pid = pid; /* Now call the function which signals the event. */ __linuxthreads_create_event (); /* Now restart the thread. */ __pthread_unlock(new_thread->p_lock); } } } if (pid == 0) {#ifdef NEED_SEPARATE_REGISTER_STACK pid = __clone2(pthread_start_thread, (void **)new_thread_bottom, (char *)new_thread - new_thread_bottom, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | __pthread_sig_cancel, new_thread);#elif _STACK_GROWS_UP pid = __clone(pthread_start_thread, (void **) new_thread_bottom, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | __pthread_sig_cancel, new_thread);#else pid = __clone(pthread_start_thread, (void **) new_thread, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | __pthread_sig_cancel, new_thread);#endif /* !NEED_SEPARATE_REGISTER_STACK */ } /* Check if cloning succeeded */ if (pid == -1) { /* Free the stack if we allocated it */ if (attr == NULL || !attr->__stackaddr_set) {#ifdef NEED_SEPARATE_REGISTER_STACK size_t stacksize = ((char *)(new_thread->p_guardaddr) - new_thread_bottom); munmap((caddr_t)new_thread_bottom, 2 * stacksize + new_thread->p_guardsize);#elif _STACK_GROWS_UP size_t stacksize = guardaddr - (char *)new_thread; munmap(new_thread, stacksize + guardsize);#else size_t stacksize = (char *)(new_thread+1) - new_thread_bottom; munmap(new_thread_bottom - guardsize, guardsize + stacksize);#endif } __pthread_handles[sseg].h_descr = NULL; __pthread_handles[sseg].h_bottom = NULL; __pthread_handles_num--; return errno; } /* Insert new thread in doubly linked list of active threads */ new_thread->p_prevlive = __pthread_main_thread; new_thread->p_nextlive = __pthread_main_thread->p_nextlive; __pthread_main_thread->p_nextlive->p_prevlive = new_thread; __pthread_main_thread->p_nextlive = new_thread; /* Set pid field of the new thread, in case we get there before the child starts. */ new_thread->p_pid = pid; return 0;}/* Try to free the resources of a thread when requested by pthread_join or pthread_detach on a terminated thread. */static void pthread_free(pthread_descr th){ pthread_handle handle; pthread_readlock_info *iter, *next; ASSERT(th->p_exited); /* Make the handle invalid */ handle = thread_handle(th->p_tid); __pthread_lock(&handle->h_lock, NULL); handle->h_descr = NULL; handle->h_bottom = (char *)(-1L); __pthread_unlock(&handle->h_lock);#ifdef FREE_THREAD FREE_THREAD(th, th->p_nr);#endif /* One fewer threads in __pthread_handles */ __pthread_handles_num--; /* Destroy read lock list, and list of free read lock structures. If the former is not empty, it means the thread exited while holding read locks! */ for (iter = th->p_readlock_list; iter != NULL; iter = next) { next = iter->pr_next; free(iter); } for (iter = th->p_readlock_free; iter != NULL; iter = next) { next = iter->pr_next; free(iter); } /* If initial thread, nothing to free */ if (!th->p_userstack) { size_t guardsize = th->p_guardsize; /* Free the stack and thread descriptor area */ char *guardaddr = th->p_guardaddr;#ifdef _STACK_GROWS_UP size_t stacksize = guardaddr - (char *)th; guardaddr = (char *)th;#else /* Guardaddr is always set, even if guardsize is 0. This allows us to compute everything else. */ size_t stacksize = (char *)(th+1) - guardaddr - guardsize;#ifdef NEED_SEPARATE_REGISTER_STACK /* Take account of the register stack, which is below guardaddr. */ guardaddr -= stacksize; stacksize *= 2;#endif#endif /* Unmap the stack. */ munmap(guardaddr, stacksize + guardsize); }}/* Handle threads that have exited */static void pthread_exited(pid_t pid){ pthread_descr th; int detached; /* Find thread with that pid */ for (th = __pthread_main_thread->p_nextlive; th != __pthread_main_thread; th = th->p_nextlive) { if (th->p_pid == pid) { /* Remove thread from list of active threads */ th->p_nextlive->p_prevlive = th->p_prevlive; th->p_prevlive->p_nextlive = th->p_nextlive; /* Mark thread as exited, and if detached, free its resources */ __pthread_lock(th->p_lock, NULL); th->p_exited = 1; /* If we have to signal this event do it now. */ if (th->p_report_events) { /* See whether TD_REAP is in any of the mask. */ int idx = __td_eventword (TD_REAP); uint32_t mask = __td_eventmask (TD_REAP); if ((mask & (__pthread_threads_events.event_bits[idx] | th->p_eventbuf.eventmask.event_bits[idx])) != 0) { /* Yep, we have to signal the reapage. */ th->p_eventbuf.eventnum = TD_REAP; th->p_eventbuf.eventdata = th; __pthread_last_event = th; /* Now call the function to signal the event. */ __linuxthreads_reap_event(); } } detached = th->p_detached; __pthread_unlock(th->p_lock); if (detached) pthread_free(th); break; } } /* If all threads have exited and the main thread is pending on a pthread_exit, wake up the main thread and terminate ourselves. */ if (main_thread_exiting && __pthread_main_thread->p_nextlive == __pthread_main_thread) { restart(__pthread_main_thread); /* Same logic as REQ_MAIN_THREAD_EXIT. */ }}static void pthread_reap_children(void){ pid_t pid; int status; while ((pid = __libc___waitpid(-1, &status, WNOHANG | __WCLONE)) > 0) { pthread_exited(pid); if (WIFSIGNALED(status)) { /* If a thread died due to a signal, send the same signal to all other threads, including the main thread. */ pthread_kill_all_threads(WTERMSIG(status), 1); _exit(0); } }}/* Try to free the resources of a thread when requested by pthread_join or pthread_detach on a terminated thread. */static void pthread_handle_free(pthread_t th_id){ pthread_handle handle = thread_handle(th_id); pthread_descr th; __pthread_lock(&handle->h_lock, NULL); if (nonexisting_handle(handle, th_id)) { /* pthread_reap_children has deallocated the thread already, nothing needs to be done */ __pthread_unlock(&handle->h_lock); return; } th = handle->h_descr; if (th->p_exited) { __pthread_unlock(&handle->h_lock); pthread_free(th); } else { /* The Unix process of the thread is still running. Mark the thread as detached so that the thread manager will deallocate its resources when the Unix process exits. */ th->p_detached = 1; __pthread_unlock(&handle->h_lock); }}/* Send a signal to all running threads */static void pthread_kill_all_threads(int sig, int main_thread_also){ pthread_descr th; for (th = __pthread_main_thread->p_nextlive; th != __pthread_main_thread; th = th->p_nextlive) { kill(th->p_pid, sig); } if (main_thread_also) { kill(__pthread_main_thread->p_pid, sig); }}static void pthread_for_each_thread(void *arg, void (*fn)(void *, pthread_descr)){ pthread_descr th; for (th = __pthread_main_thread->p_nextlive; th != __pthread_main_thread; th = th->p_nextlive) { fn(arg, th); } fn(arg, __pthread_main_thread);}/* Process-wide exit() */static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode){ pthread_descr th; __pthread_exit_requested = 1; __pthread_exit_code = exitcode; /* A forced asynchronous cancellation follows. Make sure we won't get stuck later in the main thread with a system lock being held by one of the cancelled threads. Ideally one would use the same code as in pthread_atfork(), but we can't distinguish system and user handlers there. */ __flockfilelist(); /* Send the CANCEL signal to all running threads, including the main thread, but excluding the thread from which the exit request originated (that thread must complete the exit, e.g. calling atexit functions and flushing stdio buffers). */ for (th = issuing_thread->p_nextlive; th != issuing_thread; th = th->p_nextlive) { kill(th->p_pid, __pthread_sig_cancel); } /* Now, wait for all these threads, so that they don't become zombies and their times are properly added to the thread manager's times. */ for (th = issuing_thread->p_nextlive; th != issuing_thread; th = th->p_nextlive) { __waitpid(th->p_pid, NULL, __WCLONE); } __fresetlockfiles(); restart(issuing_thread); _exit(0);}/* Handler for __pthread_sig_cancel in thread manager thread */void __pthread_manager_sighandler(int sig){ int kick_manager = terminated_children == 0 && main_thread_exiting; terminated_children = 1; /* If the main thread is terminating, kick the thread manager loop each time some threads terminate. This eliminates a two second shutdown delay caused by the thread manager sleeping in the call to __poll(). Instead, the thread manager is kicked into action, reaps the outstanding threads and resumes the main thread so that it can complete the shutdown. */ if (kick_manager) { struct pthread_request request; request.req_thread = 0; request.req_kind = REQ_KICK; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); }}/* Adjust priority of thread manager so that it always run at a priority higher than all threads */void __pthread_manager_adjust_prio(int thread_prio){ struct sched_param param; if (thread_prio <= __pthread_manager_thread.p_priority) return; param.sched_priority = thread_prio < __sched_get_priority_max(SCHED_FIFO) ? thread_prio + 1 : thread_prio; __sched_setscheduler(__pthread_manager_thread.p_pid, SCHED_FIFO, ¶m); __pthread_manager_thread.p_priority = thread_prio;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -