فهرست منبع

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 سال پیش
والد
کامیت
71d9d16063
1فایلهای تغییر یافته به همراه66 افزوده شده و 2 حذف شده
  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;