summaryrefslogtreecommitdiffstats
path: root/lib/libpthread
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread')
-rw-r--r--lib/libpthread/thread/Makefile.inc9
-rw-r--r--lib/libpthread/thread/thr_close.c9
-rw-r--r--lib/libpthread/thread/thr_cond.c133
-rw-r--r--lib/libpthread/thread/thr_create.c149
-rw-r--r--lib/libpthread/thread/thr_detach.c13
-rw-r--r--lib/libpthread/thread/thr_exit.c46
-rw-r--r--lib/libpthread/thread/thr_fcntl.c9
-rw-r--r--lib/libpthread/thread/thr_find_thread.c97
-rw-r--r--lib/libpthread/thread/thr_fork.c14
-rw-r--r--lib/libpthread/thread/thr_fsync.c2
-rw-r--r--lib/libpthread/thread/thr_getprio.c35
-rw-r--r--lib/libpthread/thread/thr_info.c2
-rw-r--r--lib/libpthread/thread/thr_init.c55
-rw-r--r--lib/libpthread/thread/thr_join.c72
-rw-r--r--lib/libpthread/thread/thr_kern.c470
-rw-r--r--lib/libpthread/thread/thr_kill.c35
-rw-r--r--lib/libpthread/thread/thr_mutex.c112
-rw-r--r--lib/libpthread/thread/thr_nanosleep.c5
-rw-r--r--lib/libpthread/thread/thr_open.c10
-rw-r--r--lib/libpthread/thread/thr_private.h83
-rw-r--r--lib/libpthread/thread/thr_read.c7
-rw-r--r--lib/libpthread/thread/thr_readv.c7
-rw-r--r--lib/libpthread/thread/thr_resume_np.c34
-rw-r--r--lib/libpthread/thread/thr_select.c9
-rw-r--r--lib/libpthread/thread/thr_seterrno.c5
-rw-r--r--lib/libpthread/thread/thr_setprio.c40
-rw-r--r--lib/libpthread/thread/thr_sig.c299
-rw-r--r--lib/libpthread/thread/thr_sigaction.c52
-rw-r--r--lib/libpthread/thread/thr_sigmask.c13
-rw-r--r--lib/libpthread/thread/thr_sigprocmask.c12
-rw-r--r--lib/libpthread/thread/thr_sigsuspend.c3
-rw-r--r--lib/libpthread/thread/thr_sigwait.c9
-rw-r--r--lib/libpthread/thread/thr_spec.c110
-rw-r--r--lib/libpthread/thread/thr_spinlock.c65
-rw-r--r--lib/libpthread/thread/thr_suspend_np.c38
-rw-r--r--lib/libpthread/thread/thr_wait4.c12
-rw-r--r--lib/libpthread/thread/thr_write.c7
-rw-r--r--lib/libpthread/thread/thr_writev.c7
38 files changed, 865 insertions, 1224 deletions
diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc
index 4f1b308..924453f 100644
--- a/lib/libpthread/thread/Makefile.inc
+++ b/lib/libpthread/thread/Makefile.inc
@@ -1,4 +1,4 @@
-# $Id: Makefile.inc,v 1.9 1997/05/06 00:49:36 jdp Exp $
+# $Id: Makefile.inc,v 1.10 1997/11/24 23:04:29 alex Exp $
# uthread sources
.PATH: ${.CURDIR}/uthread
@@ -34,6 +34,7 @@ SRCS+= \
uthread_fcntl.c \
uthread_fd.c \
uthread_file.c \
+ uthread_find_thread.c \
uthread_flock.c \
uthread_fork.c \
uthread_fstat.c \
@@ -51,7 +52,6 @@ SRCS+= \
uthread_kern.c \
uthread_kill.c \
uthread_listen.c \
- uthread_longjmp.c \
uthread_mattr_init.c \
uthread_mattr_kind_np.c \
uthread_multi_np.c \
@@ -70,23 +70,22 @@ SRCS+= \
uthread_self.c \
uthread_sendto.c \
uthread_seterrno.c \
- uthread_setjmp.c \
uthread_setprio.c \
uthread_setsockopt.c \
uthread_shutdown.c \
uthread_sig.c \
uthread_sigaction.c \
uthread_sigblock.c \
- uthread_single_np.c \
uthread_sigmask.c \
- uthread_signal.c \
uthread_sigprocmask.c \
uthread_sigsetmask.c \
uthread_sigsuspend.c \
uthread_sigwait.c \
+ uthread_single_np.c \
uthread_socket.c \
uthread_socketpair.c \
uthread_spec.c \
+ uthread_spinlock.c \
uthread_suspend_np.c \
uthread_wait4.c \
uthread_write.c \
diff --git a/lib/libpthread/thread/thr_close.c b/lib/libpthread/thread/thr_close.c
index 26a8fbf..5678e2e 100644
--- a/lib/libpthread/thread/thr_close.c
+++ b/lib/libpthread/thread/thr_close.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,9 +48,6 @@ close(int fd)
/* Lock the file descriptor while the file is closed: */
if ((ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) == 0) {
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
/* Get file descriptor status. */
fstat(fd, &sb);
@@ -84,12 +81,8 @@ close(int fd)
/* Close the file descriptor: */
ret = _thread_sys_close(fd);
- /* Free the file descriptor table entry: */
free(_thread_fd_table[fd]);
_thread_fd_table[fd] = NULL;
-
- /* Unblock signals again: */
- _thread_kern_sig_unblock(status);
}
return (ret);
}
diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c
index e7fcc62..cb08853 100644
--- a/lib/libpthread/thread/thr_cond.c
+++ b/lib/libpthread/thread/thr_cond.c
@@ -43,9 +43,9 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
pthread_cond_t pcond;
int rval = 0;
- if (cond == NULL) {
+ if (cond == NULL)
rval = EINVAL;
- } else {
+ else {
/*
* Check if a pointer to a condition variable attribute
* structure was passed by the caller:
@@ -85,6 +85,7 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
_thread_queue_init(&pcond->c_queue);
pcond->c_flags |= COND_FLAGS_INITED;
pcond->c_type = type;
+ pcond->access_lock = 0;
*cond = pcond;
}
}
@@ -98,31 +99,23 @@ pthread_cond_destroy(pthread_cond_t * cond)
{
int rval = 0;
- if (cond == NULL || *cond == NULL) {
+ if (cond == NULL || *cond == NULL)
rval = EINVAL;
- } else {
- /* Process according to condition variable type: */
- switch ((*cond)->c_type) {
- /* Fast condition variable: */
- case COND_TYPE_FAST:
- /* Nothing to do here. */
- break;
+ else {
+ /* Lock the condition variable structure: */
+ _spinlock(&(*cond)->access_lock);
- /* Trap invalid condition variable types: */
- default:
- /* Return an invalid argument error: */
- rval = EINVAL;
- break;
- }
+ /*
+ * Free the memory allocated for the condition
+ * variable structure:
+ */
+ free(*cond);
- /* Check for errors: */
- if (rval == 0) {
- /* Destroy the contents of the condition structure: */
- _thread_queue_init(&(*cond)->c_queue);
- (*cond)->c_flags = 0;
- free(*cond);
- *cond = NULL;
- }
+ /*
+ * NULL the caller's pointer now that the condition
+ * variable has been destroyed:
+ */
+ *cond = NULL;
}
/* Return the completion status: */
return (rval);
@@ -143,8 +136,8 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
*/
else if (*cond != NULL ||
(rval = pthread_cond_init(cond,NULL)) == 0) {
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ /* Lock the condition variable structure: */
+ _spinlock(&(*cond)->access_lock);
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
@@ -162,12 +155,15 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
/* Wait forever: */
_thread_run->wakeup_time.tv_sec = -1;
+ /* Unlock the condition variable structure: */
+ _atomic_unlock(&(*cond)->access_lock);
+
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT,
__FILE__, __LINE__);
- /* Block signals: */
- _thread_kern_sig_block(NULL);
+ /* Lock the condition variable structure: */
+ _spinlock(&(*cond)->access_lock);
/* Lock the mutex: */
rval = pthread_mutex_lock(mutex);
@@ -180,8 +176,8 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
break;
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ /* Unlock the condition variable structure: */
+ _atomic_unlock(&(*cond)->access_lock);
}
/* Return the completion status: */
@@ -204,8 +200,8 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
*/
else if (*cond != NULL ||
(rval = pthread_cond_init(cond,NULL)) == 0) {
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ /* Lock the condition variable structure: */
+ _spinlock(&(*cond)->access_lock);
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
@@ -233,12 +229,15 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
*/
_thread_queue_deq(&(*cond)->c_queue);
} else {
+ /* Unlock the condition variable structure: */
+ _atomic_unlock(&(*cond)->access_lock);
+
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT,
__FILE__, __LINE__);
- /* Block signals: */
- _thread_kern_sig_block(NULL);
+ /* Lock the condition variable structure: */
+ _spinlock(&(*cond)->access_lock);
/* Lock the mutex: */
if ((rval = pthread_mutex_lock(mutex)) != 0) {
@@ -258,8 +257,8 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
break;
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ /* Unlock the condition variable structure: */
+ _atomic_unlock(&(*cond)->access_lock);
}
/* Return the completion status: */
@@ -273,11 +272,11 @@ pthread_cond_signal(pthread_cond_t * cond)
int status;
pthread_t pthread;
- if (cond == NULL || *cond == NULL) {
+ if (cond == NULL || *cond == NULL)
rval = EINVAL;
- } else {
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ else {
+ /* Lock the condition variable structure: */
+ _spinlock(&(*cond)->access_lock);
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
@@ -297,8 +296,8 @@ pthread_cond_signal(pthread_cond_t * cond)
break;
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ /* Unlock the condition variable structure: */
+ _atomic_unlock(&(*cond)->access_lock);
}
/* Return the completion status: */
@@ -312,34 +311,38 @@ pthread_cond_broadcast(pthread_cond_t * cond)
int status;
pthread_t pthread;
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ if (cond == NULL || *cond == NULL)
+ rval = EINVAL;
+ else {
+ /* Lock the condition variable structure: */
+ _spinlock(&(*cond)->access_lock);
- /* Process according to condition variable type: */
- switch ((*cond)->c_type) {
- /* Fast condition variable: */
- case COND_TYPE_FAST:
- /*
- * Enter a loop to bring all threads off the
- * condition queue:
- */
- while ((pthread =
- _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
- /* Allow the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ /*
+ * Enter a loop to bring all threads off the
+ * condition queue:
+ */
+ while ((pthread =
+ _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
+ /* Allow the thread to run: */
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ }
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ /* Return an invalid argument error: */
+ rval = EINVAL;
+ break;
}
- break;
- /* Trap invalid condition variable types: */
- default:
- /* Return an invalid argument error: */
- rval = EINVAL;
- break;
+ /* Unlock the condition variable structure: */
+ _atomic_unlock(&(*cond)->access_lock);
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
-
/* Return the completion status: */
return (rval);
}
diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c
index c9c6c9f..7603dd3 100644
--- a/lib/libpthread/thread/thr_create.c
+++ b/lib/libpthread/thread/thr_create.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,8 +43,8 @@
#include "libc_private.h"
int
-_thread_create(pthread_t * thread, const pthread_attr_t * attr,
- void *(*start_routine) (void *), void *arg, pthread_t parent)
+pthread_create(pthread_t * thread, const pthread_attr_t * attr,
+ void *(*start_routine) (void *), void *arg)
{
int i;
int ret = 0;
@@ -53,8 +53,11 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
pthread_attr_t pattr;
void *stack;
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ /*
+ * Locking functions in libc are required when there are
+ * threads other than the initial thread.
+ */
+ __isthreaded = 1;
/* Allocate memory for the thread structure: */
if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
@@ -103,71 +106,33 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Initialise the thread for signals: */
new_thread->sigmask = _thread_run->sigmask;
- /*
- * Enter a loop to initialise the signal handler
- * array:
- */
- for (i = 1; i < NSIG; i++) {
- /* Default the signal handler: */
- sigfillset(&new_thread->act[i - 1].sa_mask);
- new_thread->act[i - 1].sa_handler = _thread_run->act[i - 1].sa_handler;
- new_thread->act[i - 1].sa_flags = _thread_run->act[i - 1].sa_flags;
- }
-
/* Initialise the jump buffer: */
- _thread_sys_setjmp(new_thread->saved_jmp_buf);
+ setjmp(new_thread->saved_jmp_buf);
/*
* Set up new stack frame so that it looks like it
* returned from a longjmp() to the beginning of
- * _thread_start(). Check if this is a user thread:
+ * _thread_start().
*/
- if (parent == NULL) {
- /* Use the user start function: */
#if defined(__FreeBSD__)
#if defined(__alpha__)
- new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start;
- new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0;
- new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start;
+ new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start;
+ new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0;
+ new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start;
#else
- new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start;
+ new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start;
#endif
#elif defined(__NetBSD__)
#if defined(__alpha__)
- new_thread->saved_jmp_buf[2] = (long) _thread_start;
- new_thread->saved_jmp_buf[4 + R_RA] = 0;
- new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start;
+ new_thread->saved_jmp_buf[2] = (long) _thread_start;
+ new_thread->saved_jmp_buf[4 + R_RA] = 0;
+ new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start;
#else
- new_thread->saved_jmp_buf[0] = (long) _thread_start;
+ new_thread->saved_jmp_buf[0] = (long) _thread_start;
#endif
#else
#error "Don't recognize this operating system!"
#endif
- } else {
- /*
- * Use the (funny) signal handler start
- * function:
- */
-#if defined(__FreeBSD__)
-#if defined(__alpha__)
- new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start_sig_handler;
- new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0;
- new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start_sig_handler;
-#else
- new_thread->saved_jmp_buf[0]._jb[0] = (int) _thread_start_sig_handler;
-#endif
-#elif defined(__NetBSD__)
-#if defined(__alpha__)
- new_thread->saved_jmp_buf[2] = (long) _thread_start_sig_handler;
- new_thread->saved_jmp_buf[4 + R_RA] = 0;
- new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start_sig_handler;
-#else
- new_thread->saved_jmp_buf[0] = (long) _thread_start_sig_handler;
-#endif
-#else
-#error "Don't recognize this operating system!"
-#endif
- }
/* The stack starts high and builds down: */
#if defined(__FreeBSD__)
@@ -215,57 +180,26 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
new_thread->cleanup = NULL;
new_thread->queue = NULL;
new_thread->qnxt = NULL;
- new_thread->parent_thread = parent;
new_thread->flags = 0;
+ /* Lock the thread list: */
+ _lock_thread_list();
+
/* Add the thread to the linked list of all threads: */
new_thread->nxt = _thread_link_list;
_thread_link_list = new_thread;
+ /* Unlock the thread list: */
+ _unlock_thread_list();
+
/* Return a pointer to the thread structure: */
- if(thread)
- (*thread) = new_thread;
+ (*thread) = new_thread;
- /* Check if a parent thread was specified: */
- if (parent != NULL) {
- /*
- * A parent thread was specified, so this is
- * a signal handler thread which must now
- * wait for the signal handler to complete:
- */
- PTHREAD_NEW_STATE(parent,PS_SIGTHREAD);
- } else {
- /* Schedule the new user thread: */
- _thread_kern_sched(NULL);
- }
+ /* Schedule the new user thread: */
+ _thread_kern_sched(NULL);
}
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
-
- /* Return the status: */
- return (ret);
-}
-
-int
-pthread_create(pthread_t * thread, const pthread_attr_t * attr,
- void *(*start_routine) (void *), void *arg)
-{
- int ret = 0;
-
- /*
- * Locking functions in libc are required when there are
- * threads other than the initial thread.
- */
- __isthreaded = 1;
-
- /*
- * Call the low level thread creation function which allows a parent
- * thread to be specified:
- */
- ret = _thread_create(thread, attr, start_routine, arg, NULL);
-
/* Return the status: */
return (ret);
}
@@ -279,33 +213,4 @@ _thread_start(void)
/* This point should never be reached. */
PANIC("Thread has resumed after exit");
}
-
-void
-_thread_start_sig_handler(void)
-{
- int sig;
- long arg;
- void (*sig_routine) (int);
-
- /*
- * Cast the argument from 'void *' to a variable that is NO SMALLER
- * than a pointer (otherwise gcc under NetBSD/Alpha will complain):
- */
- arg = (long) _thread_run->arg;
-
- /* Cast the argument as a signal number: */
- sig = (int) arg;
-
- /* Cast a pointer to the signal handler function: */
- sig_routine = (void (*) (int)) _thread_run->start_routine;
-
- /* Call the signal handler function: */
- (*sig_routine) (sig);
-
- /* Exit the signal handler thread: */
- pthread_exit(&arg);
-
- /* This point should never be reached. */
- PANIC("Signal handler thread has resumed after exit");
-}
#endif
diff --git a/lib/libpthread/thread/thr_detach.c b/lib/libpthread/thread/thr_detach.c
index 57c073a..da456bf 100644
--- a/lib/libpthread/thread/thr_detach.c
+++ b/lib/libpthread/thread/thr_detach.c
@@ -42,14 +42,11 @@ pthread_detach(pthread_t pthread)
int status;
pthread_t next_thread;
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
/* Check for invalid calling parameters: */
- if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) {
+ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC)
/* Return an invalid argument error: */
rval = EINVAL;
- }
+
/* Check if the thread has not been detached: */
else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) {
/* Flag the thread as detached: */
@@ -60,13 +57,9 @@ pthread_detach(pthread_t pthread)
/* Make the thread run: */
PTHREAD_NEW_STATE(next_thread,PS_RUNNING);
}
- } else {
+ } else
/* Return an error: */
rval = EINVAL;
- }
-
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
/* Return the completion status: */
return (rval);
diff --git a/lib/libpthread/thread/thr_exit.c b/lib/libpthread/thread/thr_exit.c
index 15bcfa3..4bc7da9 100644
--- a/lib/libpthread/thread/thr_exit.c
+++ b/lib/libpthread/thread/thr_exit.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -102,9 +102,6 @@ pthread_exit(void *status)
long l;
pthread_t pthread;
- /* Block signals: */
- _thread_kern_sig_block(NULL);
-
/* Save the return value: */
_thread_run->ret = status;
@@ -126,6 +123,9 @@ pthread_exit(void *status)
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
}
+ /* Lock the thread list: */
+ _lock_thread_list();
+
/* Check if the running thread is at the head of the linked list: */
if (_thread_link_list == _thread_run) {
/* There is no previous thread: */
@@ -153,39 +153,12 @@ pthread_exit(void *status)
}
}
- /* Check if this is a signal handler thread: */
- if (_thread_run->parent_thread != NULL) {
- /*
- * Enter a loop to search for other threads with the same
- * parent:
- */
- for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
- /* Compare the parent thread pointers: */
- if (pthread->parent_thread == _thread_run->parent_thread) {
- /*
- * The parent thread is waiting on at least
- * one other signal handler. Exit the loop
- * now that this is known.
- */
- break;
- }
- }
+ /* Unlock the thread list: */
+ _unlock_thread_list();
- /*
- * Check if the parent is not waiting on any other signal
- * handler threads and if it hasn't died in the meantime:
- */
- if (pthread == NULL && _thread_run->parent_thread->state != PS_DEAD) {
- /* Allow the parent thread to run again: */
- PTHREAD_NEW_STATE(_thread_run->parent_thread,PS_RUNNING);
- }
- /* Get the signal number: */
- l = (long) _thread_run->arg;
- sig = (int) l;
+ /* Lock the dead thread list: */
+ _lock_dead_thread_list();
- /* Unblock the signal from the parent thread: */
- sigdelset(&_thread_run->parent_thread->sigmask, sig);
- }
/*
* This thread will never run again. Add it to the list of dead
* threads:
@@ -193,6 +166,9 @@ pthread_exit(void *status)
_thread_run->nxt = _thread_dead;
_thread_dead = _thread_run;
+ /* Unlock the dead thread list: */
+ _unlock_dead_thread_list();
+
/*
* The running thread is no longer in the thread link list so it will
* now die:
diff --git a/lib/libpthread/thread/thr_fcntl.c b/lib/libpthread/thread/thr_fcntl.c
index f83ee50..9a50c1c 100644
--- a/lib/libpthread/thread/thr_fcntl.c
+++ b/lib/libpthread/thread/thr_fcntl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,9 +46,6 @@ fcntl(int fd, int cmd,...)
int status;
va_list ap;
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
/* Lock the file descriptor: */
if ((ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) == 0) {
/* Initialise the variable argument list: */
@@ -56,7 +53,7 @@ fcntl(int fd, int cmd,...)
/* Process according to file control command type: */
switch (cmd) {
- /* Duplicate a file descriptor: */
+ /* Duplicate a file descriptor: */
case F_DUPFD:
/*
* Get the file descriptor that the caller wants to
@@ -107,8 +104,6 @@ fcntl(int fd, int cmd,...)
/* Unlock the file descriptor: */
_thread_fd_unlock(fd, FD_RDWR);
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
/* Return the completion status: */
return (ret);
diff --git a/lib/libpthread/thread/thr_find_thread.c b/lib/libpthread/thread/thr_find_thread.c
new file mode 100644
index 0000000..99e3023
--- /dev/null
+++ b/lib/libpthread/thread/thr_find_thread.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <errno.h>
+#ifdef _THREAD_SAFE
+#include <pthread.h>
+#include "pthread_private.h"
+
+/* Find a thread in the linked list of active threads: */
+int
+_find_thread(pthread_t pthread)
+{
+ pthread_t pthread1;
+
+ /* Check if the caller has specified an invalid thread: */
+ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC)
+ /* Invalid thread: */
+ return(EINVAL);
+
+ /* Lock the thread list: */
+ _lock_thread_list();
+
+ /* Point to the first thread in the list: */
+ pthread1 = _thread_link_list;
+
+ /* Search for the thread to join to: */
+ while (pthread1 != NULL && pthread1 != pthread) {
+ /* Point to the next thread: */
+ pthread1 = pthread1->nxt;
+ }
+
+ /* Unlock the thread list: */
+ _unlock_thread_list();
+
+ /* Return zero if the thread exists: */
+ return ((pthread1 != NULL) ? 0:ESRCH);
+}
+
+/* Find a thread in the linked list of dead threads: */
+int
+_find_dead_thread(pthread_t pthread)
+{
+ pthread_t pthread1;
+
+ /* Check if the caller has specified an invalid thread: */
+ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC)
+ /* Invalid thread: */
+ return(EINVAL);
+
+ /* Lock the dead thread list: */
+ _lock_dead_thread_list();
+
+ /* Point to the first thread in the list: */
+ pthread1 = _thread_dead;
+
+ /* Search for the thread to join to: */
+ while (pthread1 != NULL && pthread1 != pthread) {
+ /* Point to the next thread: */
+ pthread1 = pthread1->nxt;
+ }
+
+ /* Unlock the dead thread list: */
+ _unlock_dead_thread_list();
+
+ /* Return zero if the thread exists: */
+ return ((pthread1 != NULL) ? 0:ESRCH);
+}
+#endif
diff --git a/lib/libpthread/thread/thr_fork.c b/lib/libpthread/thread/thr_fork.c
index 29d6090..25d6703 100644
--- a/lib/libpthread/thread/thr_fork.c
+++ b/lib/libpthread/thread/thr_fork.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,8 +47,8 @@ fork(void)
pthread_t pthread;
pthread_t pthread_next;
- /* Block signals to avoid being interrupted at a bad time: */
- _thread_kern_sig_block(&status);
+ /* Lock the thread list: */
+ _lock_thread_list();
/* Fork a new process: */
if ((ret = _thread_sys_fork()) <= 0) {
@@ -59,12 +59,12 @@ fork(void)
_thread_sys_close(_thread_kern_pipe[1]);
/* Reset signals pending for the running thread: */
- memset(_thread_run->sigpend, 0, sizeof(_thread_run->sigpend));
+ _thread_run->sigpend = 0;
/*
* Create a pipe that is written to by the signal handler to
* prevent signals being missed in calls to
- * _thread_sys_select:
+ * _select:
*/
if (_thread_sys_pipe(_thread_kern_pipe) != 0) {
/* Cannot create pipe, so abort: */
@@ -122,8 +122,8 @@ fork(void)
}
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ /* Unock the thread list: */
+ _unlock_thread_list();
/* Return the process ID: */
return (ret);
diff --git a/lib/libpthread/thread/thr_fsync.c b/lib/libpthread/thread/thr_fsync.c
index 51078e5..5658c73 100644
--- a/lib/libpthread/thread/thr_fsync.c
+++ b/lib/libpthread/thread/thr_fsync.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/lib/libpthread/thread/thr_getprio.c b/lib/libpthread/thread/thr_getprio.c
index 85bd261..708b8f1 100644
--- a/lib/libpthread/thread/thr_getprio.c
+++ b/lib/libpthread/thread/thr_getprio.c
@@ -38,36 +38,19 @@
int
pthread_getprio(pthread_t pthread)
{
- int rval = 0;
- int status;
- pthread_t pthread_p;
+ int ret;
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
- /* Point to the first thread in the list: */
- pthread_p = _thread_link_list;
-
- /* Enter a loop to search for the thread: */
- while (pthread_p != NULL && pthread_p != pthread) {
- /* Point to the next thread: */
- pthread_p = pthread_p->nxt;
- }
-
- /* Check if the thread pointer is NULL: */
- if (pthread == NULL || pthread_p == NULL) {
- /* Return an invalid argument error: */
- errno = EINVAL;
- rval = -1;
- } else {
+ /* Find the thread in the list of active threads: */
+ if ((ret = _find_thread(pthread)) == 0)
/* Get the thread priority: */
- rval = pthread->pthread_priority;
+ ret = pthread->pthread_priority;
+ else {
+ /* Invalid thread: */
+ errno = ret;
+ ret = -1;
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
-
/* Return the thread priority or an error status: */
- return (rval);
+ return (ret);
}
#endif
diff --git a/lib/libpthread/thread/thr_info.c b/lib/libpthread/thread/thr_info.c
index 2909989..c2c3426 100644
--- a/lib/libpthread/thread/thr_info.c
+++ b/lib/libpthread/thread/thr_info.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c
index 78967f4..c267a2c 100644
--- a/lib/libpthread/thread/thr_init.c
+++ b/lib/libpthread/thread/thr_init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,6 @@
#include <machine/reg.h>
#include <pthread.h>
#include "pthread_private.h"
-extern int _thread_autoinit_dummy_decl;
#ifdef GCC_2_8_MADE_THREAD_AWARE
typedef void *** (*dynamic_handler_allocator)();
@@ -80,8 +79,6 @@ _thread_init(void)
int flags;
int i;
struct sigaction act;
- /* Ensure that the auto-initialization routine is linked in: */
- _thread_autoinit_dummy_decl = 1;
/* Check if this function has already been called: */
if (_thread_initial)
@@ -96,7 +93,7 @@ _thread_init(void)
/*
* Create a pipe that is written to by the signal handler to prevent
- * signals being missed in calls to _thread_sys_select:
+ * signals being missed in calls to _select:
*/
if (_thread_sys_pipe(_thread_kern_pipe) != 0) {
/* Cannot create pipe, so abort: */
@@ -144,7 +141,6 @@ _thread_init(void)
_thread_queue_init(&(_thread_initial->join_queue));
/* Initialise the rest of the fields: */
- _thread_initial->parent_thread = NULL;
_thread_initial->specific_data = NULL;
_thread_initial->cleanup = NULL;
_thread_initial->queue = NULL;
@@ -155,49 +151,42 @@ _thread_init(void)
_thread_link_list = _thread_initial;
_thread_run = _thread_initial;
- /* Enter a loop to get the existing signal status: */
- for (i = 1; i < NSIG; i++) {
- /* Check for signals which cannot be trapped: */
- if (i == SIGKILL || i == SIGSTOP) {
- }
- /* Get the signal handler details: */
- else if (_thread_sys_sigaction(i, NULL, &act) != 0) {
- /*
- * Abort this process if signal
- * initialisation fails:
- */
- PANIC("Cannot read signal handler info");
- }
- /* Set the signal handler for the initial thread: */
- else if (sigaction(i, &act, NULL) != 0) {
- /*
- * Abort this process if signal
- * initialisation fails:
- */
- PANIC("Cannot initialise signal handler for initial thread");
- }
- }
-
/* Initialise the global signal action structure: */
sigfillset(&act.sa_mask);
act.sa_handler = (void (*) ()) _thread_sig_handler;
act.sa_flags = SA_RESTART;
- /* Enter a loop to initialise the rest of the signals: */
+ /* Enter a loop to get the existing signal status: */
for (i = 1; i < NSIG; i++) {
/* Check for signals which cannot be trapped: */
if (i == SIGKILL || i == SIGSTOP) {
}
- /* Initialise the signal for default handling: */
- else if (_thread_sys_sigaction(i, &act, NULL) != 0) {
+
+ /* Get the signal handler details: */
+ else if (_thread_sys_sigaction(i, NULL,
+ &_thread_sigact[i - 1]) != 0) {
/*
* Abort this process if signal
* initialisation fails:
*/
- PANIC("Cannot initialise signal handler");
+ PANIC("Cannot read signal handler info");
}
}
+ /*
+ * Install the signal handler for the most important
+ * signals that the user-thread kernel needs. Actually
+ * SIGINFO isn't really needed, but it is nice to have.
+ */
+ if (_thread_sys_sigaction(SIGVTALRM, &act, NULL) != 0 ||
+ _thread_sys_sigaction(SIGINFO , &act, NULL) != 0 ||
+ _thread_sys_sigaction(SIGCHLD , &act, NULL) != 0) {
+ /*
+ * Abort this process if signal initialisation fails:
+ */
+ PANIC("Cannot initialise signal handler");
+ }
+
/* Get the table size: */
if ((_thread_dtablesize = getdtablesize()) < 0) {
/*
diff --git a/lib/libpthread/thread/thr_join.c b/lib/libpthread/thread/thr_join.c
index 9e86a01..83b0c2a 100644
--- a/lib/libpthread/thread/thr_join.c
+++ b/lib/libpthread/thread/thr_join.c
@@ -38,9 +38,8 @@
int
pthread_join(pthread_t pthread, void **thread_return)
{
- int rval = 0;
- int status;
- pthread_t pthread1;
+ int ret = 0;
+ pthread_t pthread1 = NULL;
/* Check if the caller has specified an invalid thread: */
if (pthread == NULL || pthread->magic != PTHREAD_MAGIC)
@@ -52,38 +51,23 @@ pthread_join(pthread_t pthread, void **thread_return)
/* Avoid a deadlock condition: */
return(EDEADLK);
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ /*
+ * Find the thread in the list of active threads or in the
+ * list of dead threads:
+ */
+ if (_find_thread(pthread) == 0 ||
+ _find_dead_thread(pthread) == 0)
+ pthread1 = pthread;
- /* Point to the first thread in the list: */
- pthread1 = _thread_link_list;
-
- /* Search for the thread to join to: */
- while (pthread1 != NULL && pthread1 != pthread) {
- /* Point to the next thread: */
- pthread1 = pthread1->nxt;
- }
-
- if (pthread1 == NULL) {
- /* Point to the first thread in the dead thread list: */
- pthread1 = _thread_dead;
-
- /* Search for the thread to join to: */
- while (pthread1 != NULL && pthread1 != pthread) {
- /* Point to the next thread: */
- pthread1 = pthread1->nxt;
- }
- }
-
- if (pthread1 == NULL) {
+ if (pthread1 == NULL)
/* Return an error: */
- rval = ESRCH;
+ ret = ESRCH;
/* Check if this thread has been detached: */
- } else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
+ else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0)
/* Return an error: */
- rval = ESRCH;
- }
+ ret = ESRCH;
+
/* Check if the thread is not dead: */
else if (pthread->state != PS_DEAD) {
/* Add the running thread to the join queue: */
@@ -92,32 +76,22 @@ pthread_join(pthread_t pthread, void **thread_return)
/* Schedule the next thread: */
_thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
- /* Block signals again: */
- _thread_kern_sig_block(NULL);
-
/* Check if the thread is not detached: */
- if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) {
+ if ((pthread->attr.flags & PTHREAD_DETACHED) == 0)
/* Check if the return value is required: */
- if (thread_return) {
+ if (thread_return)
/* Return the thread's return value: */
*thread_return = pthread->ret;
- }
- } else {
+ else
/* Return an error: */
- rval = ESRCH;
- }
- } else {
- /* Check if the return value is required: */
- if (thread_return != NULL) {
- /* Return the thread's return value: */
- *thread_return = pthread->ret;
- }
- }
+ ret = ESRCH;
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ /* Check if the return value is required: */
+ } else if (thread_return != NULL)
+ /* Return the thread's return value: */
+ *thread_return = pthread->ret;
/* Return the completion status: */
- return (rval);
+ return (ret);
}
#endif
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c
index 3b62422..36efc31 100644
--- a/lib/libpthread/thread/thr_kern.c
+++ b/lib/libpthread/thread/thr_kern.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: uthread_kern.c,v 1.8 1998/04/11 07:47:22 jb Exp $
+ * $Id: uthread_kern.c,v 1.9 1998/04/17 09:37:41 jb Exp $
*
*/
#include <errno.h>
@@ -49,15 +49,9 @@
#include <pthread.h>
#include "pthread_private.h"
-/* Static variables: */
-static sigset_t sig_to_block = 0xffffffff;
-static sigset_t sig_to_unblock = 0;
-
/* Static function prototype definitions: */
static void
_thread_kern_select(int wait_reqd);
-static void
-_thread_signal(pthread_t pthread, int sig);
void
_thread_kern_sched(struct sigcontext * scp)
@@ -78,8 +72,12 @@ _thread_kern_sched(struct sigcontext * scp)
struct timeval tv;
struct timeval tv1;
- /* Block signals: */
- _thread_kern_sig_block(NULL);
+ /*
+ * Flag the pthread kernel as executing scheduler code
+ * to avoid a scheduler signal from interrupting this
+ * execution and calling the scheduler again.
+ */
+ _thread_kern_in_sched = 1;
/* Check if this function was called from the signal handler: */
if (scp != NULL) {
@@ -101,14 +99,20 @@ __asm__("fnsave %0": :"m"(*fdata));
_thread_run->sig_saved = 1;
}
/* Save the state of the current thread: */
- else if (_thread_sys_setjmp(_thread_run->saved_jmp_buf) != 0) {
- /* Unblock signals (just in case): */
- _thread_kern_sig_unblock(0);
-
+ else if (setjmp(_thread_run->saved_jmp_buf) != 0) {
/*
* This point is reached when a longjmp() is called to
* restore the state of a thread.
+ *
+ * This is the normal way out of the scheduler.
*/
+ _thread_kern_in_sched = 0;
+
+ /*
+ * There might be pending signals for this thread, so
+ * dispatch any that aren't blocked:
+ */
+ _dispatch_signals();
return;
} else {
/* Flag the jump buffer was the last state saved: */
@@ -135,10 +139,9 @@ __asm__("fnsave %0": :"m"(*fdata));
pthread_prv = pthread;
}
/*
- * Check if this thread has detached or if it is a signal
- * handler thread:
+ * Check if this thread has detached:
*/
- else if (((pthread->attr.flags & PTHREAD_DETACHED) != 0) || pthread->parent_thread != NULL) {
+ else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
/* Check if there is no previous dead thread: */
if (pthread_prv == NULL) {
/*
@@ -210,41 +213,10 @@ __asm__("fnsave %0": :"m"(*fdata));
_thread_kern_select(0);
/*
- * Enter a loop to look for sleeping threads that are ready
- * or threads with pending signals that are no longer
- * blocked:
+ * Enter a loop to look for sleeping threads that are ready:
*/
- for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
- /* Enter a loop to process the sending signals: */
- for (i = 1; i < NSIG; i++) {
- /*
- * Check if there are no pending signals of
- * this type:
- */
- if (pthread->sigpend[i] == 0) {
- }
- /* Check if this signal type is not masked: */
- else if (sigismember(&pthread->sigmask, i) == 0) {
- /*
- * Delete the signal from the set of
- * pending signals for this thread:
- */
- pthread->sigpend[i] -= 1;
-
- /*
- * Act on the signal for the current
- * thread:
- */
- _thread_signal(pthread, i);
- } else {
- /*
- * This signal is masked, so make
- * sure the count does not exceed 1:
- */
- pthread->sigpend[i] = 1;
- }
- }
-
+ for (pthread = _thread_link_list; pthread != NULL;
+ pthread = pthread->nxt) {
/* Check if this thread is to timeout: */
if (pthread->state == PS_COND_WAIT ||
pthread->state == PS_SLEEP_WAIT ||
@@ -369,45 +341,6 @@ __asm__("fnsave %0": :"m"(*fdata));
* priority that is ready to run:
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
- /* Check if in single-threaded mode: */
- if (_thread_single != NULL) {
- /*
- * Check if the current thread is
- * the thread for which single-threaded
- * mode is enabled:
- */
- if (pthread == _thread_single) {
- /*
- * This thread is allowed
- * to run.
- */
- } else {
- /*
- * Walk up the signal handler
- * parent thread tree to see
- * if the current thread is
- * descended from the thread
- * for which single-threaded
- * mode is enabled.
- */
- pthread_nxt = pthread;
- while(pthread_nxt != NULL &&
- pthread_nxt != _thread_single) {
- pthread_nxt = pthread->parent_thread;
- }
- /*
- * Check if the current
- * thread is not descended
- * from the thread for which
- * single-threaded mode is
- * enabled.
- */
- if (pthread_nxt == NULL)
- /* Ignore this thread. */
- continue;
- }
- }
-
/* Check if the current thread is unable to run: */
if (pthread->state != PS_RUNNING) {
}
@@ -433,49 +366,11 @@ __asm__("fnsave %0": :"m"(*fdata));
* least recently.
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
- /* Check if in single-threaded mode: */
- if (_thread_single != NULL) {
- /*
- * Check if the current thread is
- * the thread for which single-threaded
- * mode is enabled:
- */
- if (pthread == _thread_single) {
- /*
- * This thread is allowed
- * to run.
- */
- } else {
- /*
- * Walk up the signal handler
- * parent thread tree to see
- * if the current thread is
- * descended from the thread
- * for which single-threaded
- * mode is enabled.
- */
- pthread_nxt = pthread;
- while(pthread_nxt != NULL &&
- pthread_nxt != _thread_single) {
- pthread_nxt = pthread->parent_thread;
- }
- /*
- * Check if the current
- * thread is not descended
- * from the thread for which
- * single-threaded mode is
- * enabled.
- */
- if (pthread_nxt == NULL)
- /* Ignore this thread. */
- continue;
- }
- }
-
/* Check if the current thread is unable to run: */
if (pthread->state != PS_RUNNING) {
/* Ignore threads that are not ready to run. */
}
+
/*
* Check if the current thread as an agregate
* priority not equal to the highest priority found
@@ -487,6 +382,7 @@ __asm__("fnsave %0": :"m"(*fdata));
* priority.
*/
}
+
/*
* Check if the current thread reached its time slice
* allocation last time it ran (or if it has not run
@@ -494,6 +390,7 @@ __asm__("fnsave %0": :"m"(*fdata));
*/
else if (pthread->slice_usec == -1) {
}
+
/*
* Check if an eligible thread has not been found
* yet, or if the current thread has an inactive time
@@ -526,45 +423,6 @@ __asm__("fnsave %0": :"m"(*fdata));
* priority. 3. Became inactive least recently.
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
- /* Check if in single-threaded mode: */
- if (_thread_single != NULL) {
- /*
- * Check if the current thread is
- * the thread for which single-threaded
- * mode is enabled:
- */
- if (pthread == _thread_single) {
- /*
- * This thread is allowed
- * to run.
- */
- } else {
- /*
- * Walk up the signal handler
- * parent thread tree to see
- * if the current thread is
- * descended from the thread
- * for which single-threaded
- * mode is enabled.
- */
- pthread_nxt = pthread;
- while(pthread_nxt != NULL &&
- pthread_nxt != _thread_single) {
- pthread_nxt = pthread->parent_thread;
- }
- /*
- * Check if the current
- * thread is not descended
- * from the thread for which
- * single-threaded mode is
- * enabled.
- */
- if (pthread_nxt == NULL)
- /* Ignore this thread. */
- continue;
- }
- }
-
/*
* Check if the current thread is unable to
* run:
@@ -804,14 +662,13 @@ __asm__("fnsave %0": :"m"(*fdata));
* was interrupted by a signal:
*/
_thread_sys_sigreturn(&_thread_run->saved_sigcontext);
- } else {
+ } else
/*
* Do a longjmp to restart the thread that
* was context switched out (by a longjmp to
* a different thread):
*/
- _thread_sys_longjmp(_thread_run->saved_jmp_buf, 1);
- }
+ longjmp(_thread_run->saved_jmp_buf, 1);
/* This point should not be reached. */
PANIC("Thread has returned from sigreturn or longjmp");
@@ -822,243 +679,6 @@ __asm__("fnsave %0": :"m"(*fdata));
exit(0);
}
-static void
-_thread_signal(pthread_t pthread, int sig)
-{
- int done;
- long l;
- pthread_t new_pthread;
- struct sigaction act;
- void *arg;
-
- /*
- * Assume that the signal will not be dealt with according
- * to the thread state:
- */
- done = 0;
-
- /* Process according to thread state: */
- switch (pthread->state) {
- /* States which do not change when a signal is trapped: */
- case PS_COND_WAIT:
- case PS_DEAD:
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- case PS_FILE_WAIT:
- case PS_JOIN:
- case PS_MUTEX_WAIT:
- case PS_RUNNING:
- case PS_STATE_MAX:
- case PS_SIGTHREAD:
- case PS_SUSPENDED:
- /* Nothing to do here. */
- break;
-
- /* Wait for child: */
- case PS_WAIT_WAIT:
- /* Check if the signal is from a child exiting: */
- if (sig == SIGCHLD) {
- /* Reset the error: */
- _thread_seterrno(pthread, 0);
-
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
- } else {
- /* Return the 'interrupted' error: */
- _thread_seterrno(pthread, EINTR);
-
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
- }
- pthread->interrupted = 1;
- break;
-
- /* Waiting on I/O for zero or more file descriptors: */
- case PS_SELECT_WAIT:
- pthread->data.select_data->nfds = -1;
-
- /* Return the 'interrupted' error: */
- _thread_seterrno(pthread, EINTR);
- pthread->interrupted = 1;
-
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
- break;
-
- /*
- * States that are interrupted by the occurrence of a signal
- * other than the scheduling alarm:
- */
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- case PS_SLEEP_WAIT:
- case PS_SIGWAIT:
- /* Return the 'interrupted' error: */
- _thread_seterrno(pthread, EINTR);
- pthread->interrupted = 1;
-
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
-
- /* Return the signal number: */
- pthread->signo = sig;
- break;
- }
-
- /*
- * Check if this signal has been dealt with, or is being
- * ignored:
- */
- if (done || pthread->act[sig - 1].sa_handler == SIG_IGN) {
- /* Ignore the signal for this thread. */
- }
- /* Check if this signal is to use the default handler: */
- else if (pthread->act[sig - 1].sa_handler == SIG_DFL) {
- /* Process according to signal type: */
- switch (sig) {
- /* Signals which cause core dumps: */
- case SIGQUIT:
- case SIGILL:
- case SIGTRAP:
- case SIGABRT:
- case SIGEMT:
- case SIGFPE:
- case SIGBUS:
- case SIGSEGV:
- case SIGSYS:
- /* Clear the signal action: */
- sigfillset(&act.sa_mask);
- act.sa_handler = SIG_DFL;
- act.sa_flags = SA_RESTART;
- _thread_sys_sigaction(sig, &act, NULL);
-
- /*
- * Do a sigreturn back to where the signal was
- * detected and a core dump should occur:
- */
- _thread_sys_sigreturn(&pthread->saved_sigcontext);
- break;
-
- /*
- * The following signals should terminate the
- * process. Do this by clearing the signal action
- * and then re-throwing the signal.
- */
- case SIGHUP:
- case SIGINT:
- case SIGPIPE:
- case SIGALRM:
- case SIGTERM:
- case SIGXCPU:
- case SIGXFSZ:
- case SIGVTALRM:
- case SIGUSR1:
- case SIGUSR2:
- /* These signals stop the process. Also re-throw them. */
- case SIGTSTP:
- case SIGTTIN:
- case SIGTTOU:
- /* Clear the signal action: */
- sigfillset(&act.sa_mask);
- act.sa_handler = SIG_DFL;
- act.sa_flags = SA_RESTART;
- _thread_sys_sigaction(sig, &act, NULL);
- /* Re-throw to ourselves. */
- kill(getpid(), sig);
- break;
-
- case SIGCONT:
- /*
- * If we get this it means that we were
- * probably stopped and then continued.
- * Reset the handler for the SIGTSTP, SIGTTIN
- * and SIGTTOU signals.
- */
-
- sigfillset(&act.sa_mask);
- act.sa_handler = (void (*) ()) _thread_sig_handler;
- act.sa_flags = SA_RESTART;
-
- /* Initialise the signals for default handling: */
- if (_thread_sys_sigaction(SIGTSTP, &act, NULL) != 0) {
- PANIC("Cannot initialise SIGTSTP signal handler");
- }
- if (_thread_sys_sigaction(SIGTTIN, &act, NULL) != 0) {
- PANIC("Cannot initialise SIGTTIN signal handler");
- }
- if (_thread_sys_sigaction(SIGTTOU, &act, NULL) != 0) {
- PANIC("Cannot initialise SIGTTOU signal handler");
- }
- break;
-
- /* Default processing for other signals: */
- default:
- /*
- * ### Default processing is a problem to resolve!
- * ###
- */
- break;
- }
- } else {
- /*
- * Cast the signal number as a long and then to a void
- * pointer. Sigh. This is POSIX.
- */
- l = (long) sig;
- arg = (void *) l;
-
- /* Create a signal handler thread, but don't run it yet: */
- if (_thread_create(&new_pthread, NULL, (void *) pthread->act[sig - 1].sa_handler, arg, pthread) != 0) {
- /*
- * Error creating signal handler thread, so abort
- * this process:
- */
- PANIC("Cannot create signal handler thread");
- }
- }
-
- /* Nothing to return. */
- return;
-}
-
-void
-_thread_kern_sig_block(int *status)
-{
- sigset_t oset;
-
- /*
- * Block all signals so that the process will not be interrupted by
- * signals:
- */
- _thread_sys_sigprocmask(SIG_SETMASK, &sig_to_block, &oset);
-
- /* Check if the caller wants the current block status returned: */
- if (status != NULL) {
- /* Return the previous signal block status: */
- *status = (oset != 0);
- }
- return;
-}
-
-void
-_thread_kern_sig_unblock(int status)
-{
- sigset_t oset;
-
- /*
- * Check if the caller thinks that signals weren't blocked when it
- * called _thread_kern_sig_block:
- */
- if (status == 0) {
- /*
- * Unblock all signals so that the process will be
- * interrupted when a signal occurs:
- */
- _thread_sys_sigprocmask(SIG_SETMASK, &sig_to_unblock, &oset);
- }
- return;
-}
-
void
_thread_kern_sched_state(enum pthread_state state, char *fname, int lineno)
{
@@ -1382,18 +1002,12 @@ _thread_kern_select(int wait_reqd)
*/
_thread_kern_in_select = 1;
- /* Unblock all signals: */
- _thread_kern_sig_unblock(0);
-
/*
* Wait for a file descriptor to be ready for read, write, or
* an exception, or a timeout to occur:
*/
count = _thread_sys_select(nfds + 1, &fd_set_read, &fd_set_write, &fd_set_except, p_tv);
- /* Block all signals again: */
- _thread_kern_sig_block(NULL);
-
/* Reset the kernel in select flag: */
_thread_kern_in_select = 0;
@@ -1426,10 +1040,10 @@ _thread_kern_select(int wait_reqd)
* signal and each byte is the signal number.
* This data is not used, but the fact that
* the signal handler wrote to the pipe *is*
- * used to cause the _thread_sys_select call
+ * used to cause the _select call
* to complete if the signal occurred between
* the time when signals were unblocked and
- * the _thread_sys_select select call being
+ * the _select select call being
* made.
*/
}
@@ -1439,36 +1053,22 @@ _thread_kern_select(int wait_reqd)
else if (count > 0) {
/*
* Point to the time value structure which has been zeroed so
- * that the call to _thread_sys_select will not wait:
+ * that the call to _select will not wait:
*/
p_tv = &tv;
/* Poll file descrptors without wait: */
count = _thread_sys_select(nfds + 1, &fd_set_read, &fd_set_write, &fd_set_except, p_tv);
}
+
/*
- * Check if the select call was interrupted, or some other error
- * occurred:
+ * Check if any file descriptors are ready:
*/
- if (count < 0) {
- /* Check if the select call was interrupted: */
- if (errno == EINTR) {
- /*
- * Interrupted calls are expected. The interrupting
- * signal will be in the sigpend array.
- */
- } else {
- /* This should not occur: */
- }
- }
- /* Check if no file descriptors are ready: */
- else if (count == 0) {
- /* Nothing to do here. */
- } else {
+ if (count > 0) {
/*
* Enter a loop to look for threads waiting on file
* descriptors that are flagged as available by the
- * _thread_sys_select syscall:
+ * _select syscall:
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
/* Process according to thread state: */
diff --git a/lib/libpthread/thread/thr_kill.c b/lib/libpthread/thread/thr_kill.c
index eb2c6b7..f6e684b 100644
--- a/lib/libpthread/thread/thr_kill.c
+++ b/lib/libpthread/thread/thr_kill.c
@@ -39,40 +39,19 @@
int
pthread_kill(pthread_t pthread, int sig)
{
- int rval = 0;
- int status;
- pthread_t p_pthread;
+ int ret;
/* Check for invalid signal numbers: */
if (sig < 0 || sig >= NSIG)
/* Invalid signal: */
- rval = EINVAL;
- else {
- /* Assume that the search will succeed: */
- rval = 0;
+ ret = EINVAL;
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
- /* Search for the thread: */
- p_pthread = _thread_link_list;
- while (p_pthread != NULL && p_pthread != pthread) {
- p_pthread = p_pthread->nxt;
- }
-
- /* Check if the thread was not found: */
- if (p_pthread == NULL)
- /* Can't find the thread: */
- rval = ESRCH;
- else
- /* Increment the pending signal count: */
- p_pthread->sigpend[sig] += 1;
-
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
- }
+ /* Find the thread in the list of active threads: */
+ else if ((ret = _find_thread(pthread)) == 0)
+ /* Increment the pending signal count: */
+ sigaddset(&pthread->sigpend,sig);
/* Return the completion status: */
- return (rval);
+ return (ret);
}
#endif
diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c
index 9f92de9..fb737cf 100644
--- a/lib/libpthread/thread/thr_mutex.c
+++ b/lib/libpthread/thread/thr_mutex.c
@@ -49,28 +49,26 @@ pthread_mutex_init(pthread_mutex_t * mutex,
ret = EINVAL;
} else {
/* Check if default mutex attributes: */
- if (mutex_attr == NULL || *mutex_attr == NULL) {
+ if (mutex_attr == NULL || *mutex_attr == NULL)
/* Default to a fast mutex: */
type = MUTEX_TYPE_FAST;
- } else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX) {
+
+ else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX)
/* Return an invalid argument error: */
ret = EINVAL;
- } else {
+ else
/* Use the requested mutex type: */
type = (*mutex_attr)->m_type;
- }
/* Check no errors so far: */
if (ret == 0) {
- if ((pmutex = (pthread_mutex_t) malloc(sizeof(struct pthread_mutex))) == NULL) {
+ if ((pmutex = (pthread_mutex_t)
+ malloc(sizeof(struct pthread_mutex))) == NULL)
ret = ENOMEM;
- } else {
+ else {
/* Reset the mutex flags: */
pmutex->m_flags = 0;
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
/* Process according to mutex type: */
switch (type) {
/* Fast mutex: */
@@ -96,14 +94,12 @@ pthread_mutex_init(pthread_mutex_t * mutex,
pmutex->m_flags |= MUTEX_FLAGS_INITED;
pmutex->m_owner = NULL;
pmutex->m_type = type;
+ pmutex->access_lock = 0;
*mutex = pmutex;
} else {
free(pmutex);
*mutex = NULL;
}
-
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
}
}
}
@@ -114,42 +110,25 @@ pthread_mutex_init(pthread_mutex_t * mutex,
int
pthread_mutex_destroy(pthread_mutex_t * mutex)
{
- int ret = 0;
- int status;
+ int ret = 0;
- if (mutex == NULL || *mutex == NULL) {
+ if (mutex == NULL || *mutex == NULL)
ret = EINVAL;
- } else {
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
- /* Process according to mutex type: */
- switch ((*mutex)->m_type) {
- /* Fast mutex: */
- case MUTEX_TYPE_FAST:
- /* Nothing to do here. */
- break;
-
- /* Counting mutex: */
- case MUTEX_TYPE_COUNTING_FAST:
- /* Reset the mutex count: */
- (*mutex)->m_data.m_count = 0;
- break;
-
- /* Trap undefined mutex types: */
- default:
- /* Return an invalid argument error: */
- ret = EINVAL;
- break;
- }
-
- /* Clean up the mutex in case that others want to use it: */
- _thread_queue_init(&(*mutex)->m_queue);
- (*mutex)->m_owner = NULL;
- (*mutex)->m_flags = 0;
-
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ else {
+ /* Lock the mutex structure: */
+ _spinlock(&(*mutex)->access_lock);
+
+ /*
+ * Free the memory allocated for the mutex
+ * structure:
+ */
+ free(*mutex);
+
+ /*
+ * Leave the caller's pointer NULL now that
+ * the mutex has been destroyed:
+ */
+ *mutex = NULL;
}
/* Return the completion status: */
@@ -160,7 +139,6 @@ int
pthread_mutex_trylock(pthread_mutex_t * mutex)
{
int ret = 0;
- int status;
if (mutex == NULL)
ret = EINVAL;
@@ -171,8 +149,8 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
*/
else if (*mutex != NULL ||
(ret = pthread_mutex_init(mutex,NULL)) == 0) {
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ /* Lock the mutex structure: */
+ _spinlock(&(*mutex)->access_lock);
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
@@ -216,8 +194,8 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
break;
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ /* Unlock the mutex structure: */
+ _atomic_unlock(&(*mutex)->access_lock);
}
/* Return the completion status: */
@@ -228,7 +206,6 @@ int
pthread_mutex_lock(pthread_mutex_t * mutex)
{
int ret = 0;
- int status;
if (mutex == NULL)
ret = EINVAL;
@@ -239,8 +216,8 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
*/
else if (*mutex != NULL ||
(ret = pthread_mutex_init(mutex,NULL)) == 0) {
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ /* Lock the mutex structure: */
+ _spinlock(&(*mutex)->access_lock);
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
@@ -262,11 +239,14 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
*/
_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
+ /* Unlock the mutex structure: */
+ _atomic_unlock(&(*mutex)->access_lock);
+
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
- /* Block signals: */
- _thread_kern_sig_block(NULL);
+ /* Lock the mutex again: */
+ _spinlock(&(*mutex)->access_lock);
}
}
break;
@@ -292,11 +272,14 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
*/
_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
+ /* Unlock the mutex structure: */
+ _atomic_unlock(&(*mutex)->access_lock);
+
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
- /* Block signals: */
- _thread_kern_sig_block(NULL);
+ /* Lock the mutex again: */
+ _spinlock(&(*mutex)->access_lock);
}
}
@@ -311,8 +294,8 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
break;
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ /* Unlock the mutex structure: */
+ _atomic_unlock(&(*mutex)->access_lock);
}
/* Return the completion status: */
@@ -323,13 +306,12 @@ int
pthread_mutex_unlock(pthread_mutex_t * mutex)
{
int ret = 0;
- int status;
if (mutex == NULL || *mutex == NULL) {
ret = EINVAL;
} else {
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ /* Lock the mutex structure: */
+ _spinlock(&(*mutex)->access_lock);
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
@@ -379,8 +361,8 @@ pthread_mutex_unlock(pthread_mutex_t * mutex)
break;
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ /* Unlock the mutex structure: */
+ _atomic_unlock(&(*mutex)->access_lock);
}
/* Return the completion status: */
diff --git a/lib/libpthread/thread/thr_nanosleep.c b/lib/libpthread/thread/thr_nanosleep.c
index 39c7dad..4ec7d3f 100644
--- a/lib/libpthread/thread/thr_nanosleep.c
+++ b/lib/libpthread/thread/thr_nanosleep.c
@@ -66,6 +66,7 @@ nanosleep(const struct timespec * time_to_sleep,
_thread_run->wakeup_time.tv_sec += 1;
_thread_run->wakeup_time.tv_nsec -= 1000000000;
}
+ _thread_run->interrupted = 0;
/* Reschedule the current thread to sleep: */
_thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__);
@@ -106,8 +107,8 @@ nanosleep(const struct timespec * time_to_sleep,
time_remaining->tv_nsec = remaining_time.tv_nsec;
}
- /* Check if the entire sleep was not completed: */
- if (remaining_time.tv_nsec != 0 || remaining_time.tv_sec != 0) {
+ /* Check if the sleep was interrupted: */
+ if (_thread_run->interrupted) {
/* Return an EINTR error : */
errno = EINTR;
ret = -1;
diff --git a/lib/libpthread/thread/thr_open.c b/lib/libpthread/thread/thr_open.c
index ef7a504..a538a75 100644
--- a/lib/libpthread/thread/thr_open.c
+++ b/lib/libpthread/thread/thr_open.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: uthread_open.c,v 1.3 1997/05/03 03:57:21 jb Exp $
*
*/
#include <stdarg.h>
@@ -49,9 +49,6 @@ open(const char *path, int flags,...)
int status;
va_list ap;
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
/* Check if the file is being created: */
if (flags & O_CREAT) {
/* Get the creation mode: */
@@ -71,9 +68,6 @@ open(const char *path, int flags,...)
fd = -1;
}
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
-
/* Return the file descriptor or -1 on error: */
return (fd);
}
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
index 5ceeaba..5f0f3a8 100644
--- a/lib/libpthread/thread/thr_private.h
+++ b/lib/libpthread/thread/thr_private.h
@@ -60,6 +60,10 @@
*/
#define PANIC(string) _thread_exit(__FILE__,__LINE__,string)
+/* Output debug messages like this: */
+#define stdout_debug(_x) _write(1,_x,strlen(_x));
+#define stderr_debug(_x) _write(2,_x,strlen(_x));
+
/*
* State change macro:
*/
@@ -97,6 +101,11 @@ struct pthread_mutex {
struct pthread *m_owner;
union pthread_mutex_data m_data;
long m_flags;
+
+ /*
+ * Lock for accesses to this structure.
+ */
+ long access_lock;
};
/*
@@ -131,6 +140,11 @@ struct pthread_cond {
struct pthread_queue c_queue;
void *c_data;
long c_flags;
+
+ /*
+ * Lock for accesses to this structure.
+ */
+ long access_lock;
};
struct pthread_cond_attr {
@@ -204,6 +218,7 @@ struct pthread_attr {
struct pthread_key {
pthread_mutex_t mutex;
+ long access_lock;
long count;
void (*destructor) ();
};
@@ -243,6 +258,13 @@ enum pthread_state {
* File descriptor table structure.
*/
struct fd_table_entry {
+ /*
+ * Lock for accesses to this file descriptor table
+ * entry. This is passed to _spinlock() to provide atomic
+ * access to this structure. It does *not* represent the
+ * state of the lock on the file descriptor.
+ */
+ long access_lock;
struct pthread_queue r_queue; /* Read queue. */
struct pthread_queue w_queue; /* Write queue. */
struct pthread *r_owner; /* Ptr to thread owning read lock. */
@@ -288,6 +310,11 @@ struct pthread {
char *name;
/*
+ * Lock for accesses to this thread structure.
+ */
+ long access_lock;
+
+ /*
* Pointer to the next thread in the thread linked list.
*/
struct pthread *nxt;
@@ -301,13 +328,6 @@ struct pthread {
void *stack;
struct pthread_attr attr;
- /*
- * Thread-specific signal handler interface:
- *
- * Array of signal actions for this thread.
- */
- struct sigaction act[NSIG];
-
#if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(__i386__)
/*
* Saved floating point registers on systems where they are not
@@ -335,17 +355,10 @@ struct pthread {
int sig_saved;
/*
- * Current signal mask and array of pending signals.
+ * Current signal mask and pending signals.
*/
sigset_t sigmask;
- int sigpend[NSIG];
-
- /*
- * Pointer to the parent thread for which the current thread is
- * a signal handler thread, otherwise NULL if the current thread
- * is not a signal handler thread.
- */
- struct pthread *parent_thread;
+ sigset_t sigpend;
/* Thread state: */
enum pthread_state state;
@@ -463,7 +476,7 @@ SCLASS struct pthread * volatile _thread_link_list
/*
* Array of kernel pipe file descriptors that are used to ensure that
- * no signals are missed in calls to _thread_sys_select.
+ * no signals are missed in calls to _select.
*/
SCLASS int _thread_kern_pipe[2]
#ifdef GLOBAL_PTHREAD_PRIVATE
@@ -480,6 +493,12 @@ SCLASS int _thread_kern_in_select
#else
;
#endif
+SCLASS int _thread_kern_in_sched
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0;
+#else
+;
+#endif
/* Last time that an incremental priority update was performed: */
SCLASS struct timeval kern_inc_prio_time
@@ -558,6 +577,11 @@ SCLASS int _thread_dtablesize /* Descriptor table size. */
;
#endif
+/*
+ * Array of signal actions for this process.
+ */
+struct sigaction _thread_sigact[NSIG];
+
/* Undefine the storage class specifier: */
#undef SCLASS
@@ -568,8 +592,18 @@ __BEGIN_DECLS
char *__ttyname_basic(int);
char *__ttyname_r_basic(int, char *, size_t);
char *ttyname_r(int, char *, size_t);
+int _find_dead_thread(pthread_t);
+int _find_thread(pthread_t);
int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t);
int _thread_fd_lock(int, int, struct timespec *,char *fname,int lineno);
+void _dispatch_signals(void);
+void _thread_signal(pthread_t, int);
+void _lock_dead_thread_list(void);
+void _lock_thread(void);
+void _lock_thread_list(void);
+void _unlock_dead_thread_list(void);
+void _unlock_thread(void);
+void _unlock_thread_list(void);
void _thread_exit(char *, int, char *);
void _thread_fd_unlock(int, int);
void *_thread_cleanup(pthread_t);
@@ -579,8 +613,6 @@ void _thread_init(void);
void _thread_kern_sched(struct sigcontext *);
void _thread_kern_sched_state(enum pthread_state,char *fname,int lineno);
void _thread_kern_set_timeout(struct timespec *);
-void _thread_kern_sig_block(int *);
-void _thread_kern_sig_unblock(int);
void _thread_sig_handler(int, int, struct sigcontext *);
void _thread_start(void);
void _thread_start_sig_handler(void);
@@ -597,11 +629,9 @@ int _thread_sys_sigaction(int, const struct sigaction *, struct sigaction *)
int _thread_sys_sigpending(sigset_t *);
int _thread_sys_sigprocmask(int, const sigset_t *, sigset_t *);
int _thread_sys_sigsuspend(const sigset_t *);
-int _thread_sys_sigblock(int);
int _thread_sys_siginterrupt(int, int);
int _thread_sys_sigpause(int);
int _thread_sys_sigreturn(struct sigcontext *);
-int _thread_sys_sigsetmask(int);
int _thread_sys_sigstack(const struct sigstack *, struct sigstack *);
int _thread_sys_sigvec(int, struct sigvec *, struct sigvec *);
void _thread_sys_psignal(unsigned int, const char *);
@@ -734,17 +764,6 @@ int _thread_sys_flock(int, int);
int _thread_sys_open(const char *, int, ...);
#endif
-/* #include <setjmp.h> */
-#ifdef _SETJMP_H_
-int __thread_sys_setjmp(jmp_buf);
-int _thread_sys_setjmp(jmp_buf);
-int _thread_sys_sigsetjmp(sigjmp_buf, int);
-void __thread_sys_longjmp(jmp_buf, int);
-void _thread_sys_longjmp(jmp_buf, int);
-void _thread_sys_longjmperror(void);
-void _thread_sys_siglongjmp(sigjmp_buf, int);
-#endif
-
/* #include <sys/ioctl.h> */
#ifdef _SYS_IOCTL_H_
int _thread_sys_ioctl(int, unsigned long, ...);
diff --git a/lib/libpthread/thread/thr_read.c b/lib/libpthread/thread/thr_read.c
index 242014e..76df2cf 100644
--- a/lib/libpthread/thread/thr_read.c
+++ b/lib/libpthread/thread/thr_read.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: uthread_read.c,v 1.3 1997/04/01 22:44:15 jb Exp $
*
*/
#include <sys/types.h>
@@ -45,7 +45,6 @@ ssize_t
read(int fd, void *buf, size_t nbytes)
{
int ret;
- int status;
/* Lock the file descriptor for read: */
if ((ret = _thread_fd_lock(fd, FD_READ, NULL,
@@ -54,7 +53,6 @@ read(int fd, void *buf, size_t nbytes)
while ((ret = _thread_sys_read(fd, buf, nbytes)) < 0) {
if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
- _thread_kern_sig_block(&status);
_thread_run->data.fd.fd = fd;
_thread_kern_set_timeout(NULL);
@@ -69,6 +67,7 @@ read(int fd, void *buf, size_t nbytes)
* interrupted by a signal
*/
if (_thread_run->interrupted) {
+ errno = EINTR;
ret = -1;
break;
}
diff --git a/lib/libpthread/thread/thr_readv.c b/lib/libpthread/thread/thr_readv.c
index 3ea065e..10d1a43 100644
--- a/lib/libpthread/thread/thr_readv.c
+++ b/lib/libpthread/thread/thr_readv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: uthread_readv.c,v 1.3 1997/04/01 22:44:16 jb Exp $
*
*/
#include <sys/types.h>
@@ -45,7 +45,6 @@ ssize_t
readv(int fd, const struct iovec * iov, int iovcnt)
{
int ret;
- int status;
/* Lock the file descriptor for read: */
if ((ret = _thread_fd_lock(fd, FD_READ, NULL,
@@ -54,7 +53,6 @@ readv(int fd, const struct iovec * iov, int iovcnt)
while ((ret = _thread_sys_readv(fd, iov, iovcnt)) < 0) {
if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
- _thread_kern_sig_block(&status);
_thread_run->data.fd.fd = fd;
_thread_kern_set_timeout(NULL);
@@ -69,6 +67,7 @@ readv(int fd, const struct iovec * iov, int iovcnt)
* interrupted by a signal
*/
if (_thread_run->interrupted) {
+ errno = EINTR;
ret = -1;
break;
}
diff --git a/lib/libpthread/thread/thr_resume_np.c b/lib/libpthread/thread/thr_resume_np.c
index 934df58..7c5f46a 100644
--- a/lib/libpthread/thread/thr_resume_np.c
+++ b/lib/libpthread/thread/thr_resume_np.c
@@ -35,36 +35,20 @@
#include <pthread.h>
#include "pthread_private.h"
+/* Resume a thread: */
int
pthread_resume_np(pthread_t thread)
{
- int ret = -1;
- pthread_t pthread;
- /*
- * Search for the thread in the linked list.
- */
- for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) {
- /* Is this the thread? */
- if (pthread == thread) {
- /* Found the thread. Is it suspended? */
- if (pthread->state == PS_SUSPENDED) {
- /* Allow the thread to run. */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
- ret = 0;
- } else if (pthread->state == PS_RUNNING) {
- /* Thread is already running. */
- ret = 0;
- } else {
- /* Thread is in some other state. */
- errno = EINVAL;
- }
+ int ret;
+
+ /* Find the thread in the list of active threads: */
+ if ((ret = _find_thread(thread)) == 0) {
+ /* The thread exists. Is it suspended? */
+ if (thread->state != PS_SUSPENDED) {
+ /* Allow the thread to run. */
+ PTHREAD_NEW_STATE(thread,PS_RUNNING);
}
}
- /* Check if thread was not found. */
- if (ret == -1) {
- /* No such thread */
- errno = ESRCH;
- }
return(ret);
}
#endif
diff --git a/lib/libpthread/thread/thr_select.c b/lib/libpthread/thread/thr_select.c
index 7db3ed2..96df9c1 100644
--- a/lib/libpthread/thread/thr_select.c
+++ b/lib/libpthread/thread/thr_select.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -125,8 +125,13 @@ select(int numfds, fd_set * readfds, fd_set * writefds,
memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds));
}
_thread_run->data.select_data = &data;
+ _thread_run->interrupted = 0;
_thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__);
- ret = data.nfds;
+ if (_thread_run->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ } else
+ ret = data.nfds;
}
}
/* clean up the locks */
diff --git a/lib/libpthread/thread/thr_seterrno.c b/lib/libpthread/thread/thr_seterrno.c
index c4fe08b6..570807f 100644
--- a/lib/libpthread/thread/thr_seterrno.c
+++ b/lib/libpthread/thread/thr_seterrno.c
@@ -47,15 +47,14 @@ void
_thread_seterrno(pthread_t thread, int error)
{
/* Check for the initial thread: */
- if (thread == _thread_initial) {
+ if (thread == _thread_initial)
/* The initial thread always uses the global error variable: */
errno = error;
- } else {
+ else
/*
* Threads other than the initial thread always use the error
* field in the thread structureL
*/
thread->error = error;
- }
}
#endif
diff --git a/lib/libpthread/thread/thr_setprio.c b/lib/libpthread/thread/thr_setprio.c
index 4b49ed0..dd89f15 100644
--- a/lib/libpthread/thread/thr_setprio.c
+++ b/lib/libpthread/thread/thr_setprio.c
@@ -38,43 +38,19 @@
int
pthread_setprio(pthread_t pthread, int prio)
{
- int rval = 0;
- int status;
- pthread_t pthread_p;
+ int ret;
/* Check if the priority is invalid: */
- if (prio < PTHREAD_MIN_PRIORITY || prio > PTHREAD_MAX_PRIORITY) {
+ if (prio < PTHREAD_MIN_PRIORITY || prio > PTHREAD_MAX_PRIORITY)
/* Return an invalid argument error: */
- errno = EINVAL;
- rval = -1;
- } else {
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ ret = EINVAL;
- /* Point to the first thread in the list: */
- pthread_p = _thread_link_list;
-
- /* Enter a loop to search for the thread: */
- while (pthread_p != NULL && pthread_p != pthread) {
- /* Point to the next thread: */
- pthread_p = pthread_p->nxt;
- }
-
- /* Check if the thread pointer is NULL: */
- if (pthread == NULL || pthread_p == NULL) {
- /* Return a 'search' error: */
- errno = ESRCH;
- rval = -1;
- } else {
- /* Set the thread priority: */
- pthread->pthread_priority = prio;
- }
-
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
- }
+ /* Find the thread in the list of active threads: */
+ else if ((ret = _find_thread(pthread)) == 0)
+ /* Set the thread priority: */
+ pthread->pthread_priority = prio;
/* Return the error status: */
- return (rval);
+ return (ret);
}
#endif
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
index e73d5a2..1e5ee63 100644
--- a/lib/libpthread/thread/thr_sig.c
+++ b/lib/libpthread/thread/thr_sig.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,16 +38,79 @@
#include <pthread.h>
#include "pthread_private.h"
+/* Static variables: */
+static int volatile yield_on_unlock_dead = 0;
+static int volatile yield_on_unlock_thread = 0;
+static long volatile thread_dead_lock = 0;
+static long volatile thread_link_list_lock = 0;
+
+/* Lock the thread list: */
+void
+_lock_thread_list()
+{
+ /* Lock the thread list: */
+ _spinlock(&thread_link_list_lock);
+}
+
+/* Lock the dead thread list: */
+void
+_lock_dead_thread_list()
+{
+ /* Lock the dead thread list: */
+ _spinlock(&thread_dead_lock);
+}
+
+/* Lock the thread list: */
+void
+_unlock_thread_list()
+{
+ /* Unlock the thread list: */
+ _atomic_unlock(&thread_link_list_lock);
+
+ /*
+ * Check if a scheduler interrupt occurred while the thread
+ * list was locked:
+ */
+ if (yield_on_unlock_thread) {
+ /* Reset the interrupt flag: */
+ yield_on_unlock_thread = 0;
+
+ /* This thread has overstayed it's welcome: */
+ sched_yield();
+ }
+}
+
+/* Lock the dead thread list: */
+void
+_unlock_dead_thread_list()
+{
+ /* Unlock the dead thread list: */
+ _atomic_unlock(&thread_dead_lock);
+
+ /*
+ * Check if a scheduler interrupt occurred while the dead
+ * thread list was locked:
+ */
+ if (yield_on_unlock_dead) {
+ /* Reset the interrupt flag: */
+ yield_on_unlock_dead = 0;
+
+ /* This thread has overstayed it's welcome: */
+ sched_yield();
+ }
+}
+
void
_thread_sig_handler(int sig, int code, struct sigcontext * scp)
{
char c;
int i;
+ int dispatch = 0;
pthread_t pthread;
/*
* Check if the pthread kernel has unblocked signals (or is about to)
- * and was on its way into a _thread_sys_select when the current
+ * and was on its way into a _select when the current
* signal interrupted it:
*/
if (_thread_kern_in_select) {
@@ -57,51 +120,65 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
/*
* Write the signal number to the kernel pipe so that it will
* be ready to read when this signal handler returns. This
- * means that the _thread_sys_select call will complete
+ * means that the _select call will complete
* immediately.
*/
- if (_thread_sys_write(_thread_kern_pipe[1], &c, 1) != 1) {
- }
+ _thread_sys_write(_thread_kern_pipe[1], &c, 1);
}
+
/* Check if the signal requires a dump of thread information: */
- if (sig == SIGINFO) {
+ if (sig == SIGINFO)
/* Dump thread information to file: */
_thread_dump_info();
- } else {
- /* Handle depending on signal type: */
- switch (sig) {
- /* Interval timer used for timeslicing: */
- case SIGVTALRM:
+
+ /* Check if an interval timer signal: */
+ else if (sig == SIGVTALRM) {
+ /* Check if the scheduler interrupt has come at an
+ * unfortunate time which one of the threads is
+ * modifying the thread list:
+ */
+ if (thread_link_list_lock)
/*
- * Don't add the signal to any thread. Just want to
- * call the scheduler:
+ * Set a flag so that the thread that has
+ * the lock yields when it unlocks the
+ * thread list:
*/
- break;
+ yield_on_unlock_thread = 1;
- /* Child termination: */
- case SIGCHLD:
+ /* Check if the scheduler interrupt has come at an
+ * unfortunate time which one of the threads is
+ * modifying the dead thread list:
+ */
+ if (thread_dead_lock)
/*
- * Enter a loop to process each thread in the linked
- * list:
+ * Set a flag so that the thread that has
+ * the lock yields when it unlocks the
+ * dead thread list:
*/
- for (pthread = _thread_link_list; pthread != NULL;
- pthread = pthread->nxt) {
- /*
- * Add the signal to the set of pending
- * signals:
- */
- pthread->sigpend[sig] += 1;
- if (pthread->state == PS_WAIT_WAIT) {
- /* Reset the error: */
- /* There should be another flag so that this is not required! ### */
- _thread_seterrno(pthread, 0);
-
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
- }
- }
+ yield_on_unlock_dead = 1;
+
+ /*
+ * Check if the kernel has not been interrupted while
+ * executing scheduler code:
+ */
+ else if (!_thread_kern_in_sched) {
+ /*
+ * Schedule the next thread. This function is not
+ * expected to return because it will do a longjmp
+ * instead.
+ */
+ _thread_kern_sched(scp);
/*
+ * This point should not be reached, so abort the
+ * process:
+ */
+ PANIC("Returned to signal function from scheduler");
+ }
+ } else {
+ /* Check if a child has terminated: */
+ if (sig == SIGCHLD) {
+ /*
* Go through the file list and set all files
* to non-blocking again in case the child
* set some of them to block. Sigh.
@@ -109,59 +186,137 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
for (i = 0; i < _thread_dtablesize; i++) {
/* Check if this file is used: */
if (_thread_fd_table[i] != NULL) {
- /* Set the file descriptor to non-blocking: */
- _thread_sys_fcntl(i, F_SETFL, _thread_fd_table[i]->flags | O_NONBLOCK);
+ /*
+ * Set the file descriptor to
+ * non-blocking:
+ */
+ _thread_sys_fcntl(i, F_SETFL,
+ _thread_fd_table[i]->flags |
+ O_NONBLOCK);
}
}
- break;
+ }
- /* Signals specific to the running thread: */
- case SIGBUS:
- case SIGEMT:
- case SIGFPE:
- case SIGILL:
- case SIGPIPE:
- case SIGSEGV:
- case SIGSYS:
- /* Add the signal to the set of pending signals: */
- _thread_run->sigpend[sig] += 1;
- break;
+ /*
+ * POSIX says that pending SIGCONT signals are
+ * discarded when one of there signals occurs.
+ */
+ if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
+ /*
+ * Enter a loop to discard pending SIGCONT
+ * signals:
+ */
+ for (pthread = _thread_link_list;
+ pthread != NULL;
+ pthread = pthread->nxt)
+ sigdelset(&pthread->sigpend,SIGCONT);
+ }
- /* Signals to send to all threads: */
- default:
+ /* Check if the signal is not being ignored: */
+ if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
/*
* Enter a loop to process each thread in the linked
* list:
*/
for (pthread = _thread_link_list; pthread != NULL;
- pthread = pthread->nxt) {
- /*
- * Add the signal to the set of pending
- * signals:
- */
- pthread->sigpend[sig] += 1;
- }
+ pthread = pthread->nxt)
+ _thread_signal(pthread,sig);
+
+ /* Dispatch pending signals to the running thread: */
+ _dispatch_signals();
+ }
+
+ /* Returns nothing. */
+ return;
+}
+
+/* Perform thread specific actions in response to a signal: */
+void
+_thread_signal(pthread_t pthread, int sig)
+{
+ pthread_t saved;
+ struct sigaction act;
+
+ /*
+ * Flag the signal as pending. It will be dispatched later.
+ */
+ sigaddset(&pthread->sigpend,sig);
+
+ /* Check if system calls are not restarted: */
+ if ((_thread_sigact[sig - 1].sa_flags & SA_RESTART) == 0) {
+ /*
+ * Process according to thread state:
+ */
+ switch (pthread->state) {
+ /*
+ * States which do not change when a signal is trapped:
+ */
+ case PS_COND_WAIT:
+ case PS_DEAD:
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FILE_WAIT:
+ case PS_JOIN:
+ case PS_MUTEX_WAIT:
+ case PS_RUNNING:
+ case PS_STATE_MAX:
+ case PS_SIGTHREAD:
+ case PS_SUSPENDED:
+ /* Nothing to do here. */
+ break;
+
+ /*
+ * States that are interrupted by the occurrence of a signal
+ * other than the scheduling alarm:
+ */
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ case PS_SLEEP_WAIT:
+ case PS_SIGWAIT:
+ case PS_WAIT_WAIT:
+ case PS_SELECT_WAIT:
+ /* Flag the operation as interrupted: */
+ pthread->interrupted = 1;
+
+ /* Change the state of the thread to run: */
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+
+ /* Return the signal number: */
+ pthread->signo = sig;
break;
}
+ }
+}
- /* Check if the kernel is not locked: */
- if (_thread_run != &_thread_kern_thread) {
- /*
- * Schedule the next thread. This function is not
- * expected to return because it will do a longjmp
- * instead.
- */
- _thread_kern_sched(scp);
+/* Dispatch pending signals to the running thread: */
+void
+_dispatch_signals()
+{
+ int i;
+ /*
+ * Check if there are pending signals for the running
+ * thread that aren't blocked:
+ */
+ if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0)
+ /* Look for all possible pending signals: */
+ for (i = 1; i < NSIG; i++)
/*
- * This point should not be reached, so abort the
- * process:
+ * Check that a custom handler is installed
+ * and if the signal is not blocked:
*/
- PANIC("Returned to signal function from scheduler");
- }
- }
+ if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
+ _thread_sigact[i - 1].sa_handler != SIG_IGN &&
+ sigismember(&_thread_run->sigpend,i) &&
+ !sigismember(&_thread_run->sigmask,i)) {
+ /* Clear the pending signal: */
+ sigdelset(&_thread_run->sigpend,i);
- /* Returns nothing. */
- return;
+ /*
+ * Dispatch the signal via the custom signal
+ * handler:
+ */
+ (*(_thread_sigact[i - 1].sa_handler))(i);
+ }
}
#endif
diff --git a/lib/libpthread/thread/thr_sigaction.c b/lib/libpthread/thread/thr_sigaction.c
index dd08405..3538f27 100644
--- a/lib/libpthread/thread/thr_sigaction.c
+++ b/lib/libpthread/thread/thr_sigaction.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,8 +39,8 @@
int
sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
{
- int ret = 0;
- int status;
+ int ret = 0;
+ struct sigaction gact;
/* Check if the signal number is out of range: */
if (sig < 1 || sig > NSIG) {
@@ -54,25 +54,47 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
*/
if (oact != NULL) {
/* Return the existing signal action contents: */
- oact->sa_handler = _thread_run->act[sig - 1].sa_handler;
- oact->sa_mask = _thread_run->act[sig - 1].sa_mask;
- oact->sa_flags = _thread_run->act[sig - 1].sa_flags;
+ oact->sa_handler = _thread_sigact[sig - 1].sa_handler;
+ oact->sa_mask = _thread_sigact[sig - 1].sa_mask;
+ oact->sa_flags = _thread_sigact[sig - 1].sa_flags;
}
+
/* Check if a signal action was supplied: */
if (act != NULL) {
- /* Block signals while the signal handler is changed: */
- _thread_kern_sig_block(&status);
-
/* Set the new signal handler: */
- _thread_run->act[sig - 1].sa_handler = act->sa_handler;
- _thread_run->act[sig - 1].sa_mask = act->sa_mask;
- _thread_run->act[sig - 1].sa_flags = act->sa_flags;
+ _thread_sigact[sig - 1].sa_mask = act->sa_mask;
+ _thread_sigact[sig - 1].sa_flags = act->sa_flags;
+ _thread_sigact[sig - 1].sa_handler = act->sa_handler;
+ }
+
+ /*
+ * Check if the kernel needs to be advised of a change
+ * in signal action:
+ */
+ if (act != NULL && sig != SIGVTALRM && sig != SIGCHLD &&
+ sig != SIGINFO) {
+ /* Initialise the global signal action structure: */
+ gact.sa_mask = act->sa_mask;
+ gact.sa_flags = act->sa_flags | SA_RESTART;
/*
- * Unblock signals to allow the new signal handler to
- * take effect:
+ * Check if the signal handler is being set to
+ * the default or ignore handlers:
*/
- _thread_kern_sig_unblock(status);
+ if (act->sa_handler == SIG_DFL ||
+ act->sa_handler == SIG_IGN)
+ /* Specify the built in handler: */
+ gact.sa_handler = act->sa_handler;
+ else
+ /*
+ * Specify the thread kernel signal
+ * handler:
+ */
+ gact.sa_handler = (void (*) ()) _thread_sig_handler;
+
+ /* Change the signal action in the kernel: */
+ if (_thread_sys_sigaction(sig,&gact,NULL) != 0)
+ ret = -1;
}
}
diff --git a/lib/libpthread/thread/thr_sigmask.c b/lib/libpthread/thread/thr_sigmask.c
index 94f64cb..23d6b7f 100644
--- a/lib/libpthread/thread/thr_sigmask.c
+++ b/lib/libpthread/thread/thr_sigmask.c
@@ -39,8 +39,7 @@
int
pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
- int ret = 0;
- int status;
+ int ret = 0;
/* Check if the existing signal process mask is to be returned: */
if (oset != NULL) {
@@ -49,9 +48,6 @@ pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
}
/* Check if a new signal set was provided by the caller: */
if (set != NULL) {
- /* Block signals while the signal mask is changed: */
- _thread_kern_sig_block(&status);
-
/* Process according to what to do: */
switch (how) {
/* Block signals: */
@@ -81,11 +77,12 @@ pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
}
/*
- * Schedule the next thread in case there are signals that
- * now need to be acted on:
+ * Dispatch signals to the running thread that are pending
+ * and now unblocked:
*/
- _thread_kern_sched(NULL);
+ _dispatch_signals();
}
+
/* Return the completion status: */
return (ret);
}
diff --git a/lib/libpthread/thread/thr_sigprocmask.c b/lib/libpthread/thread/thr_sigprocmask.c
index b4a8d84..81b602f 100644
--- a/lib/libpthread/thread/thr_sigprocmask.c
+++ b/lib/libpthread/thread/thr_sigprocmask.c
@@ -39,8 +39,7 @@
int
sigprocmask(int how, const sigset_t * set, sigset_t * oset)
{
- int ret = 0;
- int status;
+ int ret = 0;
/* Check if the existing signal process mask is to be returned: */
if (oset != NULL) {
@@ -49,9 +48,6 @@ sigprocmask(int how, const sigset_t * set, sigset_t * oset)
}
/* Check if a new signal set was provided by the caller: */
if (set != NULL) {
- /* Block signals while the signal mask is changed: */
- _thread_kern_sig_block(&status);
-
/* Process according to what to do: */
switch (how) {
/* Block signals: */
@@ -81,10 +77,10 @@ sigprocmask(int how, const sigset_t * set, sigset_t * oset)
}
/*
- * Schedule the next thread in case there are signals that
- * now need to be acted on:
+ * Dispatch signals to the running thread that are pending
+ * and now unblocked:
*/
- _thread_kern_sched(NULL);
+ _dispatch_signals();
}
/* Return the completion status: */
return (ret);
diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c
index 14cf74b..f7a7b12 100644
--- a/lib/libpthread/thread/thr_sigsuspend.c
+++ b/lib/libpthread/thread/thr_sigsuspend.c
@@ -53,6 +53,9 @@ sigsuspend(const sigset_t * set)
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
+ /* Always return an interrupted error: */
+ errno = EINTR;
+
/* Restore the signal mask: */
_thread_run->sigmask = oset;
} else {
diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c
index 4f95190..63c7093 100644
--- a/lib/libpthread/thread/thr_sigwait.c
+++ b/lib/libpthread/thread/thr_sigwait.c
@@ -43,9 +43,6 @@ sigwait(const sigset_t * set, int *sig)
int status;
sigset_t oset;
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
/* Save the current sigmal mask: */
oset = _thread_run->sigmask;
@@ -55,18 +52,12 @@ sigwait(const sigset_t * set, int *sig)
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
- /* Block signals again: */
- _thread_kern_sig_block(NULL);
-
/* Return the signal number to the caller: */
*sig = _thread_run->signo;
/* Restore the signal mask: */
_thread_run->sigmask = oset;
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
-
/* Return the completion status: */
return (ret);
}
diff --git a/lib/libpthread/thread/thr_spec.c b/lib/libpthread/thread/thr_spec.c
index 7ff9054..dc493dd 100644
--- a/lib/libpthread/thread/thr_spec.c
+++ b/lib/libpthread/thread/thr_spec.c
@@ -39,29 +39,38 @@
#include "pthread_private.h"
/* Static variables: */
-static struct pthread_key key_table[PTHREAD_KEYS_MAX];
+static struct pthread_key key_table[PTHREAD_KEYS_MAX];
+static long key_table_lock = 0;
int
pthread_key_create(pthread_key_t * key, void (*destructor) (void *))
{
+ /* Lock the key table: */
+ _spinlock(&key_table_lock);
+
for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) {
if (key_table[(*key)].count == 0) {
key_table[(*key)].count++;
key_table[(*key)].destructor = destructor;
+
+ /* Unlock the key table: */
+ _atomic_unlock(&key_table_lock);
return (0);
}
}
+
+ /* Unlock the key table: */
+ _atomic_unlock(&key_table_lock);
return (EAGAIN);
}
int
pthread_key_delete(pthread_key_t key)
{
- int ret;
- int status;
+ int ret;
- /* Block signals: */
- _thread_kern_sig_block(&status);
+ /* Lock the key table: */
+ _spinlock(&key_table_lock);
if (key < PTHREAD_KEYS_MAX) {
switch (key_table[key].count) {
@@ -74,12 +83,11 @@ pthread_key_delete(pthread_key_t key)
default:
ret = EBUSY;
}
- } else {
+ } else
ret = EINVAL;
- }
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
+ /* Unlock the key table: */
+ _atomic_unlock(&key_table_lock);
return (ret);
}
@@ -89,14 +97,13 @@ _thread_cleanupspecific(void)
void *data;
int key;
int itr;
- int status;
-
- /* Block signals: */
- _thread_kern_sig_block(&status);
for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) {
for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
if (_thread_run->specific_data_count) {
+ /* Lock the key table entry: */
+ _spinlock(&key_table[key].access_lock);
+
if (_thread_run->specific_data[key]) {
data = (void *) _thread_run->specific_data[key];
_thread_run->specific_data[key] = NULL;
@@ -106,19 +113,16 @@ _thread_cleanupspecific(void)
}
key_table[key].count--;
}
+
+ /* Unlock the key table entry: */
+ _atomic_unlock(&key_table[key].access_lock);
} else {
free(_thread_run->specific_data);
-
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
return;
}
}
}
free(_thread_run->specific_data);
-
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
}
static inline const void **
@@ -136,25 +140,16 @@ pthread_setspecific(pthread_key_t key, const void *value)
{
pthread_t pthread;
int ret = 0;
- int status;
-
- /* Block signals: */
- _thread_kern_sig_block(&status);
/* Point to the running thread: */
pthread = _thread_run;
- /*
- * Enter a loop for signal handler threads to find the parent thread
- * which has the specific data associated with it:
- */
- while (pthread->parent_thread != NULL) {
- /* Point to the parent thread: */
- pthread = pthread->parent_thread;
- }
-
- if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) {
+ if ((pthread->specific_data) ||
+ (pthread->specific_data = pthread_key_allocate_data())) {
if ((key < PTHREAD_KEYS_MAX) && (key_table)) {
+ /* Lock the key table entry: */
+ _spinlock(&key_table[key].access_lock);
+
if (key_table[key].count) {
if (pthread->specific_data[key] == NULL) {
if (value != NULL) {
@@ -169,18 +164,16 @@ pthread_setspecific(pthread_key_t key, const void *value)
}
pthread->specific_data[key] = value;
ret = 0;
- } else {
+ } else
ret = EINVAL;
- }
- } else {
+
+ /* Unlock the key table entry: */
+ _atomic_unlock(&key_table[key].access_lock);
+
+ } else
ret = EINVAL;
- }
- } else {
+ } else
ret = ENOMEM;
- }
-
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
return (ret);
}
@@ -188,31 +181,17 @@ void *
pthread_getspecific(pthread_key_t key)
{
pthread_t pthread;
- int status;
void *data;
- /* Block signals: */
- _thread_kern_sig_block(&status);
-
/* Point to the running thread: */
pthread = _thread_run;
- /*
- * Enter a loop for signal handler threads to find the parent thread
- * which has the specific data associated with it:
- */
- while (pthread->parent_thread != NULL) {
- /* Point to the parent thread: */
- pthread = pthread->parent_thread;
- }
-
- /* Check for errors: */
- if (pthread == NULL) {
- /* Return an invalid argument error: */
- data = NULL;
- }
/* Check if there is specific data: */
- else if (pthread->specific_data != NULL && (key < PTHREAD_KEYS_MAX) && (key_table)) {
+ if (pthread->specific_data != NULL &&
+ (key < PTHREAD_KEYS_MAX) && (key_table)) {
+ /* Lock the key table entry: */
+ _spinlock(&key_table[key].access_lock);
+
/* Check if this key has been used before: */
if (key_table[key].count) {
/* Return the value: */
@@ -224,13 +203,12 @@ pthread_getspecific(pthread_key_t key)
*/
data = NULL;
}
- } else {
+
+ /* Unlock the key table entry: */
+ _atomic_unlock(&key_table[key].access_lock);
+ } else
/* No specific data has been created, so just return NULL: */
data = NULL;
- }
-
- /* Unblock signals: */
- _thread_kern_sig_unblock(status);
return (data);
}
#endif
diff --git a/lib/libpthread/thread/thr_spinlock.c b/lib/libpthread/thread/thr_spinlock.c
new file mode 100644
index 0000000..b2fe269
--- /dev/null
+++ b/lib/libpthread/thread/thr_spinlock.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ */
+
+#include <stdio.h>
+#include <sched.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "spinlock.h"
+#include "pthread_private.h"
+
+/*
+ * Lock a location for the running thread. Yield to allow other
+ * threads to run if this thread is blocked because the lock is
+ * not available. Note that this function does not sleep. It
+ * assumes that the lock will be available very soon.
+ */
+void
+_spinlock(long *lck)
+{
+ do {
+ /*
+ * Allow other threads to run if the lock is not
+ * available:
+ */
+ while (*lck != 0)
+ sched_yield();
+
+ /*
+ * Try to grab the lock and loop if another thread grabs
+ * it before we do.
+ */
+ } while(_atomic_lock(lck,(long) _thread_run));
+}
diff --git a/lib/libpthread/thread/thr_suspend_np.c b/lib/libpthread/thread/thr_suspend_np.c
index d065b73..871683a 100644
--- a/lib/libpthread/thread/thr_suspend_np.c
+++ b/lib/libpthread/thread/thr_suspend_np.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,32 +35,24 @@
#include <pthread.h>
#include "pthread_private.h"
+/* Suspend a thread: */
int
pthread_suspend_np(pthread_t thread)
{
- int ret = -1;
- pthread_t pthread;
- /*
- * Search for the thread in the linked list.
- */
- for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) {
- /* Is this the thread? */
- if (pthread == thread) {
- /* Found the thread. Is it running? */
- if (pthread->state != PS_RUNNING &&
- pthread->state != PS_SUSPENDED) {
- /* The thread operation has been interrupted */
- _thread_seterrno(pthread,EINTR);
- }
- /* Suspend the thread. */
- PTHREAD_NEW_STATE(pthread,PS_SUSPENDED);
- ret = 0;
+ int ret;
+
+ /* Find the thread in the list of active threads: */
+ if ((ret = _find_thread(thread)) == 0) {
+ /* The thread exists. Is it running? */
+ if (thread->state != PS_RUNNING &&
+ thread->state != PS_SUSPENDED) {
+ /* The thread operation has been interrupted */
+ _thread_seterrno(thread,EINTR);
+ thread->interrupted = 1;
}
- }
- /* Check if thread was not found. */
- if (ret == -1) {
- /* No such thread */
- errno = ESRCH;
+
+ /* Suspend the thread. */
+ PTHREAD_NEW_STATE(thread,PS_SUSPENDED);
}
return(ret);
}
diff --git a/lib/libpthread/thread/thr_wait4.c b/lib/libpthread/thread/thr_wait4.c
index 0a721af4f..dda8aee 100644
--- a/lib/libpthread/thread/thr_wait4.c
+++ b/lib/libpthread/thread/thr_wait4.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,23 +39,23 @@
pid_t
wait4(pid_t pid, int *istat, int options, struct rusage * rusage)
{
- int status;
pid_t ret;
- _thread_kern_sig_block(&status);
/* Perform a non-blocking wait4 syscall: */
while ((ret = _thread_sys_wait4(pid, istat, options | WNOHANG, rusage)) == 0 && (options & WNOHANG) == 0) {
+ /* Reset the interrupted operation flag: */
+ _thread_run->interrupted = 0;
+
/* Schedule the next thread while this one waits: */
_thread_kern_sched_state(PS_WAIT_WAIT, __FILE__, __LINE__);
/* Check if this call was interrupted by a signal: */
- if (errno == EINTR) {
+ if (_thread_run->interrupted) {
+ errno = EINTR;
ret = -1;
break;
}
- _thread_kern_sig_block(NULL);
}
- _thread_kern_sig_unblock(status);
return (ret);
}
#endif
diff --git a/lib/libpthread/thread/thr_write.c b/lib/libpthread/thread/thr_write.c
index e86e71b..f8be7da 100644
--- a/lib/libpthread/thread/thr_write.c
+++ b/lib/libpthread/thread/thr_write.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: uthread_write.c,v 1.3 1997/04/01 22:44:17 jb Exp $
+ * $Id: uthread_write.c,v 1.4 1998/02/13 01:27:33 julian Exp $
*
*/
#include <sys/types.h>
@@ -45,7 +45,6 @@ ssize_t
write(int fd, const void *buf, size_t nbytes)
{
int ret;
- int status;
/* Lock the file descriptor for write: */
if ((ret = _thread_fd_lock(fd, FD_WRITE, NULL,
@@ -54,7 +53,6 @@ write(int fd, const void *buf, size_t nbytes)
while ((ret = _thread_sys_write(fd, buf, nbytes)) < 0) {
if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
- _thread_kern_sig_block(&status);
_thread_run->data.fd.fd = fd;
_thread_kern_set_timeout(NULL);
@@ -69,6 +67,7 @@ write(int fd, const void *buf, size_t nbytes)
* interrupted by a signal
*/
if (_thread_run->interrupted) {
+ errno = EINTR;
ret = -1;
break;
}
diff --git a/lib/libpthread/thread/thr_writev.c b/lib/libpthread/thread/thr_writev.c
index 56e1872..f3badec 100644
--- a/lib/libpthread/thread/thr_writev.c
+++ b/lib/libpthread/thread/thr_writev.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: uthread_writev.c,v 1.3 1997/04/01 22:44:18 jb Exp $
+ * $Id: uthread_writev.c,v 1.4 1998/02/13 01:27:34 julian Exp $
*
*/
#include <sys/types.h>
@@ -45,7 +45,6 @@ ssize_t
writev(int fd, const struct iovec * iov, int iovcnt)
{
int ret;
- int status;
/* Lock the file descriptor for write: */
if ((ret = _thread_fd_lock(fd, FD_WRITE, NULL,
@@ -54,7 +53,6 @@ writev(int fd, const struct iovec * iov, int iovcnt)
while ((ret = _thread_sys_writev(fd, iov, iovcnt)) < 0) {
if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
- _thread_kern_sig_block(&status);
_thread_run->data.fd.fd = fd;
_thread_kern_set_timeout(NULL);
@@ -69,6 +67,7 @@ writev(int fd, const struct iovec * iov, int iovcnt)
* interrupted by a signal
*/
if (_thread_run->interrupted) {
+ errno = EINTR;
ret = -1;
break;
}
OpenPOWER on IntegriCloud