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.c56
1 files changed, 44 insertions, 12 deletions
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c
index 36c592197e..39c103cdc4 100644
--- a/linuxthreads/manager.c
+++ b/linuxthreads/manager.c
@@ -21,7 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <sys/select.h>		/* for select */
+#include <sys/poll.h>		/* for poll */
 #include <sys/mman.h>           /* for mmap */
 #include <sys/time.h>
 #include <sys/wait.h>           /* for waitpid macros */
@@ -37,6 +37,12 @@
 struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
 { { LOCK_INITIALIZER, &__pthread_initial_thread, 0}, /* All NULLs */ };
 
+/* This is a list of terminated, but not detached threads.  This can happen
+   when pthread_join() is called and the pthread_reap_children() function
+   removes the thread from the live list before processing the FREE_REQ
+   request.  */
+static pthread_descr non_detached;
+
 /* Indicate whether at least one thread has a user-defined stack (if 1),
    or if all threads have stacks supplied by LinuxThreads (if 0). */
 int __pthread_nonstandard_stacks = 0;
@@ -87,9 +93,8 @@ static void pthread_kill_all_threads(int sig, int main_thread_also);
 int __pthread_manager(void *arg)
 {
   int reqfd = (int)arg;
+  struct pollfd ufd;
   sigset_t mask;
-  fd_set readfds;
-  struct timeval timeout;
   int n;
   struct pthread_request request;
 
@@ -112,13 +117,11 @@ int __pthread_manager(void *arg)
   /* Synchronize debugging of the thread manager */
   n = __libc_read(reqfd, (char *)&request, sizeof(request));
   ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG);
+  ufd.fd = reqfd;
+  ufd.events = POLLIN;
   /* Enter server loop */
   while(1) {
-    FD_ZERO(&readfds);
-    FD_SET(reqfd, &readfds);
-    timeout.tv_sec = 2;
-    timeout.tv_usec = 0;
-    n = __select(reqfd + 1, &readfds, NULL, NULL, &timeout);
+    n = __poll(&ufd, 1, 2000);
 
     /* Check for termination of the main thread */
     if (getppid() == 1) {
@@ -131,7 +134,7 @@ int __pthread_manager(void *arg)
       pthread_reap_children();
     }
     /* Read and execute request */
-    if (n == 1 && FD_ISSET(reqfd, &readfds)) {
+    if (n == 1 && (ufd.revents & POLLIN)) {
       n = __libc_read(reqfd, (char *)&request, sizeof(request));
       ASSERT(n == sizeof(request));
       switch(request.req_kind) {
@@ -401,7 +404,16 @@ static void pthread_exited(pid_t pid)
       th->p_exited = 1;
       detached = th->p_detached;
       __pthread_unlock(th->p_lock);
-      if (detached) pthread_free(th);
+      if (detached)
+	pthread_free(th);
+      else {
+	/* Enqueue in the detached list.  */
+	th->p_nextlive = non_detached;
+	if (non_detached != NULL)
+	  non_detached->p_prevlive = th;
+	th->p_prevlive = NULL;
+	non_detached = th;
+      }
       break;
     }
   }
@@ -436,7 +448,6 @@ static void pthread_reap_children(void)
 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;
@@ -444,8 +455,29 @@ static void pthread_handle_free(pthread_descr th)
     if (t == th) break;
     t = t->p_nextlive;
   } while (t != __pthread_main_thread);
-  if (t != th) return;
+  if (t != th) {
+    /* Hum, it might be that the thread already was dequeued but
+       wasn't detached.  In the case the thread is already detached
+       and we cannot find it this is a user bug but we must be
+       gracious.  */
+    t = non_detached;
+    while (t != NULL) {
+      if (t == th) break;
+      t = t->p_nextlive;
+    }
+    if (t == th) {
+      if (th->p_prevlive == NULL)
+	non_detached = th->p_nextlive;
+      else
+	th->p_prevlive->p_nextlive = th->p_nextlive;
+      if (th->p_nextlive != NULL)
+	th->p_nextlive->p_prevlive = th->p_prevlive;
 
+      /* Finally free it.  */
+      pthread_free (th);
+    }
+    return;
+  }
   __pthread_lock(th->p_lock);
   if (th->p_exited) {
     __pthread_unlock(th->p_lock);