summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2002-10-23 06:49:32 +0000
committerEric Andersen <andersen@codepoet.org>2002-10-23 06:49:32 +0000
commit71d9d16063f03bba67ff448fe4a0459da5e27085 (patch)
treea1d8d692edfa94b8cc14d57a71d6a5fb49021b61
parent27e47143db2f0b85fae8203625895c7e4bf71a75 (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.c68
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;