(__pthread_threads_events): New variable.
[kopensolaris-gnu/glibc.git] / linuxthreads / manager.c
1 /* Linuxthreads - a simple clone()-based implementation of Posix        */
2 /* threads for Linux.                                                   */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
4 /*                                                                      */
5 /* This program is free software; you can redistribute it and/or        */
6 /* modify it under the terms of the GNU Library General Public License  */
7 /* as published by the Free Software Foundation; either version 2       */
8 /* of the License, or (at your option) any later version.               */
9 /*                                                                      */
10 /* This program is distributed in the hope that it will be useful,      */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
13 /* GNU Library General Public License for more details.                 */
14
15 /* The "thread manager" thread: manages creation and termination of threads */
16
17 #include <errno.h>
18 #include <sched.h>
19 #include <stddef.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/poll.h>           /* for poll */
25 #include <sys/mman.h>           /* for mmap */
26 #include <sys/param.h>
27 #include <sys/time.h>
28 #include <sys/wait.h>           /* for waitpid macros */
29
30 #include "pthread.h"
31 #include "internals.h"
32 #include "spinlock.h"
33 #include "restart.h"
34 #include "semaphore.h"
35
36 /* Array of active threads. Entry 0 is reserved for the initial thread. */
37 struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
38 { { LOCK_INITIALIZER, &__pthread_initial_thread, 0},
39   { LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ };
40
41 /* For debugging purposes put the maximum number of threads in a variable.  */
42 const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX;
43
44 /* Indicate whether at least one thread has a user-defined stack (if 1),
45    or if all threads have stacks supplied by LinuxThreads (if 0). */
46 int __pthread_nonstandard_stacks;
47
48 /* Number of active entries in __pthread_handles (used by gdb) */
49 volatile int __pthread_handles_num = 2;
50
51 /* Whether to use debugger additional actions for thread creation
52    (set to 1 by gdb) */
53 volatile int __pthread_threads_debug;
54
55 /* Globally enabled events.  */
56 volatile td_thr_events_t __pthread_threads_events;
57
58 /* Mapping from stack segment to thread descriptor. */
59 /* Stack segment numbers are also indices into the __pthread_handles array. */
60 /* Stack segment number 0 is reserved for the initial thread. */
61
62 static inline pthread_descr thread_segment(int seg)
63 {
64   return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE)
65          - 1;
66 }
67
68 /* Flag set in signal handler to record child termination */
69
70 static volatile int terminated_children = 0;
71
72 /* Flag set when the initial thread is blocked on pthread_exit waiting
73    for all other threads to terminate */
74
75 static int main_thread_exiting = 0;
76
77 /* Counter used to generate unique thread identifier.
78    Thread identifier is pthread_threads_counter + segment. */
79
80 static pthread_t pthread_threads_counter = 0;
81
82 /* Forward declarations */
83
84 static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
85                                  void * (*start_routine)(void *), void *arg,
86                                  sigset_t *mask, int father_pid,
87                                  int report_events,
88                                  td_thr_events_t *event_maskp);
89 static void pthread_handle_free(pthread_t th_id);
90 static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode);
91 static void pthread_reap_children(void);
92 static void pthread_kill_all_threads(int sig, int main_thread_also);
93
94 /* The server thread managing requests for thread creation and termination */
95
96 int __pthread_manager(void *arg)
97 {
98   int reqfd = (int)arg;
99   struct pollfd ufd;
100   sigset_t mask;
101   int n;
102   struct pthread_request request;
103
104   /* If we have special thread_self processing, initialize it.  */
105 #ifdef INIT_THREAD_SELF
106   INIT_THREAD_SELF(&__pthread_manager_thread, 1);
107 #endif
108   /* Set the error variable.  */
109   __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno;
110   __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno;
111   /* Block all signals except __pthread_sig_cancel and SIGTRAP */
112   sigfillset(&mask);
113   sigdelset(&mask, __pthread_sig_cancel); /* for thread termination */
114   sigdelset(&mask, SIGTRAP);            /* for debugging purposes */
115   sigprocmask(SIG_SETMASK, &mask, NULL);
116   /* Raise our priority to match that of main thread */
117   __pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
118   /* Synchronize debugging of the thread manager */
119   n = __libc_read(reqfd, (char *)&request, sizeof(request));
120   ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG);
121   ufd.fd = reqfd;
122   ufd.events = POLLIN;
123   /* Enter server loop */
124   while(1) {
125     n = __poll(&ufd, 1, 2000);
126
127     /* Check for termination of the main thread */
128     if (getppid() == 1) {
129       pthread_kill_all_threads(SIGKILL, 0);
130       _exit(0);
131     }
132     /* Check for dead children */
133     if (terminated_children) {
134       terminated_children = 0;
135       pthread_reap_children();
136     }
137     /* Read and execute request */
138     if (n == 1 && (ufd.revents & POLLIN)) {
139       n = __libc_read(reqfd, (char *)&request, sizeof(request));
140       ASSERT(n == sizeof(request));
141       switch(request.req_kind) {
142       case REQ_CREATE:
143         request.req_thread->p_retcode =
144           pthread_handle_create((pthread_t *) &request.req_thread->p_retval,
145                                 request.req_args.create.attr,
146                                 request.req_args.create.fn,
147                                 request.req_args.create.arg,
148                                 &request.req_args.create.mask,
149                                 request.req_thread->p_pid,
150                                 request.req_thread->p_report_events,
151                                 &request.req_thread->p_eventbuf.eventmask);
152         restart(request.req_thread);
153         break;
154       case REQ_FREE:
155         pthread_handle_free(request.req_args.free.thread_id);
156         break;
157       case REQ_PROCESS_EXIT:
158         pthread_handle_exit(request.req_thread,
159                             request.req_args.exit.code);
160         break;
161       case REQ_MAIN_THREAD_EXIT:
162         main_thread_exiting = 1;
163         if (__pthread_main_thread->p_nextlive == __pthread_main_thread) {
164           restart(__pthread_main_thread);
165           return 0;
166         }
167         break;
168       case REQ_POST:
169         __new_sem_post(request.req_args.post);
170         break;
171       case REQ_DEBUG:
172         /* Make gdb aware of new thread and gdb will restart the
173            new thread when it is ready to handle the new thread. */
174         if (__pthread_threads_debug && __pthread_sig_debug > 0)
175           raise(__pthread_sig_debug);
176         break;
177       }
178     }
179   }
180 }
181
182 /* Process creation */
183
184 static int pthread_start_thread(void *arg)
185 {
186   pthread_descr self = (pthread_descr) arg;
187   struct pthread_request request;
188   void * outcome;
189   /* Initialize special thread_self processing, if any.  */
190 #ifdef INIT_THREAD_SELF
191   INIT_THREAD_SELF(self, self->p_nr);
192 #endif
193   /* Make sure our pid field is initialized, just in case we get there
194      before our father has initialized it. */
195   THREAD_SETMEM(self, p_pid, __getpid());
196   /* Initial signal mask is that of the creating thread. (Otherwise,
197      we'd just inherit the mask of the thread manager.) */
198   sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL);
199   /* Set the scheduling policy and priority for the new thread, if needed */
200   if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0)
201     /* Explicit scheduling attributes were provided: apply them */
202     __sched_setscheduler(THREAD_GETMEM(self, p_pid),
203                          THREAD_GETMEM(self, p_start_args.schedpolicy),
204                          &self->p_start_args.schedparam);
205   else if (__pthread_manager_thread.p_priority > 0)
206     /* Default scheduling required, but thread manager runs in realtime
207        scheduling: switch new thread to SCHED_OTHER policy */
208     {
209       struct sched_param default_params;
210       default_params.sched_priority = 0;
211       __sched_setscheduler(THREAD_GETMEM(self, p_pid),
212                            SCHED_OTHER, &default_params);
213     }
214   /* Make gdb aware of new thread */
215   if (__pthread_threads_debug && __pthread_sig_debug > 0) {
216     request.req_thread = self;
217     request.req_kind = REQ_DEBUG;
218     __libc_write(__pthread_manager_request,
219                  (char *) &request, sizeof(request));
220     suspend(self);
221   }
222   /* Run the thread code */
223   outcome = self->p_start_args.start_routine(THREAD_GETMEM(self,
224                                                            p_start_args.arg));
225   /* Exit with the given return value */
226   pthread_exit(outcome);
227   return 0;
228 }
229
230 static int pthread_start_thread_event(void *arg)
231 {
232   pthread_descr self = thread_self ();
233
234   /* Get the lock the manager will free once all is correctly set up.  */
235   __pthread_lock (THREAD_GETMEM(self, p_lock), NULL);
236   /* Free it immediately.  */
237   __pthread_unlock (THREAD_GETMEM(self, p_lock));
238
239   /* Continue with the real function.  */
240   return pthread_start_thread (arg);
241 }
242
243 static int pthread_allocate_stack(const pthread_attr_t *attr,
244                                   pthread_descr default_new_thread,
245                                   int pagesize,
246                                   pthread_descr * out_new_thread,
247                                   char ** out_new_thread_bottom,
248                                   char ** out_guardaddr,
249                                   size_t * out_guardsize)
250 {
251   pthread_descr new_thread;
252   char * new_thread_bottom;
253   char * guardaddr;
254   size_t stacksize, guardsize;
255
256   if (attr != NULL && attr->__stackaddr_set)
257     {
258       /* The user provided a stack. */
259       new_thread =
260         (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1;
261       new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize;
262       guardaddr = NULL;
263       guardsize = 0;
264       __pthread_nonstandard_stacks = 1;
265     }
266   else
267     {
268       /* Allocate space for stack and thread descriptor at default address */
269       new_thread = default_new_thread;
270       new_thread_bottom = (char *) new_thread - STACK_SIZE;
271       if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE),
272                INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
273                MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN,
274                -1, 0) == MAP_FAILED)
275         /* Bad luck, this segment is already mapped. */
276         return -1;
277       /* We manage to get a stack.  Now see whether we need a guard
278          and allocate it if necessary.  Notice that the default
279          attributes (stack_size = STACK_SIZE - pagesize and
280          guardsize = pagesize) do not need a guard page, since
281          the RLIMIT_STACK soft limit prevents stacks from
282          running into one another. */
283       if (attr == NULL ||
284           attr->__guardsize == 0 ||
285           (attr->__guardsize == pagesize &&
286            attr->__stacksize == STACK_SIZE - pagesize))
287         {
288           /* We don't need a guard page. */
289           guardaddr = NULL;
290           guardsize = 0;
291         }
292       else
293         {
294           /* Put a bad page at the bottom of the stack */
295           stacksize = roundup(attr->__stacksize, pagesize);
296           if (stacksize >= STACK_SIZE - pagesize)
297             stacksize = STACK_SIZE - pagesize;
298           guardaddr = (void *)new_thread - stacksize;
299           guardsize = attr->__guardsize;
300           if (mmap ((caddr_t) guardaddr, guardsize, 0, MAP_FIXED, -1, 0)
301               == MAP_FAILED)
302             {
303               /* We don't make this an error.  */
304               guardaddr = NULL;
305               guardsize = 0;
306             }
307         }
308     }
309   /* Clear the thread data structure.  */
310   memset (new_thread, '\0', sizeof (*new_thread));
311   *out_new_thread = new_thread;
312   *out_new_thread_bottom = new_thread_bottom;
313   *out_guardaddr = guardaddr;
314   *out_guardsize = guardsize;
315   return 0;
316 }
317
318 static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
319                                  void * (*start_routine)(void *), void *arg,
320                                  sigset_t * mask, int father_pid,
321                                  int report_events,
322                                  td_thr_events_t *event_maskp)
323 {
324   size_t sseg;
325   int pid;
326   pthread_descr new_thread;
327   char * new_thread_bottom;
328   pthread_t new_thread_id;
329   char *guardaddr = NULL;
330   size_t guardsize = 0;
331   int pagesize = __getpagesize();
332
333   /* First check whether we have to change the policy and if yes, whether
334      we can  do this.  Normally this should be done by examining the
335      return value of the __sched_setscheduler call in pthread_start_thread
336      but this is hard to implement.  FIXME  */
337   if (attr != NULL && attr->__schedpolicy != SCHED_OTHER && geteuid () != 0)
338     return EPERM;
339   /* Find a free segment for the thread, and allocate a stack if needed */
340   for (sseg = 2; ; sseg++)
341     {
342       if (sseg >= PTHREAD_THREADS_MAX)
343         return EAGAIN;
344       if (__pthread_handles[sseg].h_descr != NULL)
345         continue;
346       if (pthread_allocate_stack(attr, thread_segment(sseg), pagesize,
347                                  &new_thread, &new_thread_bottom,
348                                  &guardaddr, &guardsize) == 0)
349         break;
350     }
351   __pthread_handles_num++;
352   /* Allocate new thread identifier */
353   pthread_threads_counter += PTHREAD_THREADS_MAX;
354   new_thread_id = sseg + pthread_threads_counter;
355   /* Initialize the thread descriptor.  Elements which have to be
356      initialized to zero already have this value.  */
357   new_thread->p_tid = new_thread_id;
358   new_thread->p_lock = &(__pthread_handles[sseg].h_lock);
359   new_thread->p_cancelstate = PTHREAD_CANCEL_ENABLE;
360   new_thread->p_canceltype = PTHREAD_CANCEL_DEFERRED;
361   new_thread->p_errnop = &new_thread->p_errno;
362   new_thread->p_h_errnop = &new_thread->p_h_errno;
363   new_thread->p_guardaddr = guardaddr;
364   new_thread->p_guardsize = guardsize;
365   new_thread->p_self = new_thread;
366   new_thread->p_nr = sseg;
367   /* Initialize the thread handle */
368   __pthread_init_lock(&__pthread_handles[sseg].h_lock);
369   __pthread_handles[sseg].h_descr = new_thread;
370   __pthread_handles[sseg].h_bottom = new_thread_bottom;
371   /* Determine scheduling parameters for the thread */
372   new_thread->p_start_args.schedpolicy = -1;
373   if (attr != NULL) {
374     new_thread->p_detached = attr->__detachstate;
375     new_thread->p_userstack = attr->__stackaddr_set;
376
377     switch(attr->__inheritsched) {
378     case PTHREAD_EXPLICIT_SCHED:
379       new_thread->p_start_args.schedpolicy = attr->__schedpolicy;
380       memcpy (&new_thread->p_start_args.schedparam, &attr->__schedparam,
381               sizeof (struct sched_param));
382       break;
383     case PTHREAD_INHERIT_SCHED:
384       new_thread->p_start_args.schedpolicy = __sched_getscheduler(father_pid);
385       __sched_getparam(father_pid, &new_thread->p_start_args.schedparam);
386       break;
387     }
388     new_thread->p_priority =
389       new_thread->p_start_args.schedparam.sched_priority;
390   }
391   /* Finish setting up arguments to pthread_start_thread */
392   new_thread->p_start_args.start_routine = start_routine;
393   new_thread->p_start_args.arg = arg;
394   new_thread->p_start_args.mask = *mask;
395   /* Raise priority of thread manager if needed */
396   __pthread_manager_adjust_prio(new_thread->p_priority);
397   /* Do the cloning.  We have to use two different functions depending
398      on whether we are debugging or not.  */
399   pid = 0;      /* Note that the thread never can have PID zero.  */
400   if (report_events)
401     {
402       /* See whether the TD_CREATE event bit is set in any of the
403          masks.  */
404       int idx = __td_eventword (TD_CREATE);
405       uint32_t mask = __td_eventmask (TD_CREATE);
406
407       if ((mask & (__pthread_threads_events.event_bits[idx]
408                    | event_maskp->event_bits[idx])) != 0)
409         {
410           /* Lock the mutex the child will use now so that it will stop.  */
411           __pthread_lock(new_thread->p_lock, NULL);
412
413           /* We have to report this event.  */
414           pid = __clone(pthread_start_thread_event, (void **) new_thread,
415                         CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
416                         __pthread_sig_cancel, new_thread);
417           if (pid != -1)
418             {
419               /* Now fill in the information about the new thread in
420                  the newly created thread's data structure.  We cannot let
421                  the new thread do this since we don't know whether it was
422                  already scheduled when we send the event.  */
423               new_thread->p_eventbuf.eventdata = new_thread;
424               new_thread->p_eventbuf.eventnum = TD_CREATE;
425
426               /* Now call the function which signals the event.  */
427               __linuxthreads_create_event ();
428
429               /* Now restart the thread.  */
430               __pthread_unlock(new_thread->p_lock);
431             }
432         }
433     }
434   if (pid == 0)
435     pid = __clone(pthread_start_thread, (void **) new_thread,
436                   CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
437                   __pthread_sig_cancel, new_thread);
438   /* Check if cloning succeeded */
439   if (pid == -1) {
440     /* Free the stack if we allocated it */
441     if (attr == NULL || !attr->__stackaddr_set)
442       {
443         if (new_thread->p_guardsize != 0)
444           munmap(new_thread->p_guardaddr, new_thread->p_guardsize);
445         munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
446                INITIAL_STACK_SIZE);
447       }
448     __pthread_handles[sseg].h_descr = NULL;
449     __pthread_handles[sseg].h_bottom = NULL;
450     __pthread_handles_num--;
451     return errno;
452   }
453   /* Insert new thread in doubly linked list of active threads */
454   new_thread->p_prevlive = __pthread_main_thread;
455   new_thread->p_nextlive = __pthread_main_thread->p_nextlive;
456   __pthread_main_thread->p_nextlive->p_prevlive = new_thread;
457   __pthread_main_thread->p_nextlive = new_thread;
458   /* Set pid field of the new thread, in case we get there before the
459      child starts. */
460   new_thread->p_pid = pid;
461   /* We're all set */
462   *thread = new_thread_id;
463   return 0;
464 }
465
466
467 /* Try to free the resources of a thread when requested by pthread_join
468    or pthread_detach on a terminated thread. */
469
470 static void pthread_free(pthread_descr th)
471 {
472   pthread_handle handle;
473   ASSERT(th->p_exited);
474   /* Make the handle invalid */
475   handle =  thread_handle(th->p_tid);
476   __pthread_lock(&handle->h_lock, NULL);
477   handle->h_descr = NULL;
478   handle->h_bottom = (char *)(-1L);
479   __pthread_unlock(&handle->h_lock);
480 #ifdef FREE_THREAD_SELF
481   FREE_THREAD_SELF(th, th->p_nr);
482 #endif
483   /* One fewer threads in __pthread_handles */
484   __pthread_handles_num--;
485   /* If initial thread, nothing to free */
486   if (th == &__pthread_initial_thread) return;
487   if (!th->p_userstack)
488     {
489       /* Free the stack and thread descriptor area */
490       if (th->p_guardsize != 0)
491         munmap(th->p_guardaddr, th->p_guardsize);
492       munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE);
493     }
494 }
495
496 /* Handle threads that have exited */
497
498 static void pthread_exited(pid_t pid)
499 {
500   pthread_descr th;
501   int detached;
502   /* Find thread with that pid */
503   for (th = __pthread_main_thread->p_nextlive;
504        th != __pthread_main_thread;
505        th = th->p_nextlive) {
506     if (th->p_pid == pid) {
507       /* Remove thread from list of active threads */
508       th->p_nextlive->p_prevlive = th->p_prevlive;
509       th->p_prevlive->p_nextlive = th->p_nextlive;
510       /* Mark thread as exited, and if detached, free its resources */
511       __pthread_lock(th->p_lock, NULL);
512       th->p_exited = 1;
513       /* If we have to signal this event do it now.  */
514       if (th->p_report_events)
515         {
516           /* See whether TD_DEATH is in any of the mask.  */
517           int idx = __td_eventword (TD_REAP);
518           uint32_t mask = __td_eventmask (TD_REAP);
519
520           if ((mask & (__pthread_threads_events.event_bits[idx]
521                        | th->p_eventbuf.eventmask.event_bits[idx])) != 0)
522             {
523               /* Yep, we have to signal the death.  */
524               th->p_eventbuf.eventnum = TD_DEATH;
525               th->p_eventbuf.eventdata = th;
526
527               /* Now call the function to signal the event.  */
528               __linuxthreads_reap_event();
529             }
530         }
531       detached = th->p_detached;
532       __pthread_unlock(th->p_lock);
533       if (detached)
534         pthread_free(th);
535       break;
536     }
537   }
538   /* If all threads have exited and the main thread is pending on a
539      pthread_exit, wake up the main thread and terminate ourselves. */
540   if (main_thread_exiting &&
541       __pthread_main_thread->p_nextlive == __pthread_main_thread) {
542     restart(__pthread_main_thread);
543     _exit(0);
544   }
545 }
546
547 static void pthread_reap_children(void)
548 {
549   pid_t pid;
550   int status;
551
552   while ((pid = __libc_waitpid(-1, &status, WNOHANG | __WCLONE)) > 0) {
553     pthread_exited(pid);
554     if (WIFSIGNALED(status)) {
555       /* If a thread died due to a signal, send the same signal to
556          all other threads, including the main thread. */
557       pthread_kill_all_threads(WTERMSIG(status), 1);
558       _exit(0);
559     }
560   }
561 }
562
563 /* Try to free the resources of a thread when requested by pthread_join
564    or pthread_detach on a terminated thread. */
565
566 static void pthread_handle_free(pthread_t th_id)
567 {
568   pthread_handle handle = thread_handle(th_id);
569   pthread_descr th;
570
571   __pthread_lock(&handle->h_lock, NULL);
572   if (invalid_handle(handle, th_id)) {
573     /* pthread_reap_children has deallocated the thread already,
574        nothing needs to be done */
575     __pthread_unlock(&handle->h_lock);
576     return;
577   }
578   th = handle->h_descr;
579   if (th->p_exited) {
580     __pthread_unlock(&handle->h_lock);
581     pthread_free(th);
582   } else {
583     /* The Unix process of the thread is still running.
584        Mark the thread as detached so that the thread manager will
585        deallocate its resources when the Unix process exits. */
586     th->p_detached = 1;
587     __pthread_unlock(&handle->h_lock);
588   }
589 }
590
591 /* Send a signal to all running threads */
592
593 static void pthread_kill_all_threads(int sig, int main_thread_also)
594 {
595   pthread_descr th;
596   for (th = __pthread_main_thread->p_nextlive;
597        th != __pthread_main_thread;
598        th = th->p_nextlive) {
599     kill(th->p_pid, sig);
600   }
601   if (main_thread_also) {
602     kill(__pthread_main_thread->p_pid, sig);
603   }
604 }
605
606 /* Process-wide exit() */
607
608 static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
609 {
610   pthread_descr th;
611   __pthread_exit_requested = 1;
612   __pthread_exit_code = exitcode;
613   /* Send the CANCEL signal to all running threads, including the main
614      thread, but excluding the thread from which the exit request originated
615      (that thread must complete the exit, e.g. calling atexit functions
616      and flushing stdio buffers). */
617   for (th = issuing_thread->p_nextlive;
618        th != issuing_thread;
619        th = th->p_nextlive) {
620     kill(th->p_pid, __pthread_sig_cancel);
621   }
622   /* Now, wait for all these threads, so that they don't become zombies
623      and their times are properly added to the thread manager's times. */
624   for (th = issuing_thread->p_nextlive;
625        th != issuing_thread;
626        th = th->p_nextlive) {
627     waitpid(th->p_pid, NULL, __WCLONE);
628   }
629   restart(issuing_thread);
630   _exit(0);
631 }
632
633 /* Handler for __pthread_sig_cancel in thread manager thread */
634
635 void __pthread_manager_sighandler(int sig)
636 {
637   terminated_children = 1;
638 }
639
640 /* Adjust priority of thread manager so that it always run at a priority
641    higher than all threads */
642
643 void __pthread_manager_adjust_prio(int thread_prio)
644 {
645   struct sched_param param;
646
647   if (thread_prio <= __pthread_manager_thread.p_priority) return;
648   param.sched_priority =
649     thread_prio < __sched_get_priority_max(SCHED_FIFO)
650     ? thread_prio + 1 : thread_prio;
651   __sched_setscheduler(__pthread_manager_thread.p_pid, SCHED_FIFO, &param);
652   __pthread_manager_thread.p_priority = thread_prio;
653 }