diff options
author | Eric Andersen <andersen@codepoet.org> | 2002-10-23 06:49:32 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2002-10-23 06:49:32 +0000 |
commit | 71d9d16063f03bba67ff448fe4a0459da5e27085 (patch) | |
tree | a1d8d692edfa94b8cc14d57a71d6a5fb49021b61 | |
parent | 27e47143db2f0b85fae8203625895c7e4bf71a75 (diff) |
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.
-rw-r--r-- | libpthread/linuxthreads/manager.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/libpthread/linuxthreads/manager.c b/libpthread/linuxthreads/manager.c index 5d355e107..78858eb65 100644 --- a/libpthread/linuxthreads/manager.c +++ b/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; |