diff options
author | Ulrich Drepper <drepper@redhat.com> | 1998-03-11 12:42:25 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 1998-03-11 12:42:25 +0000 |
commit | 5afdca0087dad2994ad4fcdfe7f489f4dbcab7b3 (patch) | |
tree | c9c82db2ff92537b921361a02a284b0e18a594b8 /linuxthreads/manager.c | |
parent | 3d76e7784700c20fc222920b2a22baba006daa15 (diff) | |
download | glibc-5afdca0087dad2994ad4fcdfe7f489f4dbcab7b3.tar.gz glibc-5afdca0087dad2994ad4fcdfe7f489f4dbcab7b3.tar.xz glibc-5afdca0087dad2994ad4fcdfe7f489f4dbcab7b3.zip |
LinuxThreads library.
1998-03-11 00:42 Wolfram Gloger <wmglo@dent.med.uni-muenchen.de> * linuxthreads/manager.c: Enable resetting of the thread scheduling policy to SCHED_OTHER when the parent thread has a different one. 1998-02-01 13:51 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define _POSIX_ASYNCHRONOUS_IO. * sysdeps/pthread/pthread.h: Define bits for Unix98 variants of mutexes. * mutex.c: Implement new mutex types. * internals.h: Include <signal.h>. * libpthread.map: Add __erno_location and __h_errno_location. * errno.c: Return pointer to variable actually in use. This might not be the one in the thread structure. * internals.h (struct _pthread_descr_struct): Add new fields p_errnop and p_h_errnop. * manager.c (__pthread_manager): Set p_errnop and p_h_errnop member of manager thread structure. (pthread_handle_create): Set p_errnop and p_h_errnop members for new thread. * pthread.c: Adapt initializer for thread structures. (__pthread_initial_thread): Set p_errnop and p_h_errnop member. (__pthread_reset_main_thread): Reset p_errnop and p_h_errnop of current thread to global variables. 1998-01-31 17:27 Ulrich Drepper <drepper@cygnus.com> * rwlock.c: New file. * Makefile (libpthread-routines): Add rwlock. * sysdeps/pthread/pthread.h: Define data structures and declare functions. * libpthread.map: Add new functions. 1997-12-18 13:50 Philip Blundell <pb@nexus.co.uk> * sysdeps/arm/pt-machine.h: New file; add ARM support. * sysdeps/arm/Implies: likewise. * README: Document it. 1997-12-13 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * signals.c: Remove unneeded initializer for sigwaited, saving a 1997-04-11 01:18 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * semaphore.c (sem_init): Set sem_spinlock only if available. 1997-12-04 01:48 Ulrich Drepper <drepper@cygnus.com> * mutex.c: Implement PTHREAD_MUTEX_CHECKERROR. * sysdeps/pthread/pthread.h: Define PTHREAD_MUTEX_CHECKERROR. * Makefile: Update from LinuxThreads 0.7. * internals.h. Likewise. * manager.c: Likewise. * mutex.c: Likewise. * pthread.c: Likewise. * signals.c: Likewise. * specific.c: Likewise. * Examples/ex3.c: Likewise. 1997-11-20 18:13 Ulrich Drepper <drepper@cygnus.com> * pthread.c (__pthread_reset_main_thread): Close pipe only if still open. 1997-10-29 05:38 Ulrich Drepper <drepper@cygnus.com> * wrapsyscall.c: Add socket functions which are also cancelation points. 1997-10-19 21:40 Wolfram Gloger <wg@wolfram.dent.med.uni-muenchen.de> * specific.c (__libc_internal_tsd_set, __libc_internal_tsd_get): New functions for fast thread specific data within libc. * internals.h: Add new array p_libc_specific to struct _pthread_descr_struct. * sysdeps/pthread/bits/libc-lock.h: Declare new functions. 1997-10-13 05:39 Ulrich Drepper <drepper@cygnus.com> * semaphore.h: Add __BEGIN_DECLS/__END_DECLS. Reported by Ralf Corsepius <corsepiu@faw.uni-ulm.de>. 1997-08-29 03:05 Ulrich Drepper <drepper@cygnus.com> * internals.h (struct _pthread_descr_struct): Add definitions for two-level specific key handling. * manager.c (pthread_handle_create): Initialize specific memory array. * specific.c: Implement two-level key handling. * weaks.c: Don't provide dummy key handling. * sysdeps/pthread/bits/libc-lock.h: Typedef __libc_lock_t (no #define). Add definition of __libc_key_t. * sysdeps/unix/sysv/linux/bits/local_lim.h: Define PTHREAD_KEYS_MAX as 1024. Add definition of _POSIX_THREAD_DESTRUCTOR_ITERATIONS and PTHREAD_DESTRUCTOR_ITERATIONS. * manager.c (pthread_handle_create): Compare mmap result with MAP_FAILED. * ptfork.c: Rename to __pthread_atfork and make old name a weak alias. * sysdeps/pthread/bits/pthread.h: Add prototype for __pthread_atfork. 1997-08-22 19:04 Richard Henderson <rth@cygnus.com> sysdeps/sparc -> sysdeps/sparc/sparc32 sysdeps/sparc64 -> sysdeps/sparc/sparc64 * internals.h: Change definition of THREAD_SELF to be an expression, not a statement that did a return. * sysdeps/alpha/pt-machine.h (THREAD_SELF): Update accordingly. * sysdeps/sparc/sparc32/pt-machine.h (THREAD_SELF, INIT_THREAD_SELF): Follow Solaris and use a "system reserved" register (%g6) to hold the thread descriptor. * sysdeps/sparc/sparc64/pt-machine.h: Likewise. 1997-08-03 00:09 Ulrich Drepper <drepper@cygnus.com> * mutex.c: Correct pthread_once. Patch by Xavier Leroy. * sysdeps/pthread/pthread.h: Add prototype for __pthread_once. * sysdeps/pthread/bits/pthread.h: Add macros for __libc_once. * semaphore.c: Include spinlock.h only when needed. * specific.c (__pthread_setsepcific, __pthread_getspecific): Reject keys for entries not in use. * weaks.c: Implement key handling functions for real. 1997-06-29 01:04 Richard Henderson <richard@gnu.ai.mit.edu> Initial sparc64-linux support: * linuxthreads/sysdeps/sparc64/Implies: New file. * linuxthreads/sysdeps/sparc64/pt-machine.h: Likewise. 1997-06-29 00:48 Ulrich Drepper <drepper@cygnus.com> * semaphore.c: Include spinlock.h at correct place. Patch by HJ Lu. 1997-06-13 10:06 Richard Henderson <rth@tamu.edu> The Great Bit File Move: * sysdeps/alpha/semaphorebits.h: -> .../bits/semaphore.h. * sysdeps/powerpc/semaphorebits.h: Likewise. * sysdeps/pthread/cmpxchg/semaphorebits.h: Likewise. * sysdeps/pthread/no-cmpxchg/semaphorebits.h: Likewise. * sysdeps/pthread/libc-lock.h: -> bits/ * sysdeps/pthread/stdio-lock.h: Likewise. * sysdeps/unix/sysv/linux/local_lim.h: Likewise. * sysdeps/unix/sysv/linux/posix_opt.h: Likewise. * semaphore.h: Likewise. * sysdeps/pthread/pthread.h: Likewise. * lockfile.c: <foo.h> -> <bits/foo.h>. * semaphore.h: Likewise. * Makefile: (headers): foo.h -> bits/foo.h. * sysdeps/pthread/Makefile: Likewise. 1997-04-11 01:18 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * semaphore.c (sem_init): Set sem_spinlock only if available. * sysdeps/m68k/pt-machine.h (testandset, __compare_and_swap): Fix asm constraints. 1997-04-09 03:00 Ulrich Drepper <drepper@cygnus.com> Update from LinuxThreads 0.6. * attr.c (pthread_attr_getdetachstate): Use __sched_get_priority_max and __sched_get_priority_min instead of names without `__'. * manager.c: Rewrite large parts to implement opaque pthread_t. * cancel.c: Adapt for opaque pthread_t type. * condvar.c: Likewise. * errno.c: Likewise. * join.c: Likewise. * mutex.c: Likewise. * pthread.c: Likewise. * signals.c: Likewise. * specific.c: Likewise. * restart.h: Likewise. * queue.h: Likewise. * Examples/ex3.c: Likewise. * Examples/ex4.c: Likewise. * sysdeps/pthread/pthread.h: Likewise. * pthread.c: Accumulate time for all threads in thread manager. * semaphore.c: Implement fallback implementation for architectures sometimes missing compare-exchange operations. * cancel.c (pthread_cancel): Validate handle argument. * join.c (pthread_join): Likewise. (pthread_detach): Likewise. * signals.c (pthread_kill): Likewise. * spinlock.h (acquire): Use __sched_yield not sched_yield. * queue.h (enqueue): Enqueue thread according to priority. * internals.c (struct pthread_start_args): New struct for passing args to cloning function. (struct _pthread): Rename to _pthread_descr_struct and adapt for opaque pthread_t. * Examples/Makefile (clean): Pass -f option to rm. * sysdeps/i386/pt-machine.h: Add check for compare-exchange instruction and define TEST_FOR_COMPARE_AND_SWAP. * sysdeps/i386/i486/pt-machine.h: Removed. * sysdeps/unix/sysv/linux/local_lim.h (PTHREAD_THREADS_MAX): Increase to 1024. 1997-04-04 16:38 Ulrich Drepper <drepper@cygnus.com> * restart.h (suspend): Clear p_signal before suspending. (suspend_with_cancellation): Likewise. Patch by Xavier Leroy <Xavier.Leroy@inria.fr>. * weaks.c: Make __pthread_key_create return 1. * sysdeps/pthread/libc-lock.h: Define __libc_key_create, __libc_getspecific, __libc_setspecific, and __libc_key_t. * sysdeps/pthread/stdio-lock.h: Don't care for implementation not using libio. 1997-03-19 15:13 Miguel de Icaza <miguel@nuclecu.unam.mx> * sysdeps/sparc/pt-machine (RELEASE): Fix. 1997-03-01 07:55 Geoff Keating <geoffk@ozemail.com.au> * sysdeps/powerpc/Implies: Added. * sysdeps/powerpc/pt-machine.h: Added. * sysdeps/powerpc/semaphorebits.h: Added. 1997-01-22 01:22 Ulrich Drepper <drepper@cygnus.com> * linuxtheads/pthread.c (__pthread_initial_thread): Correct initializer. (__pthread_manager_thread): Likewise. Reported by Andreas Jaeger. 1997-01-18 22:15 Richard Henderson <rth@tamu.edu> Since sigset_t no longer fits in a register, we can't pass in the thread's initial mask so easily. Take this opportunity to simplify the clone implementation by only accepting a single void* argument. * linuxthreads/manager.c (__pthread_manager): Put thread vitals in the thread struct instead of as arguments through clone. (pthread_start_thread): Look for them there. * linuxthreads/internals.h (struct _pthread): Add p_initial_fn, p_initial_fn_arg, p_initial_mask. Fix __pthread_manager proto. * linuxthreads/pthread.c (pthread_initialize_manager): Revise clone invocation.
Diffstat (limited to 'linuxthreads/manager.c')
-rw-r--r-- | linuxthreads/manager.c | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c new file mode 100644 index 0000000000..325955db4a --- /dev/null +++ b/linuxthreads/manager.c @@ -0,0 +1,400 @@ +/* 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. */ + +/* The "thread manager" thread: manages creation and termination of threads */ + +#include <errno.h> +#include <sched.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/select.h> /* for select */ +#include <sys/mman.h> /* for mmap */ +#include <sys/time.h> +#include <sys/wait.h> /* for waitpid macros */ +#include <linux/tasks.h> + +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" + +/* Array of active threads. Entry 0 is reserved for the initial thread. */ + +struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] = +{ { 0, &__pthread_initial_thread}, /* All NULLs */ }; + +/* Mapping from stack segment to thread descriptor. */ +/* Stack segment numbers are also indices into the __pthread_handles array. */ +/* Stack segment number 0 is reserved for the initial thread. */ + +static inline pthread_descr thread_segment(int seg) +{ + return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE) + - 1; +} + +/* Flag set in signal handler to record child termination */ + +static volatile int terminated_children = 0; + +/* Flag set when the initial thread is blocked on pthread_exit waiting + for all other threads to terminate */ + +static int main_thread_exiting = 0; + +/* Counter used to generate unique thread identifier. + Thread identifier is pthread_threads_counter + segment. */ + +static pthread_t pthread_threads_counter = 0; + +/* Forward declarations */ + +static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg, + sigset_t *mask, int father_pid); +static void pthread_handle_free(pthread_descr th); +static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode); +static void pthread_reap_children(void); +static void pthread_kill_all_threads(int sig, int main_thread_also); + +/* The server thread managing requests for thread creation and termination */ + +int __pthread_manager(void *arg) +{ + int reqfd = (int)arg; + sigset_t mask; + fd_set readfds; + struct timeval timeout; + int n; + struct pthread_request request; + + /* If we have special thread_self processing, initialize it. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(&__pthread_manager_thread); +#endif + /* Set the error variable. */ + __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno; + __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno; + /* Block all signals except PTHREAD_SIG_RESTART */ + sigfillset(&mask); + sigdelset(&mask, PTHREAD_SIG_RESTART); + sigprocmask(SIG_SETMASK, &mask, NULL); + /* Enter server loop */ + while(1) { + FD_ZERO(&readfds); + FD_SET(reqfd, &readfds); + timeout.tv_sec = 2; + timeout.tv_usec = 0; + n = __select(FD_SETSIZE, &readfds, NULL, NULL, &timeout); + /* Check for termination of the main thread */ + if (getppid() == 1) { + pthread_kill_all_threads(SIGKILL, 0); + _exit(0); + } + /* Check for dead children */ + if (terminated_children) { + terminated_children = 0; + pthread_reap_children(); + } + /* Read and execute request */ + if (n == 1 && FD_ISSET(reqfd, &readfds)) { + n = __libc_read(reqfd, (char *)&request, sizeof(request)); + ASSERT(n == sizeof(request)); + switch(request.req_kind) { + case REQ_CREATE: + request.req_thread->p_retcode = + pthread_handle_create((pthread_t *) &request.req_thread->p_retval, + request.req_args.create.attr, + request.req_args.create.fn, + request.req_args.create.arg, + &request.req_args.create.mask, + request.req_thread->p_pid); + restart(request.req_thread); + break; + case REQ_FREE: + pthread_handle_free(request.req_args.free.thread); + break; + case REQ_PROCESS_EXIT: + pthread_handle_exit(request.req_thread, + request.req_args.exit.code); + break; + case REQ_MAIN_THREAD_EXIT: + main_thread_exiting = 1; + if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { + restart(__pthread_main_thread); + return 0; + } + break; + } + } + } +} + +/* Process creation */ + +static int pthread_start_thread(void *arg) +{ + pthread_descr self = (pthread_descr) arg; + void * outcome; + /* Initialize special thread_self processing, if any. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(self); +#endif + /* Make sure our pid field is initialized, just in case we get there + before our father has initialized it. */ + self->p_pid = __getpid(); + /* Initial signal mask is that of the creating thread. (Otherwise, + we'd just inherit the mask of the thread manager.) */ + sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); + /* Set the scheduling policy and priority for the new thread, if needed */ + if (self->p_start_args.schedpolicy >= 0) + __sched_setscheduler(self->p_pid, self->p_start_args.schedpolicy, + &self->p_start_args.schedparam); + /* Run the thread code */ + outcome = self->p_start_args.start_routine(self->p_start_args.arg); + /* Exit with the given return value */ + pthread_exit(outcome); + return 0; +} + +static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg, + sigset_t * mask, int father_pid) +{ + size_t sseg; + int pid; + pthread_descr new_thread; + pthread_t new_thread_id; + int i; + + /* Find a free stack segment for the current stack */ + for (sseg = 1; ; sseg++) { + if (sseg >= PTHREAD_THREADS_MAX) return EAGAIN; + if (__pthread_handles[sseg].h_descr != NULL) continue; + new_thread = thread_segment(sseg); + /* Allocate space for stack and thread descriptor. */ + if (mmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE), + INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -1, 0) + != MAP_FAILED) break; + /* It seems part of this segment is already mapped. Try the next. */ + } + /* Allocate new thread identifier */ + pthread_threads_counter += PTHREAD_THREADS_MAX; + new_thread_id = sseg + pthread_threads_counter; + /* Initialize the thread descriptor */ + new_thread->p_nextwaiting = NULL; + new_thread->p_tid = new_thread_id; + new_thread->p_priority = 0; + new_thread->p_spinlock = &(__pthread_handles[sseg].h_spinlock); + new_thread->p_signal = 0; + new_thread->p_signal_jmp = NULL; + new_thread->p_cancel_jmp = NULL; + new_thread->p_terminated = 0; + new_thread->p_detached = attr == NULL ? 0 : attr->detachstate; + new_thread->p_exited = 0; + new_thread->p_retval = NULL; + new_thread->p_joining = NULL; + new_thread->p_cleanup = NULL; + new_thread->p_cancelstate = PTHREAD_CANCEL_ENABLE; + new_thread->p_canceltype = PTHREAD_CANCEL_DEFERRED; + new_thread->p_canceled = 0; + new_thread->p_errnop = &new_thread->p_errno; + new_thread->p_errno = 0; + new_thread->p_h_errnop = &new_thread->p_h_errno; + new_thread->p_h_errno = 0; + for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) + new_thread->p_specific[i] = NULL; + /* Initialize the thread handle */ + __pthread_handles[sseg].h_spinlock = 0; /* should already be 0 */ + __pthread_handles[sseg].h_descr = new_thread; + /* Determine scheduling parameters for the thread */ + new_thread->p_start_args.schedpolicy = -1; + if (attr != NULL) { + switch(attr->inheritsched) { + case PTHREAD_EXPLICIT_SCHED: + new_thread->p_start_args.schedpolicy = attr->schedpolicy; + new_thread->p_start_args.schedparam = attr->schedparam; + break; + case PTHREAD_INHERIT_SCHED: + /* schedpolicy doesn't need to be set, only get priority */ + __sched_getparam(father_pid, &new_thread->p_start_args.schedparam); + break; + } + new_thread->p_priority = + new_thread->p_start_args.schedparam.sched_priority; + } + /* Finish setting up arguments to pthread_start_thread */ + new_thread->p_start_args.start_routine = start_routine; + new_thread->p_start_args.arg = arg; + new_thread->p_start_args.mask = *mask; + /* Do the cloning */ + pid = __clone(pthread_start_thread, (void **) new_thread, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + PTHREAD_SIG_RESTART, + new_thread); + /* Check if cloning succeeded */ + if (pid == -1) { + /* Free the stack */ + munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE), + INITIAL_STACK_SIZE); + __pthread_handles[sseg].h_descr = NULL; + 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; + /* We're all set */ + *thread = new_thread_id; + return 0; +} + +/* Free the resources of a thread. */ + +static void pthread_free(pthread_descr th) +{ + pthread_handle handle; + ASSERT(th->p_exited); + /* Make the handle invalid */ + handle = thread_handle(th->p_tid); + acquire(&handle->h_spinlock); + handle->h_descr = NULL; + release(&handle->h_spinlock); + /* If initial thread, nothing to free */ + if (th == &__pthread_initial_thread) return; + /* Free the stack and thread descriptor area */ + munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE); +} + +/* 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 */ + acquire(th->p_spinlock); + th->p_exited = 1; + detached = th->p_detached; + release(th->p_spinlock); + 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); + _exit(0); + } +} + +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); + } + } +} + +/* Free the resources of a thread */ + +static void pthread_handle_free(pthread_descr th) +{ + acquire(th->p_spinlock); + if (th->p_exited) { + release(th->p_spinlock); + 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; + release(th->p_spinlock); + } +} + +/* 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); + } +} + +/* 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; + /* 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); + } + restart(issuing_thread); + _exit(0); +} + +/* Handler for PTHREAD_SIG_RESTART in thread manager thread */ + +void __pthread_manager_sighandler(int sig) +{ + terminated_children = 1; +} |