about summary refs log tree commit diff
path: root/linuxthreads/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'linuxthreads/manager.c')
-rw-r--r--linuxthreads/manager.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c
index e7de399cde..c9625327c1 100644
--- a/linuxthreads/manager.c
+++ b/linuxthreads/manager.c
@@ -93,6 +93,8 @@ int __pthread_manager(void *arg)
   sigfillset(&mask);
   sigdelset(&mask, PTHREAD_SIG_RESTART);
   sigprocmask(SIG_SETMASK, &mask, NULL);
+  /* Raise our priority to match that of main thread */
+  __pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
   /* Enter server loop */
   while(1) {
     FD_ZERO(&readfds);
@@ -276,6 +278,8 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   new_thread->p_start_args.start_routine = start_routine;
   new_thread->p_start_args.arg = arg;
   new_thread->p_start_args.mask = *mask;
+  /* Raise priority of thread manager if needed */
+  __pthread_manager_adjust_prio(new_thread->p_priority);
   /* Do the cloning */
   pid = __clone(pthread_start_thread, (void **) new_thread,
                 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
@@ -390,10 +394,22 @@ static void pthread_reap_children(void)
   }
 }
 
-/* Free the resources of a thread */
+/* 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_descr th)
 {
+  pthread_descr t;
+
+  /* Check that the thread th is still there -- pthread_reap_children
+     might have deallocated it already */
+  t = __pthread_main_thread;
+  do {
+    if (t == th) break;
+    t = t->p_nextlive;
+  } while (t != __pthread_main_thread);
+  if (t != th) return;
+
   acquire(th->p_spinlock);
   if (th->p_exited) {
     release(th->p_spinlock);
@@ -455,3 +471,18 @@ void __pthread_manager_sighandler(int sig)
 {
   terminated_children = 1;
 }
+
+/* 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, &param);
+  __pthread_manager_thread.p_priority = thread_prio;
+}