diff options
142 files changed, 2754 insertions, 3772 deletions
diff --git a/lib/libc_r/uthread/Makefile.inc b/lib/libc_r/uthread/Makefile.inc index 4f1b308..924453f 100644 --- a/lib/libc_r/uthread/Makefile.inc +++ b/lib/libc_r/uthread/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/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h index 5ceeaba..5f0f3a8 100644 --- a/lib/libc_r/uthread/pthread_private.h +++ b/lib/libc_r/uthread/pthread_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/libc_r/uthread/uthread_accept.c b/lib/libc_r/uthread/uthread_accept.c index 261fa15..1ea1474 100644 --- a/lib/libc_r/uthread/uthread_accept.c +++ b/lib/libc_r/uthread/uthread_accept.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 @@ -57,13 +57,15 @@ accept(int fd, struct sockaddr * name, int *namelen) /* Set the timeout: */ _thread_kern_set_timeout(NULL); + _thread_run->interrupted = 0; /* Schedule the next thread: */ _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__); /* Check if the wait was interrupted: */ - if (errno == EINTR) { + if (_thread_run->interrupted) { /* Return an error status: */ + errno = EINTR; ret = -1; break; } @@ -88,8 +90,8 @@ accept(int fd, struct sockaddr * name, int *namelen) ret = -1; } /* - * If the parent socket was blocking, make sure that - * the new socket is also set blocking here (as the + * If the parent socket was blocking, make sure that + * the new socket is also set blocking here (as the * call to _thread_fd_table_init() above will always * set the new socket flags to non-blocking, as that * will be the inherited state of the new socket. diff --git a/lib/libc_r/uthread/uthread_bind.c b/lib/libc_r/uthread/uthread_bind.c index 1f7bbec..adc30a1 100644 --- a/lib/libc_r/uthread/uthread_bind.c +++ b/lib/libc_r/uthread/uthread_bind.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/libc_r/uthread/uthread_close.c b/lib/libc_r/uthread/uthread_close.c index 26a8fbf..5678e2e 100644 --- a/lib/libc_r/uthread/uthread_close.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_cond.c b/lib/libc_r/uthread/uthread_cond.c index e7fcc62..cb08853 100644 --- a/lib/libc_r/uthread/uthread_cond.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_connect.c b/lib/libc_r/uthread/uthread_connect.c index bf42db3..9ae03c5 100644 --- a/lib/libc_r/uthread/uthread_connect.c +++ b/lib/libc_r/uthread/uthread_connect.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/libc_r/uthread/uthread_create.c b/lib/libc_r/uthread/uthread_create.c index c9c6c9f..7603dd3 100644 --- a/lib/libc_r/uthread/uthread_create.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_detach.c b/lib/libc_r/uthread/uthread_detach.c index 57c073a..da456bf 100644 --- a/lib/libc_r/uthread/uthread_detach.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_dup.c b/lib/libc_r/uthread/uthread_dup.c index e6c4598..1017685 100644 --- a/lib/libc_r/uthread/uthread_dup.c +++ b/lib/libc_r/uthread/uthread_dup.c @@ -1,3 +1,35 @@ +/* + * Copyright (c) 1995-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 <unistd.h> #ifdef _THREAD_SAFE #include <pthread.h> diff --git a/lib/libc_r/uthread/uthread_dup2.c b/lib/libc_r/uthread/uthread_dup2.c index 6da78f7..e47230b 100644 --- a/lib/libc_r/uthread/uthread_dup2.c +++ b/lib/libc_r/uthread/uthread_dup2.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/libc_r/uthread/uthread_execve.c b/lib/libc_r/uthread/uthread_execve.c index d12b8ff..5f40e1c 100644 --- a/lib/libc_r/uthread/uthread_execve.c +++ b/lib/libc_r/uthread/uthread_execve.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 @@ -79,11 +79,8 @@ execve(const char *name, char *const * argv, char *const * envp) if (i == SIGKILL || i == SIGSTOP) { /* Don't do anything with these signals. */ } else { - /* - * Check if the running thread is ignoring this - * signal: - */ - if (_thread_run->act[i - 1].sa_handler == SIG_IGN) { + /* Check if ignoring this signal: */ + if (_thread_sigact[i - 1].sa_handler == SIG_IGN) { /* Continue to ignore this signal: */ act.sa_handler = SIG_IGN; } else { @@ -92,8 +89,8 @@ execve(const char *name, char *const * argv, char *const * envp) } /* Copy the mask and flags for this signal: */ - act.sa_mask = _thread_run->act[i - 1].sa_mask; - act.sa_flags = _thread_run->act[i - 1].sa_flags; + act.sa_mask = _thread_sigact[i - 1].sa_mask; + act.sa_flags = _thread_sigact[i - 1].sa_flags; /* Change the signal action for the process: */ _thread_sys_sigaction(i, &act, &oact); diff --git a/lib/libc_r/uthread/uthread_exit.c b/lib/libc_r/uthread/uthread_exit.c index 15bcfa3..4bc7da9 100644 --- a/lib/libc_r/uthread/uthread_exit.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_fchmod.c b/lib/libc_r/uthread/uthread_fchmod.c index ee5dfde..64c0558 100644 --- a/lib/libc_r/uthread/uthread_fchmod.c +++ b/lib/libc_r/uthread/uthread_fchmod.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/libc_r/uthread/uthread_fchown.c b/lib/libc_r/uthread/uthread_fchown.c index 52f65b8..a0e5c4c 100644 --- a/lib/libc_r/uthread/uthread_fchown.c +++ b/lib/libc_r/uthread/uthread_fchown.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/libc_r/uthread/uthread_fcntl.c b/lib/libc_r/uthread/uthread_fcntl.c index f83ee50..9a50c1c 100644 --- a/lib/libc_r/uthread/uthread_fcntl.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_fd.c b/lib/libc_r/uthread/uthread_fd.c index 541f92f..19b985f 100644 --- a/lib/libc_r/uthread/uthread_fd.c +++ b/lib/libc_r/uthread/uthread_fd.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_fd.c,v 1.4 1997/04/01 22:49:58 jb Exp $ + * $Id: uthread_fd.c,v 1.5 1998/02/13 01:27:32 julian Exp $ * */ #include <errno.h> @@ -39,6 +39,9 @@ #include <pthread.h> #include "pthread_private.h" +/* Static variables: */ +static long fd_table_lock = 0; + /* * This function *must* return -1 and set the thread specific errno * as a system call. This is because the error return from this @@ -50,10 +53,9 @@ int _thread_fd_table_init(int fd) { int ret = 0; - int status; - /* Block signals: */ - _thread_kern_sig_block(&status); + /* Lock the file descriptor table: */ + _spinlock(&fd_table_lock); /* Check if the file descriptor is out of range: */ if (fd < 0 || fd >= _thread_dtablesize) { @@ -75,12 +77,12 @@ _thread_fd_table_init(int fd) /* Return a bad file descriptor error: */ errno = EBADF; ret = -1; - } - else { + } else { /* Assume that the operation will succeed: */ ret = 0; /* Initialise the file locks: */ + _thread_fd_table[fd]->access_lock = 0; _thread_fd_table[fd]->r_owner = NULL; _thread_fd_table[fd]->w_owner = NULL; _thread_fd_table[fd]->r_fname = NULL; @@ -134,8 +136,8 @@ _thread_fd_table_init(int fd) } } - /* Unblock signals: */ - _thread_kern_sig_unblock(status); + /* Unlock the file descriptor table: */ + _atomic_unlock(&fd_table_lock); /* Return the completion status: */ return (ret); @@ -145,17 +147,19 @@ void _thread_fd_unlock(int fd, int lock_type) { int ret; - int status; - - /* Block signals while the file descriptor lock is tested: */ - _thread_kern_sig_block(&status); /* * Check that the file descriptor table is initialised for this * entry: */ - if ((ret = _thread_fd_table_init(fd)) != 0) { - } else { + if ((ret = _thread_fd_table_init(fd)) == 0) { + /* + * Lock the file descriptor table entry to prevent + * other threads for clashing with the current + * thread's accesses: + */ + _spinlock(&_thread_fd_table[fd]->access_lock); + /* Check if the running thread owns the read lock: */ if (_thread_fd_table[fd]->r_owner == _thread_run) { /* Check the file descriptor and lock types: */ @@ -232,12 +236,12 @@ _thread_fd_unlock(int fd, int lock_type) } } } - } - /* Unblock signals again: */ - _thread_kern_sig_unblock(status); + /* Unlock the file descriptor table entry: */ + _atomic_unlock(&_thread_fd_table[fd]->access_lock); - /* Nothing to return. */ + } + /* Nothing to return. */ return; } @@ -246,17 +250,19 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout, char *fname, int lineno) { int ret; - int status; - - /* Block signals while the file descriptor lock is tested: */ - _thread_kern_sig_block(&status); /* * Check that the file descriptor table is initialised for this * entry: */ - if ((ret = _thread_fd_table_init(fd)) != 0) { - } else { + if ((ret = _thread_fd_table_init(fd)) == 0) { + /* + * Lock the file descriptor table entry to prevent + * other threads for clashing with the current + * thread's accesses: + */ + _spinlock(&_thread_fd_table[fd]->access_lock); + /* Check the file descriptor and lock types: */ if (lock_type == FD_READ || lock_type == FD_RDWR) { /* @@ -290,6 +296,12 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout, _thread_kern_set_timeout(timeout); /* + * Unlock the file descriptor + * table entry: + */ + _atomic_unlock(&_thread_fd_table[fd]->access_lock); + + /* * Schedule this thread to wait on * the read lock. It will only be * woken when it becomes the next in @@ -301,11 +313,11 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout, _thread_kern_sched_state(PS_FDLR_WAIT, __FILE__, __LINE__); /* - * Block signals so that the file - * descriptor lock can again be - * tested: + * Lock the file descriptor + * table entry again: */ - _thread_kern_sig_block(NULL); + _spinlock(&_thread_fd_table[fd]->access_lock); + } else { /* * The running thread now owns the @@ -365,6 +377,12 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout, _thread_kern_set_timeout(timeout); /* + * Unlock the file descriptor + * table entry: + */ + _atomic_unlock(&_thread_fd_table[fd]->access_lock); + + /* * Schedule this thread to wait on * the write lock. It will only be * woken when it becomes the next in @@ -375,11 +393,10 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout, _thread_kern_sched_state(PS_FDLW_WAIT, __FILE__, __LINE__); /* - * Block signals so that the file - * descriptor lock can again be - * tested: + * Lock the file descriptor + * table entry again: */ - _thread_kern_sig_block(NULL); + _spinlock(&_thread_fd_table[fd]->access_lock); } else { /* * The running thread now owns the @@ -406,10 +423,10 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout, /* Increment the write lock count: */ _thread_fd_table[fd]->w_lockcount++; } - } - /* Unblock signals again: */ - _thread_kern_sig_unblock(status); + /* Unlock the file descriptor table entry: */ + _atomic_unlock(&_thread_fd_table[fd]->access_lock); + } /* Return the completion status: */ return (ret); diff --git a/lib/libc_r/uthread/uthread_file.c b/lib/libc_r/uthread/uthread_file.c index 6d88c0a..483db47 100644 --- a/lib/libc_r/uthread/uthread_file.c +++ b/lib/libc_r/uthread/uthread_file.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: uthread_file.c,v 1.2 1998/04/11 07:47:20 jb Exp $ * * POSIX stdio FILE locking functions. These assume that the locking * is only required at FILE structure level, not at file descriptor @@ -97,6 +97,9 @@ struct static_file_lock { /* Set to non-zero when initialisation is complete: */ static int init_done = 0; +/* Lock for accesses to the hash table: */ +static long hash_lock = 0; + /* * Find a lock structure for a FILE, return NULL if the file is * not locked: @@ -127,7 +130,7 @@ find_lock(int idx, FILE *fp) } /* - * Lock a file, assuming that there is no lock structure currently1 + * Lock a file, assuming that there is no lock structure currently * assigned to it. */ static @@ -185,8 +188,8 @@ _flockfile_debug(FILE * fp, char *fname, int lineno) /* Check if this is a real file: */ if (fp->_file >= 0) { - /* Block signals: */ - _thread_kern_sig_block(&status); + /* Lock the hash table: */ + _spinlock(&hash_lock); /* Check if the static array has not been initialised: */ if (!init_done) { @@ -205,6 +208,9 @@ _flockfile_debug(FILE * fp, char *fname, int lineno) */ p = do_lock(idx, fp); + /* Unlock the hash table: */ + _atomic_unlock(&hash_lock); + /* * The file is already locked, so check if the * running thread is the owner: @@ -217,6 +223,9 @@ _flockfile_debug(FILE * fp, char *fname, int lineno) * the file: */ p->count++; + + /* Unlock the hash table: */ + _atomic_unlock(&hash_lock); } else { /* * The file is locked for another thread. @@ -225,15 +234,12 @@ _flockfile_debug(FILE * fp, char *fname, int lineno) */ TAILQ_INSERT_TAIL(&p->l_head,_thread_run,qe); + /* Unlock the hash table: */ + _atomic_unlock(&hash_lock); + /* Wait on the FILE lock: */ _thread_kern_sched_state(PS_FILE_WAIT, fname, lineno); - - /* Block signals again: */ - _thread_kern_sig_block(NULL); } - - /* Unblock signals: */ - _thread_kern_sig_unblock(status); } return; } @@ -255,8 +261,8 @@ _ftrylockfile(FILE * fp) /* Check if this is a real file: */ if (fp->_file >= 0) { - /* Block signals: */ - _thread_kern_sig_block(&status); + /* Lock the hash table: */ + _spinlock(&hash_lock); /* Get a pointer to any existing lock for the file: */ if ((p = find_lock(idx, fp)) == NULL) { @@ -291,8 +297,9 @@ _ftrylockfile(FILE * fp) /* Return success: */ ret = 0; - /* Unblock signals: */ - _thread_kern_sig_unblock(status); + /* Unlock the hash table: */ + _atomic_unlock(&hash_lock); + } return (ret); } @@ -306,8 +313,8 @@ _funlockfile(FILE * fp) /* Check if this is a real file: */ if (fp->_file >= 0) { - /* Block signals: */ - _thread_kern_sig_block(&status); + /* Lock the hash table: */ + _spinlock(&hash_lock); /* * Get a pointer to the lock for the file and check that @@ -350,8 +357,8 @@ _funlockfile(FILE * fp) } } - /* Unblock signals: */ - _thread_kern_sig_unblock(status); + /* Unlock the hash table: */ + _atomic_unlock(&hash_lock); } return; } diff --git a/lib/libc_r/uthread/uthread_find_thread.c b/lib/libc_r/uthread/uthread_find_thread.c new file mode 100644 index 0000000..99e3023 --- /dev/null +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_flock.c b/lib/libc_r/uthread/uthread_flock.c index 4071b54..85dd2d9 100644 --- a/lib/libc_r/uthread/uthread_flock.c +++ b/lib/libc_r/uthread/uthread_flock.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/libc_r/uthread/uthread_fork.c b/lib/libc_r/uthread/uthread_fork.c index 29d6090..25d6703 100644 --- a/lib/libc_r/uthread/uthread_fork.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_fstat.c b/lib/libc_r/uthread/uthread_fstat.c index fc29e66..8c875ea 100644 --- a/lib/libc_r/uthread/uthread_fstat.c +++ b/lib/libc_r/uthread/uthread_fstat.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/libc_r/uthread/uthread_fstatfs.c b/lib/libc_r/uthread/uthread_fstatfs.c index 252c8b1..1216c82 100644 --- a/lib/libc_r/uthread/uthread_fstatfs.c +++ b/lib/libc_r/uthread/uthread_fstatfs.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/libc_r/uthread/uthread_fsync.c b/lib/libc_r/uthread/uthread_fsync.c index 51078e5..5658c73 100644 --- a/lib/libc_r/uthread/uthread_fsync.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_getdirentries.c b/lib/libc_r/uthread/uthread_getdirentries.c index b75e804..a1fd5b4 100644 --- a/lib/libc_r/uthread/uthread_getdirentries.c +++ b/lib/libc_r/uthread/uthread_getdirentries.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/libc_r/uthread/uthread_getpeername.c b/lib/libc_r/uthread/uthread_getpeername.c index d3bb4e1..3052bea2 100644 --- a/lib/libc_r/uthread/uthread_getpeername.c +++ b/lib/libc_r/uthread/uthread_getpeername.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/libc_r/uthread/uthread_getprio.c b/lib/libc_r/uthread/uthread_getprio.c index 85bd261..708b8f1 100644 --- a/lib/libc_r/uthread/uthread_getprio.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_getsockname.c b/lib/libc_r/uthread/uthread_getsockname.c index 5a8466b..df73fed 100644 --- a/lib/libc_r/uthread/uthread_getsockname.c +++ b/lib/libc_r/uthread/uthread_getsockname.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/libc_r/uthread/uthread_getsockopt.c b/lib/libc_r/uthread/uthread_getsockopt.c index fdedd90..49afa15 100644 --- a/lib/libc_r/uthread/uthread_getsockopt.c +++ b/lib/libc_r/uthread/uthread_getsockopt.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/libc_r/uthread/uthread_info.c b/lib/libc_r/uthread/uthread_info.c index 2909989..c2c3426 100644 --- a/lib/libc_r/uthread/uthread_info.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_init.c b/lib/libc_r/uthread/uthread_init.c index 78967f4..c267a2c 100644 --- a/lib/libc_r/uthread/uthread_init.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_ioctl.c b/lib/libc_r/uthread/uthread_ioctl.c index 676eff3..5a9b30c 100644 --- a/lib/libc_r/uthread/uthread_ioctl.c +++ b/lib/libc_r/uthread/uthread_ioctl.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 @@ -42,16 +42,12 @@ ioctl(int fd, unsigned long request,...) { int ret; int *op; - 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: */ - va_start(ap, request); + va_start(ap, request); switch( request) { case FIONBIO: @@ -65,18 +61,16 @@ ioctl(int fd, unsigned long request,...) ret = 0; break; default: - ret = _thread_sys_ioctl(fd, request, va_arg(ap, char *)); + ret = _thread_sys_ioctl(fd, request, va_arg(ap, char *)); break; } /* Free variable arguments: */ - va_end(ap); + va_end(ap); /* 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/libc_r/uthread/uthread_join.c b/lib/libc_r/uthread/uthread_join.c index 9e86a01..83b0c2a 100644 --- a/lib/libc_r/uthread/uthread_join.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_kern.c b/lib/libc_r/uthread/uthread_kern.c index 3b62422..36efc31 100644 --- a/lib/libc_r/uthread/uthread_kern.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_kill.c b/lib/libc_r/uthread/uthread_kill.c index eb2c6b7..f6e684b 100644 --- a/lib/libc_r/uthread/uthread_kill.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_listen.c b/lib/libc_r/uthread/uthread_listen.c index 453f25e..7c6f81d 100644 --- a/lib/libc_r/uthread/uthread_listen.c +++ b/lib/libc_r/uthread/uthread_listen.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/libc_r/uthread/uthread_mutex.c b/lib/libc_r/uthread/uthread_mutex.c index 9f92de9..fb737cf 100644 --- a/lib/libc_r/uthread/uthread_mutex.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_nanosleep.c b/lib/libc_r/uthread/uthread_nanosleep.c index 39c7dad..4ec7d3f 100644 --- a/lib/libc_r/uthread/uthread_nanosleep.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_open.c b/lib/libc_r/uthread/uthread_open.c index ef7a504..a538a75 100644 --- a/lib/libc_r/uthread/uthread_open.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_pipe.c b/lib/libc_r/uthread/uthread_pipe.c index 5bac6b3..48ef8ed 100644 --- a/lib/libc_r/uthread/uthread_pipe.c +++ b/lib/libc_r/uthread/uthread_pipe.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/libc_r/uthread/uthread_read.c b/lib/libc_r/uthread/uthread_read.c index 242014e..76df2cf 100644 --- a/lib/libc_r/uthread/uthread_read.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_readv.c b/lib/libc_r/uthread/uthread_readv.c index 3ea065e..10d1a43 100644 --- a/lib/libc_r/uthread/uthread_readv.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_recvfrom.c b/lib/libc_r/uthread/uthread_recvfrom.c index a3d6a7d..8d5d9db 100644 --- a/lib/libc_r/uthread/uthread_recvfrom.c +++ b/lib/libc_r/uthread/uthread_recvfrom.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 @@ -50,11 +50,13 @@ recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr * from, int * /* Set the timeout: */ _thread_kern_set_timeout(NULL); + _thread_run->interrupted = 0; _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__); /* Check if the wait was interrupted: */ - if (errno == EINTR) { + if (_thread_run->interrupted) { /* Return an error status: */ + errno = EINTR; ret = -1; break; } diff --git a/lib/libc_r/uthread/uthread_resume_np.c b/lib/libc_r/uthread/uthread_resume_np.c index 934df58..7c5f46a 100644 --- a/lib/libc_r/uthread/uthread_resume_np.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_select.c b/lib/libc_r/uthread/uthread_select.c index 7db3ed2..96df9c1 100644 --- a/lib/libc_r/uthread/uthread_select.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_sendto.c b/lib/libc_r/uthread/uthread_sendto.c index c7155c8..afac661 100644 --- a/lib/libc_r/uthread/uthread_sendto.c +++ b/lib/libc_r/uthread/uthread_sendto.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 @@ -50,7 +50,15 @@ sendto(int fd, const void *msg, size_t len, int flags, const struct sockaddr * t /* Set the timeout: */ _thread_kern_set_timeout(NULL); + _thread_run->interrupted = 0; _thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__); + + /* Check if the operation was interrupted: */ + if (_thread_run->interrupted) { + errno = EINTR; + ret = -1; + break; + } } else { ret = -1; break; diff --git a/lib/libc_r/uthread/uthread_seterrno.c b/lib/libc_r/uthread/uthread_seterrno.c index c4fe08b6..570807f 100644 --- a/lib/libc_r/uthread/uthread_seterrno.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_setprio.c b/lib/libc_r/uthread/uthread_setprio.c index 4b49ed0..dd89f15 100644 --- a/lib/libc_r/uthread/uthread_setprio.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_setsockopt.c b/lib/libc_r/uthread/uthread_setsockopt.c index be004a3..0fed796 100644 --- a/lib/libc_r/uthread/uthread_setsockopt.c +++ b/lib/libc_r/uthread/uthread_setsockopt.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/libc_r/uthread/uthread_shutdown.c b/lib/libc_r/uthread/uthread_shutdown.c index 5e06910..b698c67 100644 --- a/lib/libc_r/uthread/uthread_shutdown.c +++ b/lib/libc_r/uthread/uthread_shutdown.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/libc_r/uthread/uthread_sig.c b/lib/libc_r/uthread/uthread_sig.c index e73d5a2..1e5ee63 100644 --- a/lib/libc_r/uthread/uthread_sig.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_sigaction.c b/lib/libc_r/uthread/uthread_sigaction.c index dd08405..3538f27 100644 --- a/lib/libc_r/uthread/uthread_sigaction.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_sigblock.c b/lib/libc_r/uthread/uthread_sigblock.c index bca32e1..fb1e085 100644 --- a/lib/libc_r/uthread/uthread_sigblock.c +++ b/lib/libc_r/uthread/uthread_sigblock.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/libc_r/uthread/uthread_sigmask.c b/lib/libc_r/uthread/uthread_sigmask.c index 94f64cb..23d6b7f 100644 --- a/lib/libc_r/uthread/uthread_sigmask.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_sigprocmask.c b/lib/libc_r/uthread/uthread_sigprocmask.c index b4a8d84..81b602f 100644 --- a/lib/libc_r/uthread/uthread_sigprocmask.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_sigsetmask.c b/lib/libc_r/uthread/uthread_sigsetmask.c index 2780670..bf48d7b 100644 --- a/lib/libc_r/uthread/uthread_sigsetmask.c +++ b/lib/libc_r/uthread/uthread_sigsetmask.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/libc_r/uthread/uthread_sigsuspend.c b/lib/libc_r/uthread/uthread_sigsuspend.c index 14cf74b..f7a7b12 100644 --- a/lib/libc_r/uthread/uthread_sigsuspend.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_sigwait.c b/lib/libc_r/uthread/uthread_sigwait.c index 4f95190..63c7093 100644 --- a/lib/libc_r/uthread/uthread_sigwait.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_socket.c b/lib/libc_r/uthread/uthread_socket.c index bfc657d..7b5fe00 100644 --- a/lib/libc_r/uthread/uthread_socket.c +++ b/lib/libc_r/uthread/uthread_socket.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/libc_r/uthread/uthread_socketpair.c b/lib/libc_r/uthread/uthread_socketpair.c index 2c8761b..c64d67a 100644 --- a/lib/libc_r/uthread/uthread_socketpair.c +++ b/lib/libc_r/uthread/uthread_socketpair.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_socketpair.c,v 1.3 1997/04/01 22:52:43 jb Exp $ * */ #include <sys/types.h> diff --git a/lib/libc_r/uthread/uthread_spec.c b/lib/libc_r/uthread/uthread_spec.c index 7ff9054..dc493dd 100644 --- a/lib/libc_r/uthread/uthread_spec.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_spinlock.c b/lib/libc_r/uthread/uthread_spinlock.c new file mode 100644 index 0000000..b2fe269 --- /dev/null +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_suspend_np.c b/lib/libc_r/uthread/uthread_suspend_np.c index d065b73..871683a 100644 --- a/lib/libc_r/uthread/uthread_suspend_np.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_wait4.c b/lib/libc_r/uthread/uthread_wait4.c index 0a721af4f..dda8aee 100644 --- a/lib/libc_r/uthread/uthread_wait4.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_write.c b/lib/libc_r/uthread/uthread_write.c index e86e71b..f8be7da 100644 --- a/lib/libc_r/uthread/uthread_write.c +++ b/lib/libc_r/uthread/uthread_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/libc_r/uthread/uthread_writev.c b/lib/libc_r/uthread/uthread_writev.c index 56e1872..f3badec 100644 --- a/lib/libc_r/uthread/uthread_writev.c +++ b/lib/libc_r/uthread/uthread_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; } diff --git a/lib/libkse/thread/Makefile.inc b/lib/libkse/thread/Makefile.inc index 4f1b308..924453f 100644 --- a/lib/libkse/thread/Makefile.inc +++ b/lib/libkse/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/libkse/thread/thr_close.c b/lib/libkse/thread/thr_close.c index 26a8fbf..5678e2e 100644 --- a/lib/libkse/thread/thr_close.c +++ b/lib/libkse/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/libkse/thread/thr_cond.c b/lib/libkse/thread/thr_cond.c index e7fcc62..cb08853 100644 --- a/lib/libkse/thread/thr_cond.c +++ b/lib/libkse/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/libkse/thread/thr_create.c b/lib/libkse/thread/thr_create.c index c9c6c9f..7603dd3 100644 --- a/lib/libkse/thread/thr_create.c +++ b/lib/libkse/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/libkse/thread/thr_detach.c b/lib/libkse/thread/thr_detach.c index 57c073a..da456bf 100644 --- a/lib/libkse/thread/thr_detach.c +++ b/lib/libkse/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/libkse/thread/thr_exit.c b/lib/libkse/thread/thr_exit.c index 15bcfa3..4bc7da9 100644 --- a/lib/libkse/thread/thr_exit.c +++ b/lib/libkse/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/libkse/thread/thr_fcntl.c b/lib/libkse/thread/thr_fcntl.c index f83ee50..9a50c1c 100644 --- a/lib/libkse/thread/thr_fcntl.c +++ b/lib/libkse/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/libkse/thread/thr_find_thread.c b/lib/libkse/thread/thr_find_thread.c new file mode 100644 index 0000000..99e3023 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_fork.c b/lib/libkse/thread/thr_fork.c index 29d6090..25d6703 100644 --- a/lib/libkse/thread/thr_fork.c +++ b/lib/libkse/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/libkse/thread/thr_fsync.c b/lib/libkse/thread/thr_fsync.c index 51078e5..5658c73 100644 --- a/lib/libkse/thread/thr_fsync.c +++ b/lib/libkse/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/libkse/thread/thr_getprio.c b/lib/libkse/thread/thr_getprio.c index 85bd261..708b8f1 100644 --- a/lib/libkse/thread/thr_getprio.c +++ b/lib/libkse/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/libkse/thread/thr_info.c b/lib/libkse/thread/thr_info.c index 2909989..c2c3426 100644 --- a/lib/libkse/thread/thr_info.c +++ b/lib/libkse/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/libkse/thread/thr_init.c b/lib/libkse/thread/thr_init.c index 78967f4..c267a2c 100644 --- a/lib/libkse/thread/thr_init.c +++ b/lib/libkse/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/libkse/thread/thr_join.c b/lib/libkse/thread/thr_join.c index 9e86a01..83b0c2a 100644 --- a/lib/libkse/thread/thr_join.c +++ b/lib/libkse/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/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c index 3b62422..36efc31 100644 --- a/lib/libkse/thread/thr_kern.c +++ b/lib/libkse/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/libkse/thread/thr_kill.c b/lib/libkse/thread/thr_kill.c index eb2c6b7..f6e684b 100644 --- a/lib/libkse/thread/thr_kill.c +++ b/lib/libkse/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/libkse/thread/thr_mutex.c b/lib/libkse/thread/thr_mutex.c index 9f92de9..fb737cf 100644 --- a/lib/libkse/thread/thr_mutex.c +++ b/lib/libkse/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/libkse/thread/thr_nanosleep.c b/lib/libkse/thread/thr_nanosleep.c index 39c7dad..4ec7d3f 100644 --- a/lib/libkse/thread/thr_nanosleep.c +++ b/lib/libkse/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/libkse/thread/thr_open.c b/lib/libkse/thread/thr_open.c index ef7a504..a538a75 100644 --- a/lib/libkse/thread/thr_open.c +++ b/lib/libkse/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/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h index 5ceeaba..5f0f3a8 100644 --- a/lib/libkse/thread/thr_private.h +++ b/lib/libkse/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/libkse/thread/thr_read.c b/lib/libkse/thread/thr_read.c index 242014e..76df2cf 100644 --- a/lib/libkse/thread/thr_read.c +++ b/lib/libkse/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/libkse/thread/thr_readv.c b/lib/libkse/thread/thr_readv.c index 3ea065e..10d1a43 100644 --- a/lib/libkse/thread/thr_readv.c +++ b/lib/libkse/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/libkse/thread/thr_resume_np.c b/lib/libkse/thread/thr_resume_np.c index 934df58..7c5f46a 100644 --- a/lib/libkse/thread/thr_resume_np.c +++ b/lib/libkse/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/libkse/thread/thr_select.c b/lib/libkse/thread/thr_select.c index 7db3ed2..96df9c1 100644 --- a/lib/libkse/thread/thr_select.c +++ b/lib/libkse/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/libkse/thread/thr_seterrno.c b/lib/libkse/thread/thr_seterrno.c index c4fe08b6..570807f 100644 --- a/lib/libkse/thread/thr_seterrno.c +++ b/lib/libkse/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/libkse/thread/thr_setprio.c b/lib/libkse/thread/thr_setprio.c index 4b49ed0..dd89f15 100644 --- a/lib/libkse/thread/thr_setprio.c +++ b/lib/libkse/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/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c index e73d5a2..1e5ee63 100644 --- a/lib/libkse/thread/thr_sig.c +++ b/lib/libkse/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/libkse/thread/thr_sigaction.c b/lib/libkse/thread/thr_sigaction.c index dd08405..3538f27 100644 --- a/lib/libkse/thread/thr_sigaction.c +++ b/lib/libkse/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/libkse/thread/thr_sigmask.c b/lib/libkse/thread/thr_sigmask.c index 94f64cb..23d6b7f 100644 --- a/lib/libkse/thread/thr_sigmask.c +++ b/lib/libkse/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/libkse/thread/thr_sigprocmask.c b/lib/libkse/thread/thr_sigprocmask.c index b4a8d84..81b602f 100644 --- a/lib/libkse/thread/thr_sigprocmask.c +++ b/lib/libkse/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/libkse/thread/thr_sigsuspend.c b/lib/libkse/thread/thr_sigsuspend.c index 14cf74b..f7a7b12 100644 --- a/lib/libkse/thread/thr_sigsuspend.c +++ b/lib/libkse/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/libkse/thread/thr_sigwait.c b/lib/libkse/thread/thr_sigwait.c index 4f95190..63c7093 100644 --- a/lib/libkse/thread/thr_sigwait.c +++ b/lib/libkse/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/libkse/thread/thr_spec.c b/lib/libkse/thread/thr_spec.c index 7ff9054..dc493dd 100644 --- a/lib/libkse/thread/thr_spec.c +++ b/lib/libkse/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/libkse/thread/thr_spinlock.c b/lib/libkse/thread/thr_spinlock.c new file mode 100644 index 0000000..b2fe269 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_suspend_np.c b/lib/libkse/thread/thr_suspend_np.c index d065b73..871683a 100644 --- a/lib/libkse/thread/thr_suspend_np.c +++ b/lib/libkse/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/libkse/thread/thr_wait4.c b/lib/libkse/thread/thr_wait4.c index 0a721af4f..dda8aee 100644 --- a/lib/libkse/thread/thr_wait4.c +++ b/lib/libkse/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/libkse/thread/thr_write.c b/lib/libkse/thread/thr_write.c index e86e71b..f8be7da 100644 --- a/lib/libkse/thread/thr_write.c +++ b/lib/libkse/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/libkse/thread/thr_writev.c b/lib/libkse/thread/thr_writev.c index 56e1872..f3badec 100644 --- a/lib/libkse/thread/thr_writev.c +++ b/lib/libkse/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; } 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; } |