Bladeren bron

A patch from Arne Jonsson <arne.jonsson@i3micro.com> to allow
uClibc's libpthread to run on linux 2.0.x kernels which lack
poll() and therefore must use select() instead.

Eric Andersen 21 jaren geleden
bovenliggende
commit
71d9d16063
1 gewijzigde bestanden met toevoegingen van 66 en 2 verwijderingen
  1. 66 2
      libpthread/linuxthreads/manager.c

+ 66 - 2
libpthread/linuxthreads/manager.c

@@ -38,6 +38,16 @@
 #include "semaphore.h"
 #include "debug.h" /* PDEBUG, added by StS */
 
+
+/* poll() is not supported in kernel <= 2.0, therefore is __NR_poll is
+ * not available, we assume an old Linux kernel is in use and we will
+ * use select() instead. */
+#include <sys/syscall.h>
+#ifndef __NR_poll
+# define USE_SELECT
+#endif
+
+
 /* Array of active threads. Entry 0 is reserved for the initial thread. */
 struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
 { { LOCK_INITIALIZER, &__pthread_initial_thread, 0},
@@ -104,7 +114,12 @@ static void pthread_kill_all_threads(int sig, int main_thread_also);
 int __pthread_manager(void *arg)
 {
   int reqfd = (int) (long int) arg;
+#ifdef USE_SELECT
+  struct timeval tv;
+  fd_set fd;
+#else
   struct pollfd ufd;
+#endif
   sigset_t mask;
   int n;
   struct pthread_request request;
@@ -126,14 +141,23 @@ 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);
+#ifndef USE_SELECT
   ufd.fd = reqfd;
   ufd.events = POLLIN;
+#endif
   /* Enter server loop */
   while(1) {
+#ifdef USE_SELECT
+    tv.tv_sec = 2;
+    tv.tv_usec = 0;
+    FD_ZERO (&fd);
+    FD_SET (reqfd, &fd);
+    n = select (reqfd + 1, &fd, NULL, NULL, &tv);
+#else
 PDEBUG("before poll\n");
     n = poll(&ufd, 1, 2000);
 PDEBUG("after poll\n");
-
+#endif
     /* Check for termination of the main thread */
     if (getppid() == 1) {
       pthread_kill_all_threads(SIGKILL, 0);
@@ -145,7 +169,13 @@ PDEBUG("after poll\n");
       pthread_reap_children();
     }
     /* Read and execute request */
-    if (n == 1 && (ufd.revents & POLLIN)) {
+#ifdef USE_SELECT
+    if (n == 1)
+#else
+    if (n == 1 && (ufd.revents & POLLIN))
+#endif
+    {
+
 PDEBUG("before __libc_read\n");
       n = __libc_read(reqfd, (char *)&request, sizeof(request));
 PDEBUG("after __libc_read, n=%d\n", n);
@@ -488,6 +518,18 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   /* Do the cloning.  We have to use two different functions depending
      on whether we are debugging or not.  */
   pid = 0;     /* Note that the thread never can have PID zero.  */
+
+
+  /* ******************************************************** */
+  /*  This code was moved from below to cope with running threads
+   *  on uClinux systems.  See comment below...
+   * 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;
+  /* ********************************************************* */
+
   if (report_events)
     {
       /* See whether the TD_CREATE event bit is set in any of the
@@ -535,6 +577,14 @@ PDEBUG("cloning new_thread = %p\n", new_thread);
 		  __pthread_sig_cancel, new_thread);
   /* Check if cloning succeeded */
   if (pid == -1) {
+    /******************************************************** 
+     * Code inserted to remove the thread from our list of active
+     * threads in case of failure (needed to cope with uClinux), 
+     * See comment below. */
+    new_thread->p_nextlive->p_prevlive = new_thread->p_prevlive;
+    new_thread->p_prevlive->p_nextlive = new_thread->p_nextlive;
+    /********************************************************/
+
     /* Free the stack if we allocated it */
     if (attr == NULL || !attr->__stackaddr_set)
       {
@@ -553,11 +603,25 @@ PDEBUG("cloning new_thread = %p\n", new_thread);
     return errno;
   }
 PDEBUG("new thread pid = %d\n", pid);
+
+#if 0
+  /* ***********************************************************
+   This code has been moved before the call to clone().  In uClinux,
+   the use of wait on a semaphore is dependant upon that the child so
+   the child must be in the active threads list. This list is used in
+   pthread_find_self() to get the pthread_descr of self. So, if the
+   child calls sem_wait before this code is executed , it will hang
+   forever and initial_thread will instead be posted by a sem_post
+   call. */
+
   /* 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;
+  /************************************************************/
+#endif
+
   /* Set pid field of the new thread, in case we get there before the
      child starts. */
   new_thread->p_pid = pid;