diff options
author | Marco S Hyman <marc@cvs.openbsd.org> | 2002-10-30 19:11:57 +0000 |
---|---|---|
committer | Marco S Hyman <marc@cvs.openbsd.org> | 2002-10-30 19:11:57 +0000 |
commit | 5b3d505b4e254da05bc3ffa547a6e9f65798bf3d (patch) | |
tree | 0ceb12589bb4b87bde661f6909649e57f1b16c15 | |
parent | 2051a2b3c5d4ccdbc313073e0e948ca64da5d8e7 (diff) |
signal handling changes. This corrects several signal
handling errors in the threads library. Most of the libc_r regression
tests are now ok. thread specific kill semantics are still not correct.
No negative comments after posting to tech@ a week or so ago.
siginfo test fails on sparc64 due to sparc64 oddity.
22 files changed, 506 insertions, 486 deletions
diff --git a/lib/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h index 23723ca68e0..88341872451 100644 --- a/lib/libc_r/uthread/pthread_private.h +++ b/lib/libc_r/uthread/pthread_private.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pthread_private.h,v 1.35 2002/02/21 20:57:41 fgsch Exp $ */ +/* $OpenBSD: pthread_private.h,v 1.36 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -1082,8 +1082,9 @@ __BEGIN_DECLS int _find_thread(pthread_t); struct pthread *_get_curthread(void); void _set_curthread(struct pthread *); -int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t); -void _dispatch_signals(void); +int _thread_create(pthread_t *, const pthread_attr_t *, + void *(*start_routine)(void *), void *,pthread_t); +void _dispatch_signals(pthread_t, struct sigcontext *); void _thread_signal(pthread_t, int); int _mutex_cv_lock(pthread_mutex_t *); int _mutex_cv_unlock(pthread_mutex_t *); @@ -1115,9 +1116,10 @@ void _thread_kern_sched_state_unlock(enum pthread_state state, void _thread_kern_set_timeout(const struct timespec *); void _thread_kern_sig_defer(void); void _thread_kern_sig_undefer(void); -void _thread_sig_handler(int, int, struct sigcontext *); +void _thread_sig_handler(int, siginfo_t *, struct sigcontext *); void _thread_sig_handle(int, struct sigcontext *); void _thread_sig_init(void); +void _thread_sig_process(int, struct sigcontext *); void _thread_start(void); void _thread_start_sig_handler(void); void _thread_seterrno(pthread_t,int); diff --git a/lib/libc_r/uthread/uthread_accept.c b/lib/libc_r/uthread/uthread_accept.c index 23197f8dadc..9c4b1d81eca 100644 --- a/lib/libc_r/uthread/uthread_accept.c +++ b/lib/libc_r/uthread/uthread_accept.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_accept.c,v 1.5 2001/08/21 19:24:53 fgsch Exp $ */ +/* $OpenBSD: uthread_accept.c,v 1.6 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -52,7 +52,8 @@ accept(int fd, struct sockaddr * name, socklen_t *namelen) /* Enter a loop to wait for a connection request: */ while ((ret = _thread_sys_accept(fd, name, namelen)) < 0) { /* Check if the socket is to block: */ - if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) { + if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && + (errno == EWOULDBLOCK || errno == EAGAIN)) { /* Save the socket file descriptor: */ curthread->data.fd.fd = fd; curthread->data.fd.fname = __FILE__; @@ -63,7 +64,8 @@ accept(int fd, struct sockaddr * name, socklen_t *namelen) curthread->interrupted = 0; /* Schedule the next thread: */ - _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__); + _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, + __LINE__); /* Check if the wait was interrupted: */ if (curthread->interrupted) { @@ -81,26 +83,19 @@ accept(int fd, struct sockaddr * name, socklen_t *namelen) } } - /* Check for errors: */ - if (ret < 0) { - } - /* Initialise the file descriptor table for the new socket: */ - else if (_thread_fd_table_init(ret) != 0) { - /* Quietly close the socket: */ - _thread_sys_close(ret); - - /* Return an error: */ - ret = -1; - } - /* - * 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. + /* + * If no errors initialize the file descriptor table + * for the new socket. Turn on blocking mode in the + * child if it is on in the parent. This is done + * as _thread_fd_table_init *may* have turned the flag on. */ - if((ret > 0) && (_thread_fd_table[fd]->flags & O_NONBLOCK) == 0) - _thread_fd_table[ret]->flags &= ~O_NONBLOCK; + if (ret != -1) + if (_thread_fd_table_init(ret) != 0) { + /* Quietly close the socket: */ + _thread_sys_close(ret); + ret = -1; + } else if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0) + _thread_fd_table[ret]->flags &= ~O_NONBLOCK; /* Unlock the file descriptor: */ _FD_UNLOCK(fd, FD_RDWR); diff --git a/lib/libc_r/uthread/uthread_exit.c b/lib/libc_r/uthread/uthread_exit.c index a7a0c60a267..27ed0903ea6 100644 --- a/lib/libc_r/uthread/uthread_exit.c +++ b/lib/libc_r/uthread/uthread_exit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_exit.c,v 1.15 2001/12/19 02:02:52 fgsch Exp $ */ +/* $OpenBSD: uthread_exit.c,v 1.16 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -132,7 +132,7 @@ _thread_exit(const char *fname, int lineno, const char *string) /* Set the abort handler to default (dump core) */ sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; + sa.sa_flags = SA_SIGINFO; (void)_thread_sys_sigaction(SIGABRT, &sa, NULL); (void)_thread_sys_kill(_thread_sys_getpid(), SIGABRT); for (;;) ; diff --git a/lib/libc_r/uthread/uthread_init.c b/lib/libc_r/uthread/uthread_init.c index d9f398c381b..803e46e1fe8 100644 --- a/lib/libc_r/uthread/uthread_init.c +++ b/lib/libc_r/uthread/uthread_init.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_init.c,v 1.21 2002/02/21 20:57:41 fgsch Exp $ */ +/* $OpenBSD: uthread_init.c,v 1.22 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -222,7 +222,7 @@ _thread_init(void) /* Initialise the global signal action structure: */ sigfillset(&act.sa_mask); act.sa_handler = (void (*) ()) _thread_sig_handler; - act.sa_flags = 0; + act.sa_flags = SA_SIGINFO; /* Clear pending signals for the process: */ sigemptyset(&_process_sigpending); @@ -263,6 +263,9 @@ _thread_init(void) */ PANIC("Cannot initialize signal handler"); } + _thread_sigact[_SCHED_SIGNAL - 1].sa_flags = SA_SIGINFO; + _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO; + _thread_sigact[SIGCHLD - 1].sa_flags = SA_SIGINFO; /* Get the process signal mask: */ _thread_sys_sigprocmask(SIG_SETMASK, NULL, &_process_sigmask); diff --git a/lib/libc_r/uthread/uthread_kern.c b/lib/libc_r/uthread/uthread_kern.c index da3c91ff933..f7db1f0871b 100644 --- a/lib/libc_r/uthread/uthread_kern.c +++ b/lib/libc_r/uthread/uthread_kern.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_kern.c,v 1.21 2002/02/21 20:57:41 fgsch Exp $ */ +/* $OpenBSD: uthread_kern.c,v 1.22 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -50,15 +50,19 @@ #include <pthread.h> #include "pthread_private.h" -/* Static function prototype definitions: */ -static void -thread_kern_poll(int wait_reqd); - -static void -dequeue_signals(void); +#if defined(PTHREAD_TRACE_KERN) +#define PTHREAD_TRACE(x) _thread_sys_write(-1, (void*) x, 0) +#else +#define PTHREAD_TRACE(x) +#endif -static inline void -thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in); +/* + * local functions. Do NOT make these static... we want so see them in + * crash dumps. + */ +void _thread_kern_poll(int); +void _dequeue_signals(void); +inline void _thread_run_switch_hook(pthread_t, pthread_t); /* Static variables: */ static int last_tick = 0; @@ -68,6 +72,7 @@ _thread_kern_sched_sig(void) { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(1); curthread->check_pending = 1; _thread_kern_sched(NULL); } @@ -83,6 +88,8 @@ _thread_kern_sched(struct sigcontext * scp) int add_to_prioq; pthread_t old_thread_run; + PTHREAD_TRACE(2); + /* * Flag the pthread kernel as executing scheduler code * to avoid a scheduler signal from interrupting this @@ -291,7 +298,7 @@ _thread_kern_sched(struct sigcontext * scp) * Poll file descriptors to update the state of threads * waiting on file I/O where data may be available: */ - thread_kern_poll(0); + _thread_kern_poll(0); /* Protect the scheduling queues: */ _queue_signals = 1; @@ -409,7 +416,7 @@ _thread_kern_sched(struct sigcontext * scp) * There are no threads ready to run, so wait until * something happens that changes this condition: */ - thread_kern_poll(1); + _thread_kern_poll(1); /* * This process' usage will likely be very small @@ -445,7 +452,7 @@ _thread_kern_sched(struct sigcontext * scp) /* Protect the scheduling queues again: */ _queue_signals = 1; - dequeue_signals(); + _dequeue_signals(); /* * Check for a higher priority thread that @@ -519,7 +526,7 @@ _thread_kern_sched(struct sigcontext * scp) */ if ((_sched_switch_hook != NULL) && (_last_user_thread != curthread)) { - thread_run_switch_hook(_last_user_thread, + _thread_run_switch_hook(_last_user_thread, curthread); } @@ -543,7 +550,7 @@ _thread_kern_sched(struct sigcontext * scp) if (_sched_switch_hook != NULL) { /* Run the installed switch hook: */ - thread_run_switch_hook(_last_user_thread, + _thread_run_switch_hook(_last_user_thread, curthread); } @@ -569,6 +576,7 @@ _thread_kern_sched_state(enum pthread_state state, char *fname, int lineno) { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(3); /* * Flag the pthread kernel as executing scheduler code * to avoid a scheduler signal from interrupting this @@ -597,6 +605,8 @@ _thread_kern_sched_state_unlock(enum pthread_state state, { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(4); + /* * Flag the pthread kernel as executing scheduler code * to avoid a scheduler signal from interrupting this @@ -622,8 +632,8 @@ _thread_kern_sched_state_unlock(enum pthread_state state, _thread_kern_sched(NULL); } -static void -thread_kern_poll(int wait_reqd) +void +_thread_kern_poll(int wait_reqd) { int count = 0; int i, found; @@ -634,6 +644,8 @@ thread_kern_poll(int wait_reqd) struct timespec ts; struct timeval tv; + PTHREAD_TRACE(5); + /* Check if the caller wants to wait: */ if (wait_reqd == 0) { timeout_ms = 0; @@ -683,8 +695,7 @@ thread_kern_poll(int wait_reqd) if (_sigq_check_reqd != 0) { /* Reset flag before handling queued signals: */ _sigq_check_reqd = 0; - - dequeue_signals(); + _dequeue_signals(); } /* @@ -809,8 +820,7 @@ thread_kern_poll(int wait_reqd) if (_sigq_check_reqd != 0) { /* Reset flag before handling signals: */ _sigq_check_reqd = 0; - - dequeue_signals(); + _dequeue_signals(); } } @@ -943,10 +953,7 @@ thread_kern_poll(int wait_reqd) /* Protect the scheduling queues: */ _queue_signals = 1; - - dequeue_signals(); - - /* Unprotect the scheduling queues: */ + _dequeue_signals(); _queue_signals = 0; } } @@ -958,6 +965,8 @@ _thread_kern_set_timeout(const struct timespec * timeout) struct timespec current_time; struct timeval tv; + PTHREAD_TRACE(6); + /* Reset the timeout flag for the running thread: */ curthread->timeout = 0; @@ -998,6 +1007,8 @@ _thread_kern_sig_defer(void) { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(7); + /* Allow signal deferral to be recursive. */ curthread->sig_defer_count++; } @@ -1007,6 +1018,8 @@ _thread_kern_sig_undefer(void) { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(8); + /* * Perform checks to yield only if we are about to undefer * signals. @@ -1047,12 +1060,14 @@ _thread_kern_sig_undefer(void) } } -static void -dequeue_signals(void) +void +_dequeue_signals(void) { char bufr[128]; int i, num; + PTHREAD_TRACE(9); + /* * Enter a loop to read and handle queued signals from the * pthread kernel pipe: @@ -1072,7 +1087,7 @@ dequeue_signals(void) } else { /* Handle this signal: */ - _thread_sig_handle((int) bufr[i], NULL); + _thread_sig_process((int) bufr[i], NULL); } } } @@ -1085,12 +1100,14 @@ dequeue_signals(void) } } -static inline void -thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in) +inline void +_thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in) { pthread_t tid_out = thread_out; pthread_t tid_in = thread_in; + PTHREAD_TRACE(10); + if ((tid_out != NULL) && (tid_out->flags & PTHREAD_FLAGS_PRIVATE) != 0) tid_out = NULL; diff --git a/lib/libc_r/uthread/uthread_kill.c b/lib/libc_r/uthread/uthread_kill.c index 172d3817513..59d78b80ebf 100644 --- a/lib/libc_r/uthread/uthread_kill.c +++ b/lib/libc_r/uthread/uthread_kill.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_kill.c,v 1.7 1999/11/25 07:01:37 d Exp $ */ +/* $OpenBSD: uthread_kill.c,v 1.8 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -38,6 +38,12 @@ #include <pthread.h> #include "pthread_private.h" +/* + * XXX THIS IS WRONG! The signal has to either come through the OS to + * get the proper siginfo, context, etc., or we need to gen up a + * siginfo (assuming needed). Signal reset and other semantics + * also need to be obeyed. + */ int pthread_kill(pthread_t pthread, int sig) { @@ -75,7 +81,6 @@ pthread_kill(pthread_t pthread, int sig) /* Return the signal number: */ pthread->signo = sig; } - /* Increment the pending signal count: */ sigaddset(&pthread->sigpend,sig); break; @@ -88,7 +93,6 @@ pthread_kill(pthread_t pthread, int sig) /* Return the signal number: */ pthread->signo = sig; } else - /* Increment the pending signal count. */ sigaddset(&pthread->sigpend,sig); break; @@ -111,7 +115,6 @@ pthread_kill(pthread_t pthread, int sig) /* Return the signal number: */ pthread->signo = sig; } else { - /* Increment the pending signal count: */ sigaddset(&pthread->sigpend,sig); } break; @@ -144,7 +147,7 @@ pthread_kill(pthread_t pthread, int sig) /* * Dispatch the signal via the custom signal - * handler: + * handler: ;;; what about SA_SIGINFO??? */ (*(_thread_sigact[sig - 1].sa_handler))(sig); diff --git a/lib/libc_r/uthread/uthread_mutex.c b/lib/libc_r/uthread/uthread_mutex.c index 41f510c37e4..79bd3573379 100644 --- a/lib/libc_r/uthread/uthread_mutex.c +++ b/lib/libc_r/uthread/uthread_mutex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_mutex.c,v 1.14 2002/01/23 23:11:57 fgsch Exp $ */ +/* $OpenBSD: uthread_mutex.c,v 1.15 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -715,27 +715,6 @@ pthread_mutex_lock(pthread_mutex_t *mutex) } int -_pthread_mutex_lock(pthread_mutex_t *mutex) -{ - int ret = 0; - - if (_thread_initial == NULL) - _thread_init(); - - if (mutex == NULL) - ret = EINVAL; - - /* - * If the mutex is statically initialized, perform the dynamic - * initialization marking it private (delete safe): - */ - else if ((*mutex != NULL) || ((ret = init_static_private(mutex)) == 0)) - ret = mutex_lock_common(mutex); - - return (ret); -} - -int pthread_mutex_unlock(pthread_mutex_t * mutex) { return (mutex_unlock_common(mutex, /* add reference */ 0)); diff --git a/lib/libc_r/uthread/uthread_sig.c b/lib/libc_r/uthread/uthread_sig.c index 48f360f3ea3..be4e5c8323c 100644 --- a/lib/libc_r/uthread/uthread_sig.c +++ b/lib/libc_r/uthread/uthread_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_sig.c,v 1.13 2002/10/07 22:36:04 marc Exp $ */ +/* $OpenBSD: uthread_sig.c,v 1.14 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -41,10 +41,10 @@ #include "pthread_private.h" /* Static variables: */ -static spinlock_t signal_lock = _SPINLOCK_INITIALIZER; -unsigned int pending_sigs[NSIG]; -unsigned int handled_sigs[NSIG]; -int volatile check_pending = 0; +static _spinlock_lock_t signal_lock = _SPINLOCK_UNLOCKED; +siginfo_t info_queue[NSIG]; +volatile sig_atomic_t pending_sigs[NSIG]; +volatile sig_atomic_t check_pending = 0; /* Initialize signal handling facility: */ void @@ -52,113 +52,142 @@ _thread_sig_init(void) { int i; - /* Clear pending and handled signal counts: */ + /* Clear local state */ for (i = 1; i < NSIG; i++) { pending_sigs[i - 1] = 0; - handled_sigs[i - 1] = 0; } /* Clear the lock: */ - signal_lock.access_lock = 0; + signal_lock = _SPINLOCK_UNLOCKED; } +/* + * Process a pending signal unless it is already in progress. If the + * SA_NODEFER flag is on, process it any way. + */ +void +_thread_sig_process(int sig, struct sigcontext * scp) +{ + int locked = 0; + + if (_atomic_lock(&signal_lock) == 0) + locked = 1; + + if (locked || _thread_sigact[sig - 1].sa_flags & SA_NODEFER) { + _thread_sig_handle(sig, scp); + pending_sigs[sig - 1] = 0; + } else + check_pending = 1; + if (locked) + signal_lock = _SPINLOCK_UNLOCKED; +} + +/* + * This is the only installed signal handler. In addition to handling + * thread kernel signals it is installed in place of application handlers + * and dispatches signals appropriately. + */ void -_thread_sig_handler(int sig, int code, struct sigcontext * scp) +_thread_sig_handler(int sig, siginfo_t *info, struct sigcontext * scp) { struct pthread *curthread = _get_curthread(); char c; int i; - /* Check if an interval timer signal: */ + /* + * save the info for this signal in a per signal queue of depth + * one. Per a POSIX suggestion, only the info for the first + * of multiple activations of the same signal is kept. + */ + if (pending_sigs[sig - 1] == 0) { + pending_sigs[sig - 1]++; + memcpy(&info_queue[sig - 1], info, sizeof *info); + } + if (sig == _SCHED_SIGNAL) { /* Update the scheduling clock: */ gettimeofday((struct timeval *)&_sched_tod, NULL); _sched_ticks++; - if (_thread_kern_in_sched != 0) { - /* - * The scheduler is already running; ignore this - * signal. - */ - } - /* - * Check if the scheduler interrupt has come when - * the currently running thread has deferred thread - * signals. - */ - else if (curthread->sig_defer_count > 0) - curthread->yield_on_sig_undefer = 1; - - else { - /* - * Schedule the next thread. This function is not - * expected to return because it will do a longjmp - * instead. - */ - _thread_kern_sched(scp); - - /* The scheduler currently returns here instead - of calling sigreturn due to a sparc sigreturn - bug. We should also return. That brings - us back to the sigtramp code which will - sigreturn to the context stored on the current - stack (which is the same as scp, above). - The code originally did this: - - PANIC("Returned to signal function from scheduler"); - */ - return; - } - } - /* - * Check if the kernel has been interrupted while the scheduler - * is accessing the scheduling queues or if there is a currently - * running thread that has deferred signals. - */ - else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) && - (curthread->sig_defer_count > 0))) { - /* Cast the signal number to a character variable: */ - c = sig; + /* only process signal when scheduler isn't running */ + if (_thread_kern_in_sched == 0) + if (curthread->sig_defer_count > 0) + /* + * The scheduler interrupt has come when + * the currently running thread has deferred + * thread signals. + */ + curthread->yield_on_sig_undefer = 1; + else { + /* Schedule the next thread. */ + _thread_kern_sched(scp); + /* + * The scheduler currently returns here instead + * of calling sigreturn due to a sparc sigreturn + * bug. We should also return. That brings + * us back to the sigtramp code which will + * sigreturn to the context stored on the + * current stack (which is the same as scp, + * above). The code originally did this: + * + * PANIC("Returned to signal function " + * "from scheduler"); + */ + return; + } + } else if ((_queue_signals != 0) || + ((_thread_kern_in_sched == 0) && + (curthread->sig_defer_count > 0))) { /* - * Write the signal number to the kernel pipe so that it will - * be ready to read when this signal handler returns. + * The kernel has been interrupted while the scheduler + * is accessing the scheduling queues or there is a currently + * running thread that has deferred signals. + * + * Cast the signal number to a character variable and Write + * the signal number to the kernel pipe so that it will be + * ready to read when this signal handler returns. */ + c = sig; _thread_sys_write(_thread_kern_pipe[1], &c, 1); - - /* Indicate that there are queued signals in the pipe. */ _sigq_check_reqd = 1; - } - else { - if (_atomic_lock(&signal_lock.access_lock)) { - /* There is another signal handler running: */ - pending_sigs[sig - 1]++; - check_pending = 1; + } else { + /* process the signal */ + _thread_sig_process(sig, scp); + /* + * process pending signals unless a current signal handler + * is running (signal_lock is locked). When locked + * the pending signals will be processed when the running + * handler returns. + */ + while (check_pending != 0 && _atomic_lock(&signal_lock) == 0) { + check_pending = 0; + signal_lock = _SPINLOCK_UNLOCKED; + for (i = 1; i < NSIG; i++) + if (pending_sigs[i - 1]) + _thread_sig_process(i, scp); } - else { - /* It's safe to handle the signal now. */ - _thread_sig_handle(sig, scp); + } - /* Reset the pending and handled count back to 0: */ - pending_sigs[sig - 1] = 0; - handled_sigs[sig - 1] = 0; +} - signal_lock.access_lock = 0; - } +/* + * Clear the pending flag for the given signal on all threads + */ +void +_clear_pending_flag(int sig) +{ + pthread_t pthread; - /* Enter a loop to process pending signals: */ - while ((check_pending != 0) && - (_atomic_lock(&signal_lock.access_lock) == 0)) { - check_pending = 0; - for (i = 1; i < NSIG; i++) { - if (pending_sigs[i - 1] > handled_sigs[i - 1]) - _thread_sig_handle(i, scp); - } - signal_lock.access_lock = 0; - } + TAILQ_FOREACH(pthread, &_thread_list, tle) { + sigdelset(&pthread->sigpend, sig); } } + +/* + * Process the given signal. + */ void _thread_sig_handle(int sig, struct sigcontext * scp) { @@ -166,51 +195,30 @@ _thread_sig_handle(int sig, struct sigcontext * scp) int i; pthread_t pthread, pthread_next; - /* Check if the signal requires a dump of thread information: */ if (sig == SIGINFO) - /* Dump thread information to file: */ - _thread_dump_info(); - - /* Check if an interval timer signal: */ - else if (sig == _SCHED_SIGNAL) { - /* - * This shouldn't ever occur (should this panic?). - */ - } else { - /* Check if a child has terminated: */ + _thread_dump_info(); /* Dump thread information */ + else if (sig == _SCHED_SIGNAL) + ; /* This shouldn't ever occur (should this panic?). */ + else { 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. */ - 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: - */ + for (i = 0; i < _thread_dtablesize; i++) + if (_thread_fd_table[i] != NULL) _thread_sys_fcntl(i, F_SETFL, _thread_fd_table[i]->flags | O_NONBLOCK); - } - } } /* * POSIX says that pending SIGCONT signals are * discarded when one of these signals occurs. */ - if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { - /* - * Enter a loop to discard pending SIGCONT - * signals: - */ - TAILQ_FOREACH(pthread, &_thread_list, tle) { - sigdelset(&pthread->sigpend,SIGCONT); - } - } + if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) + _clear_pending_flag(SIGCONT); /* * Enter a loop to process each thread in the waiting @@ -220,7 +228,7 @@ _thread_sig_handle(int sig, struct sigcontext * scp) * first one we find. */ for (pthread = TAILQ_FIRST(&_waitingq); - pthread != NULL; pthread = pthread_next) { + pthread != NULL; pthread = pthread_next) { /* * Grab the next thread before possibly destroying * the link entry. @@ -243,33 +251,33 @@ _thread_sig_handle(int sig, struct sigcontext * scp) } } - /* Check if the signal is not being ignored: */ - if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) + if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { /* - * Enter a loop to process each thread in the linked - * list: + * mark the signal as pending for each thread + * and give the thread a chance to update + * its state. */ TAILQ_FOREACH(pthread, &_thread_list, tle) { - pthread_t pthread_saved = curthread; - /* Current thread inside critical region? */ if (curthread->sig_defer_count > 0) pthread->sig_defer_count++; - _thread_signal(pthread,sig); - - /* - * Dispatch pending signals to the - * running thread: - */ - _set_curthread(pthread); - _dispatch_signals(); - _set_curthread(pthread_saved); - + if (curthread->sig_defer_count > 0) + pthread->sig_defer_count--; + } + /* + * give each thread a chance to dispatch pending + * signals. + */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { /* Current thread inside critical region? */ if (curthread->sig_defer_count > 0) + pthread->sig_defer_count++; + _dispatch_signals(pthread, scp); + if (curthread->sig_defer_count > 0) pthread->sig_defer_count--; } + } } /* Returns nothing. */ @@ -373,11 +381,14 @@ _thread_signal(pthread_t pthread, int sig) } } -/* Dispatch pending signals to the running thread: */ +/* + * possibly dispatch a signal to the given thread. + */ void -_dispatch_signals() +_dispatch_signals(pthread_t pthread, struct sigcontext * scp) { - struct pthread *curthread = _get_curthread(); + pthread_t pthread_saved; + struct sigaction act; void (*action)(int, siginfo_t *, void *); int i; @@ -385,7 +396,7 @@ _dispatch_signals() * Check if there are pending signals for the running * thread that aren't blocked: */ - if ((curthread->sigpend & ~curthread->sigmask) != 0) + if ((pthread->sigpend & ~pthread->sigmask) != 0) /* Look for all possible pending signals: */ for (i = 1; i < NSIG; i++) /* @@ -394,23 +405,28 @@ _dispatch_signals() */ if (_thread_sigact[i - 1].sa_handler != SIG_DFL && _thread_sigact[i - 1].sa_handler != SIG_IGN && - sigismember(&curthread->sigpend,i) && - !sigismember(&curthread->sigmask,i)) { + sigismember(&pthread->sigpend,i) && + !sigismember(&pthread->sigmask,i)) { action = _thread_sigact[i - 1].sa_sigaction; - - /* Clear the pending signal: */ - sigdelset(&curthread->sigpend,i); + _clear_pending_flag(i); /* clear custom handler if SA_RESETHAND set. */ if (_thread_sigact[i - 1].sa_flags & - SA_RESETHAND) - _thread_sigact[i - 1].sa_handler = - SIG_DFL; + SA_RESETHAND) { + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + sigaction(i, &act, NULL); + } + /* * Dispatch the signal via the custom signal - * handler: + * handler. */ - (*action)(i, 0, 0); + pthread_saved = _get_curthread(); + _set_curthread(pthread); + (*action)(i, &info_queue[i - 1], scp); + _set_curthread(pthread_saved); } } #endif diff --git a/lib/libc_r/uthread/uthread_sigaction.c b/lib/libc_r/uthread/uthread_sigaction.c index de0aaeb7bfe..61463f7ef99 100644 --- a/lib/libc_r/uthread/uthread_sigaction.c +++ b/lib/libc_r/uthread/uthread_sigaction.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_sigaction.c,v 1.5 1999/11/25 07:01:44 d Exp $ */ +/* $OpenBSD: uthread_sigaction.c,v 1.6 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -75,12 +75,9 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact) */ if (act != NULL && sig != _SCHED_SIGNAL && sig != SIGCHLD && sig != SIGINFO) { - /* Initialise the global signal action structure: */ gact.sa_mask = act->sa_mask; - gact.sa_flags = 0; - - /* Ensure the scheduling signal is masked: */ sigaddset(&gact.sa_mask, _SCHED_SIGNAL); + gact.sa_flags = act->sa_flags | SA_SIGINFO; /* * Check if the signal handler is being set to @@ -91,14 +88,12 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact) /* 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; + /* 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) + if (_thread_sys_sigaction(sig, &gact, NULL) != 0) ret = -1; } } diff --git a/lib/libc_r/uthread/uthread_signal.c b/lib/libc_r/uthread/uthread_signal.c index bd9b488b3d0..3cc2373fc64 100644 --- a/lib/libc_r/uthread/uthread_signal.c +++ b/lib/libc_r/uthread/uthread_signal.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_signal.c,v 1.4 1999/11/25 07:01:45 d Exp $ */ +/* $OpenBSD: uthread_signal.c,v 1.5 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -46,7 +46,7 @@ _thread_sys_signal(int s, sig_t a) /* Initialise the signal action structure: */ sigemptyset(&sa.sa_mask); sa.sa_handler = a; - sa.sa_flags = 0; + sa.sa_flags = SA_SIGINFO; /* Perform the sigaction syscall: */ if (_thread_sys_sigaction(s, &sa, &osa) < 0) { diff --git a/lib/libc_r/uthread/uthread_sigwait.c b/lib/libc_r/uthread/uthread_sigwait.c index 0d1bf618be1..b7b72c7ea09 100644 --- a/lib/libc_r/uthread/uthread_sigwait.c +++ b/lib/libc_r/uthread/uthread_sigwait.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_sigwait.c,v 1.10 2002/02/21 20:57:41 fgsch Exp $ */ +/* $OpenBSD: uthread_sigwait.c,v 1.11 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -53,7 +53,7 @@ sigwait(const sigset_t * set, int *sig) * Specify the thread kernel signal handler. */ act.sa_handler = (void (*) ()) _thread_sig_handler; - act.sa_flags = SA_RESTART; + act.sa_flags = SA_SIGINFO | SA_RESTART; /* Ensure the signal handler cannot be interrupted by other signals: */ sigfillset(&act.sa_mask); diff --git a/lib/libpthread/uthread/pthread_private.h b/lib/libpthread/uthread/pthread_private.h index 23723ca68e0..88341872451 100644 --- a/lib/libpthread/uthread/pthread_private.h +++ b/lib/libpthread/uthread/pthread_private.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pthread_private.h,v 1.35 2002/02/21 20:57:41 fgsch Exp $ */ +/* $OpenBSD: pthread_private.h,v 1.36 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -1082,8 +1082,9 @@ __BEGIN_DECLS int _find_thread(pthread_t); struct pthread *_get_curthread(void); void _set_curthread(struct pthread *); -int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t); -void _dispatch_signals(void); +int _thread_create(pthread_t *, const pthread_attr_t *, + void *(*start_routine)(void *), void *,pthread_t); +void _dispatch_signals(pthread_t, struct sigcontext *); void _thread_signal(pthread_t, int); int _mutex_cv_lock(pthread_mutex_t *); int _mutex_cv_unlock(pthread_mutex_t *); @@ -1115,9 +1116,10 @@ void _thread_kern_sched_state_unlock(enum pthread_state state, void _thread_kern_set_timeout(const struct timespec *); void _thread_kern_sig_defer(void); void _thread_kern_sig_undefer(void); -void _thread_sig_handler(int, int, struct sigcontext *); +void _thread_sig_handler(int, siginfo_t *, struct sigcontext *); void _thread_sig_handle(int, struct sigcontext *); void _thread_sig_init(void); +void _thread_sig_process(int, struct sigcontext *); void _thread_start(void); void _thread_start_sig_handler(void); void _thread_seterrno(pthread_t,int); diff --git a/lib/libpthread/uthread/uthread_accept.c b/lib/libpthread/uthread/uthread_accept.c index 23197f8dadc..9c4b1d81eca 100644 --- a/lib/libpthread/uthread/uthread_accept.c +++ b/lib/libpthread/uthread/uthread_accept.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_accept.c,v 1.5 2001/08/21 19:24:53 fgsch Exp $ */ +/* $OpenBSD: uthread_accept.c,v 1.6 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -52,7 +52,8 @@ accept(int fd, struct sockaddr * name, socklen_t *namelen) /* Enter a loop to wait for a connection request: */ while ((ret = _thread_sys_accept(fd, name, namelen)) < 0) { /* Check if the socket is to block: */ - if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) { + if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && + (errno == EWOULDBLOCK || errno == EAGAIN)) { /* Save the socket file descriptor: */ curthread->data.fd.fd = fd; curthread->data.fd.fname = __FILE__; @@ -63,7 +64,8 @@ accept(int fd, struct sockaddr * name, socklen_t *namelen) curthread->interrupted = 0; /* Schedule the next thread: */ - _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__); + _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, + __LINE__); /* Check if the wait was interrupted: */ if (curthread->interrupted) { @@ -81,26 +83,19 @@ accept(int fd, struct sockaddr * name, socklen_t *namelen) } } - /* Check for errors: */ - if (ret < 0) { - } - /* Initialise the file descriptor table for the new socket: */ - else if (_thread_fd_table_init(ret) != 0) { - /* Quietly close the socket: */ - _thread_sys_close(ret); - - /* Return an error: */ - ret = -1; - } - /* - * 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. + /* + * If no errors initialize the file descriptor table + * for the new socket. Turn on blocking mode in the + * child if it is on in the parent. This is done + * as _thread_fd_table_init *may* have turned the flag on. */ - if((ret > 0) && (_thread_fd_table[fd]->flags & O_NONBLOCK) == 0) - _thread_fd_table[ret]->flags &= ~O_NONBLOCK; + if (ret != -1) + if (_thread_fd_table_init(ret) != 0) { + /* Quietly close the socket: */ + _thread_sys_close(ret); + ret = -1; + } else if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0) + _thread_fd_table[ret]->flags &= ~O_NONBLOCK; /* Unlock the file descriptor: */ _FD_UNLOCK(fd, FD_RDWR); diff --git a/lib/libpthread/uthread/uthread_exit.c b/lib/libpthread/uthread/uthread_exit.c index a7a0c60a267..27ed0903ea6 100644 --- a/lib/libpthread/uthread/uthread_exit.c +++ b/lib/libpthread/uthread/uthread_exit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_exit.c,v 1.15 2001/12/19 02:02:52 fgsch Exp $ */ +/* $OpenBSD: uthread_exit.c,v 1.16 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -132,7 +132,7 @@ _thread_exit(const char *fname, int lineno, const char *string) /* Set the abort handler to default (dump core) */ sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; + sa.sa_flags = SA_SIGINFO; (void)_thread_sys_sigaction(SIGABRT, &sa, NULL); (void)_thread_sys_kill(_thread_sys_getpid(), SIGABRT); for (;;) ; diff --git a/lib/libpthread/uthread/uthread_init.c b/lib/libpthread/uthread/uthread_init.c index d9f398c381b..803e46e1fe8 100644 --- a/lib/libpthread/uthread/uthread_init.c +++ b/lib/libpthread/uthread/uthread_init.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_init.c,v 1.21 2002/02/21 20:57:41 fgsch Exp $ */ +/* $OpenBSD: uthread_init.c,v 1.22 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -222,7 +222,7 @@ _thread_init(void) /* Initialise the global signal action structure: */ sigfillset(&act.sa_mask); act.sa_handler = (void (*) ()) _thread_sig_handler; - act.sa_flags = 0; + act.sa_flags = SA_SIGINFO; /* Clear pending signals for the process: */ sigemptyset(&_process_sigpending); @@ -263,6 +263,9 @@ _thread_init(void) */ PANIC("Cannot initialize signal handler"); } + _thread_sigact[_SCHED_SIGNAL - 1].sa_flags = SA_SIGINFO; + _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO; + _thread_sigact[SIGCHLD - 1].sa_flags = SA_SIGINFO; /* Get the process signal mask: */ _thread_sys_sigprocmask(SIG_SETMASK, NULL, &_process_sigmask); diff --git a/lib/libpthread/uthread/uthread_kern.c b/lib/libpthread/uthread/uthread_kern.c index da3c91ff933..f7db1f0871b 100644 --- a/lib/libpthread/uthread/uthread_kern.c +++ b/lib/libpthread/uthread/uthread_kern.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_kern.c,v 1.21 2002/02/21 20:57:41 fgsch Exp $ */ +/* $OpenBSD: uthread_kern.c,v 1.22 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -50,15 +50,19 @@ #include <pthread.h> #include "pthread_private.h" -/* Static function prototype definitions: */ -static void -thread_kern_poll(int wait_reqd); - -static void -dequeue_signals(void); +#if defined(PTHREAD_TRACE_KERN) +#define PTHREAD_TRACE(x) _thread_sys_write(-1, (void*) x, 0) +#else +#define PTHREAD_TRACE(x) +#endif -static inline void -thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in); +/* + * local functions. Do NOT make these static... we want so see them in + * crash dumps. + */ +void _thread_kern_poll(int); +void _dequeue_signals(void); +inline void _thread_run_switch_hook(pthread_t, pthread_t); /* Static variables: */ static int last_tick = 0; @@ -68,6 +72,7 @@ _thread_kern_sched_sig(void) { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(1); curthread->check_pending = 1; _thread_kern_sched(NULL); } @@ -83,6 +88,8 @@ _thread_kern_sched(struct sigcontext * scp) int add_to_prioq; pthread_t old_thread_run; + PTHREAD_TRACE(2); + /* * Flag the pthread kernel as executing scheduler code * to avoid a scheduler signal from interrupting this @@ -291,7 +298,7 @@ _thread_kern_sched(struct sigcontext * scp) * Poll file descriptors to update the state of threads * waiting on file I/O where data may be available: */ - thread_kern_poll(0); + _thread_kern_poll(0); /* Protect the scheduling queues: */ _queue_signals = 1; @@ -409,7 +416,7 @@ _thread_kern_sched(struct sigcontext * scp) * There are no threads ready to run, so wait until * something happens that changes this condition: */ - thread_kern_poll(1); + _thread_kern_poll(1); /* * This process' usage will likely be very small @@ -445,7 +452,7 @@ _thread_kern_sched(struct sigcontext * scp) /* Protect the scheduling queues again: */ _queue_signals = 1; - dequeue_signals(); + _dequeue_signals(); /* * Check for a higher priority thread that @@ -519,7 +526,7 @@ _thread_kern_sched(struct sigcontext * scp) */ if ((_sched_switch_hook != NULL) && (_last_user_thread != curthread)) { - thread_run_switch_hook(_last_user_thread, + _thread_run_switch_hook(_last_user_thread, curthread); } @@ -543,7 +550,7 @@ _thread_kern_sched(struct sigcontext * scp) if (_sched_switch_hook != NULL) { /* Run the installed switch hook: */ - thread_run_switch_hook(_last_user_thread, + _thread_run_switch_hook(_last_user_thread, curthread); } @@ -569,6 +576,7 @@ _thread_kern_sched_state(enum pthread_state state, char *fname, int lineno) { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(3); /* * Flag the pthread kernel as executing scheduler code * to avoid a scheduler signal from interrupting this @@ -597,6 +605,8 @@ _thread_kern_sched_state_unlock(enum pthread_state state, { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(4); + /* * Flag the pthread kernel as executing scheduler code * to avoid a scheduler signal from interrupting this @@ -622,8 +632,8 @@ _thread_kern_sched_state_unlock(enum pthread_state state, _thread_kern_sched(NULL); } -static void -thread_kern_poll(int wait_reqd) +void +_thread_kern_poll(int wait_reqd) { int count = 0; int i, found; @@ -634,6 +644,8 @@ thread_kern_poll(int wait_reqd) struct timespec ts; struct timeval tv; + PTHREAD_TRACE(5); + /* Check if the caller wants to wait: */ if (wait_reqd == 0) { timeout_ms = 0; @@ -683,8 +695,7 @@ thread_kern_poll(int wait_reqd) if (_sigq_check_reqd != 0) { /* Reset flag before handling queued signals: */ _sigq_check_reqd = 0; - - dequeue_signals(); + _dequeue_signals(); } /* @@ -809,8 +820,7 @@ thread_kern_poll(int wait_reqd) if (_sigq_check_reqd != 0) { /* Reset flag before handling signals: */ _sigq_check_reqd = 0; - - dequeue_signals(); + _dequeue_signals(); } } @@ -943,10 +953,7 @@ thread_kern_poll(int wait_reqd) /* Protect the scheduling queues: */ _queue_signals = 1; - - dequeue_signals(); - - /* Unprotect the scheduling queues: */ + _dequeue_signals(); _queue_signals = 0; } } @@ -958,6 +965,8 @@ _thread_kern_set_timeout(const struct timespec * timeout) struct timespec current_time; struct timeval tv; + PTHREAD_TRACE(6); + /* Reset the timeout flag for the running thread: */ curthread->timeout = 0; @@ -998,6 +1007,8 @@ _thread_kern_sig_defer(void) { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(7); + /* Allow signal deferral to be recursive. */ curthread->sig_defer_count++; } @@ -1007,6 +1018,8 @@ _thread_kern_sig_undefer(void) { struct pthread *curthread = _get_curthread(); + PTHREAD_TRACE(8); + /* * Perform checks to yield only if we are about to undefer * signals. @@ -1047,12 +1060,14 @@ _thread_kern_sig_undefer(void) } } -static void -dequeue_signals(void) +void +_dequeue_signals(void) { char bufr[128]; int i, num; + PTHREAD_TRACE(9); + /* * Enter a loop to read and handle queued signals from the * pthread kernel pipe: @@ -1072,7 +1087,7 @@ dequeue_signals(void) } else { /* Handle this signal: */ - _thread_sig_handle((int) bufr[i], NULL); + _thread_sig_process((int) bufr[i], NULL); } } } @@ -1085,12 +1100,14 @@ dequeue_signals(void) } } -static inline void -thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in) +inline void +_thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in) { pthread_t tid_out = thread_out; pthread_t tid_in = thread_in; + PTHREAD_TRACE(10); + if ((tid_out != NULL) && (tid_out->flags & PTHREAD_FLAGS_PRIVATE) != 0) tid_out = NULL; diff --git a/lib/libpthread/uthread/uthread_kill.c b/lib/libpthread/uthread/uthread_kill.c index 172d3817513..59d78b80ebf 100644 --- a/lib/libpthread/uthread/uthread_kill.c +++ b/lib/libpthread/uthread/uthread_kill.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_kill.c,v 1.7 1999/11/25 07:01:37 d Exp $ */ +/* $OpenBSD: uthread_kill.c,v 1.8 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -38,6 +38,12 @@ #include <pthread.h> #include "pthread_private.h" +/* + * XXX THIS IS WRONG! The signal has to either come through the OS to + * get the proper siginfo, context, etc., or we need to gen up a + * siginfo (assuming needed). Signal reset and other semantics + * also need to be obeyed. + */ int pthread_kill(pthread_t pthread, int sig) { @@ -75,7 +81,6 @@ pthread_kill(pthread_t pthread, int sig) /* Return the signal number: */ pthread->signo = sig; } - /* Increment the pending signal count: */ sigaddset(&pthread->sigpend,sig); break; @@ -88,7 +93,6 @@ pthread_kill(pthread_t pthread, int sig) /* Return the signal number: */ pthread->signo = sig; } else - /* Increment the pending signal count. */ sigaddset(&pthread->sigpend,sig); break; @@ -111,7 +115,6 @@ pthread_kill(pthread_t pthread, int sig) /* Return the signal number: */ pthread->signo = sig; } else { - /* Increment the pending signal count: */ sigaddset(&pthread->sigpend,sig); } break; @@ -144,7 +147,7 @@ pthread_kill(pthread_t pthread, int sig) /* * Dispatch the signal via the custom signal - * handler: + * handler: ;;; what about SA_SIGINFO??? */ (*(_thread_sigact[sig - 1].sa_handler))(sig); diff --git a/lib/libpthread/uthread/uthread_mutex.c b/lib/libpthread/uthread/uthread_mutex.c index 41f510c37e4..79bd3573379 100644 --- a/lib/libpthread/uthread/uthread_mutex.c +++ b/lib/libpthread/uthread/uthread_mutex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_mutex.c,v 1.14 2002/01/23 23:11:57 fgsch Exp $ */ +/* $OpenBSD: uthread_mutex.c,v 1.15 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -715,27 +715,6 @@ pthread_mutex_lock(pthread_mutex_t *mutex) } int -_pthread_mutex_lock(pthread_mutex_t *mutex) -{ - int ret = 0; - - if (_thread_initial == NULL) - _thread_init(); - - if (mutex == NULL) - ret = EINVAL; - - /* - * If the mutex is statically initialized, perform the dynamic - * initialization marking it private (delete safe): - */ - else if ((*mutex != NULL) || ((ret = init_static_private(mutex)) == 0)) - ret = mutex_lock_common(mutex); - - return (ret); -} - -int pthread_mutex_unlock(pthread_mutex_t * mutex) { return (mutex_unlock_common(mutex, /* add reference */ 0)); diff --git a/lib/libpthread/uthread/uthread_sig.c b/lib/libpthread/uthread/uthread_sig.c index 48f360f3ea3..be4e5c8323c 100644 --- a/lib/libpthread/uthread/uthread_sig.c +++ b/lib/libpthread/uthread/uthread_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_sig.c,v 1.13 2002/10/07 22:36:04 marc Exp $ */ +/* $OpenBSD: uthread_sig.c,v 1.14 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -41,10 +41,10 @@ #include "pthread_private.h" /* Static variables: */ -static spinlock_t signal_lock = _SPINLOCK_INITIALIZER; -unsigned int pending_sigs[NSIG]; -unsigned int handled_sigs[NSIG]; -int volatile check_pending = 0; +static _spinlock_lock_t signal_lock = _SPINLOCK_UNLOCKED; +siginfo_t info_queue[NSIG]; +volatile sig_atomic_t pending_sigs[NSIG]; +volatile sig_atomic_t check_pending = 0; /* Initialize signal handling facility: */ void @@ -52,113 +52,142 @@ _thread_sig_init(void) { int i; - /* Clear pending and handled signal counts: */ + /* Clear local state */ for (i = 1; i < NSIG; i++) { pending_sigs[i - 1] = 0; - handled_sigs[i - 1] = 0; } /* Clear the lock: */ - signal_lock.access_lock = 0; + signal_lock = _SPINLOCK_UNLOCKED; } +/* + * Process a pending signal unless it is already in progress. If the + * SA_NODEFER flag is on, process it any way. + */ +void +_thread_sig_process(int sig, struct sigcontext * scp) +{ + int locked = 0; + + if (_atomic_lock(&signal_lock) == 0) + locked = 1; + + if (locked || _thread_sigact[sig - 1].sa_flags & SA_NODEFER) { + _thread_sig_handle(sig, scp); + pending_sigs[sig - 1] = 0; + } else + check_pending = 1; + if (locked) + signal_lock = _SPINLOCK_UNLOCKED; +} + +/* + * This is the only installed signal handler. In addition to handling + * thread kernel signals it is installed in place of application handlers + * and dispatches signals appropriately. + */ void -_thread_sig_handler(int sig, int code, struct sigcontext * scp) +_thread_sig_handler(int sig, siginfo_t *info, struct sigcontext * scp) { struct pthread *curthread = _get_curthread(); char c; int i; - /* Check if an interval timer signal: */ + /* + * save the info for this signal in a per signal queue of depth + * one. Per a POSIX suggestion, only the info for the first + * of multiple activations of the same signal is kept. + */ + if (pending_sigs[sig - 1] == 0) { + pending_sigs[sig - 1]++; + memcpy(&info_queue[sig - 1], info, sizeof *info); + } + if (sig == _SCHED_SIGNAL) { /* Update the scheduling clock: */ gettimeofday((struct timeval *)&_sched_tod, NULL); _sched_ticks++; - if (_thread_kern_in_sched != 0) { - /* - * The scheduler is already running; ignore this - * signal. - */ - } - /* - * Check if the scheduler interrupt has come when - * the currently running thread has deferred thread - * signals. - */ - else if (curthread->sig_defer_count > 0) - curthread->yield_on_sig_undefer = 1; - - else { - /* - * Schedule the next thread. This function is not - * expected to return because it will do a longjmp - * instead. - */ - _thread_kern_sched(scp); - - /* The scheduler currently returns here instead - of calling sigreturn due to a sparc sigreturn - bug. We should also return. That brings - us back to the sigtramp code which will - sigreturn to the context stored on the current - stack (which is the same as scp, above). - The code originally did this: - - PANIC("Returned to signal function from scheduler"); - */ - return; - } - } - /* - * Check if the kernel has been interrupted while the scheduler - * is accessing the scheduling queues or if there is a currently - * running thread that has deferred signals. - */ - else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) && - (curthread->sig_defer_count > 0))) { - /* Cast the signal number to a character variable: */ - c = sig; + /* only process signal when scheduler isn't running */ + if (_thread_kern_in_sched == 0) + if (curthread->sig_defer_count > 0) + /* + * The scheduler interrupt has come when + * the currently running thread has deferred + * thread signals. + */ + curthread->yield_on_sig_undefer = 1; + else { + /* Schedule the next thread. */ + _thread_kern_sched(scp); + /* + * The scheduler currently returns here instead + * of calling sigreturn due to a sparc sigreturn + * bug. We should also return. That brings + * us back to the sigtramp code which will + * sigreturn to the context stored on the + * current stack (which is the same as scp, + * above). The code originally did this: + * + * PANIC("Returned to signal function " + * "from scheduler"); + */ + return; + } + } else if ((_queue_signals != 0) || + ((_thread_kern_in_sched == 0) && + (curthread->sig_defer_count > 0))) { /* - * Write the signal number to the kernel pipe so that it will - * be ready to read when this signal handler returns. + * The kernel has been interrupted while the scheduler + * is accessing the scheduling queues or there is a currently + * running thread that has deferred signals. + * + * Cast the signal number to a character variable and Write + * the signal number to the kernel pipe so that it will be + * ready to read when this signal handler returns. */ + c = sig; _thread_sys_write(_thread_kern_pipe[1], &c, 1); - - /* Indicate that there are queued signals in the pipe. */ _sigq_check_reqd = 1; - } - else { - if (_atomic_lock(&signal_lock.access_lock)) { - /* There is another signal handler running: */ - pending_sigs[sig - 1]++; - check_pending = 1; + } else { + /* process the signal */ + _thread_sig_process(sig, scp); + /* + * process pending signals unless a current signal handler + * is running (signal_lock is locked). When locked + * the pending signals will be processed when the running + * handler returns. + */ + while (check_pending != 0 && _atomic_lock(&signal_lock) == 0) { + check_pending = 0; + signal_lock = _SPINLOCK_UNLOCKED; + for (i = 1; i < NSIG; i++) + if (pending_sigs[i - 1]) + _thread_sig_process(i, scp); } - else { - /* It's safe to handle the signal now. */ - _thread_sig_handle(sig, scp); + } - /* Reset the pending and handled count back to 0: */ - pending_sigs[sig - 1] = 0; - handled_sigs[sig - 1] = 0; +} - signal_lock.access_lock = 0; - } +/* + * Clear the pending flag for the given signal on all threads + */ +void +_clear_pending_flag(int sig) +{ + pthread_t pthread; - /* Enter a loop to process pending signals: */ - while ((check_pending != 0) && - (_atomic_lock(&signal_lock.access_lock) == 0)) { - check_pending = 0; - for (i = 1; i < NSIG; i++) { - if (pending_sigs[i - 1] > handled_sigs[i - 1]) - _thread_sig_handle(i, scp); - } - signal_lock.access_lock = 0; - } + TAILQ_FOREACH(pthread, &_thread_list, tle) { + sigdelset(&pthread->sigpend, sig); } } + +/* + * Process the given signal. + */ void _thread_sig_handle(int sig, struct sigcontext * scp) { @@ -166,51 +195,30 @@ _thread_sig_handle(int sig, struct sigcontext * scp) int i; pthread_t pthread, pthread_next; - /* Check if the signal requires a dump of thread information: */ if (sig == SIGINFO) - /* Dump thread information to file: */ - _thread_dump_info(); - - /* Check if an interval timer signal: */ - else if (sig == _SCHED_SIGNAL) { - /* - * This shouldn't ever occur (should this panic?). - */ - } else { - /* Check if a child has terminated: */ + _thread_dump_info(); /* Dump thread information */ + else if (sig == _SCHED_SIGNAL) + ; /* This shouldn't ever occur (should this panic?). */ + else { 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. */ - 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: - */ + for (i = 0; i < _thread_dtablesize; i++) + if (_thread_fd_table[i] != NULL) _thread_sys_fcntl(i, F_SETFL, _thread_fd_table[i]->flags | O_NONBLOCK); - } - } } /* * POSIX says that pending SIGCONT signals are * discarded when one of these signals occurs. */ - if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { - /* - * Enter a loop to discard pending SIGCONT - * signals: - */ - TAILQ_FOREACH(pthread, &_thread_list, tle) { - sigdelset(&pthread->sigpend,SIGCONT); - } - } + if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) + _clear_pending_flag(SIGCONT); /* * Enter a loop to process each thread in the waiting @@ -220,7 +228,7 @@ _thread_sig_handle(int sig, struct sigcontext * scp) * first one we find. */ for (pthread = TAILQ_FIRST(&_waitingq); - pthread != NULL; pthread = pthread_next) { + pthread != NULL; pthread = pthread_next) { /* * Grab the next thread before possibly destroying * the link entry. @@ -243,33 +251,33 @@ _thread_sig_handle(int sig, struct sigcontext * scp) } } - /* Check if the signal is not being ignored: */ - if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) + if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { /* - * Enter a loop to process each thread in the linked - * list: + * mark the signal as pending for each thread + * and give the thread a chance to update + * its state. */ TAILQ_FOREACH(pthread, &_thread_list, tle) { - pthread_t pthread_saved = curthread; - /* Current thread inside critical region? */ if (curthread->sig_defer_count > 0) pthread->sig_defer_count++; - _thread_signal(pthread,sig); - - /* - * Dispatch pending signals to the - * running thread: - */ - _set_curthread(pthread); - _dispatch_signals(); - _set_curthread(pthread_saved); - + if (curthread->sig_defer_count > 0) + pthread->sig_defer_count--; + } + /* + * give each thread a chance to dispatch pending + * signals. + */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { /* Current thread inside critical region? */ if (curthread->sig_defer_count > 0) + pthread->sig_defer_count++; + _dispatch_signals(pthread, scp); + if (curthread->sig_defer_count > 0) pthread->sig_defer_count--; } + } } /* Returns nothing. */ @@ -373,11 +381,14 @@ _thread_signal(pthread_t pthread, int sig) } } -/* Dispatch pending signals to the running thread: */ +/* + * possibly dispatch a signal to the given thread. + */ void -_dispatch_signals() +_dispatch_signals(pthread_t pthread, struct sigcontext * scp) { - struct pthread *curthread = _get_curthread(); + pthread_t pthread_saved; + struct sigaction act; void (*action)(int, siginfo_t *, void *); int i; @@ -385,7 +396,7 @@ _dispatch_signals() * Check if there are pending signals for the running * thread that aren't blocked: */ - if ((curthread->sigpend & ~curthread->sigmask) != 0) + if ((pthread->sigpend & ~pthread->sigmask) != 0) /* Look for all possible pending signals: */ for (i = 1; i < NSIG; i++) /* @@ -394,23 +405,28 @@ _dispatch_signals() */ if (_thread_sigact[i - 1].sa_handler != SIG_DFL && _thread_sigact[i - 1].sa_handler != SIG_IGN && - sigismember(&curthread->sigpend,i) && - !sigismember(&curthread->sigmask,i)) { + sigismember(&pthread->sigpend,i) && + !sigismember(&pthread->sigmask,i)) { action = _thread_sigact[i - 1].sa_sigaction; - - /* Clear the pending signal: */ - sigdelset(&curthread->sigpend,i); + _clear_pending_flag(i); /* clear custom handler if SA_RESETHAND set. */ if (_thread_sigact[i - 1].sa_flags & - SA_RESETHAND) - _thread_sigact[i - 1].sa_handler = - SIG_DFL; + SA_RESETHAND) { + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + sigaction(i, &act, NULL); + } + /* * Dispatch the signal via the custom signal - * handler: + * handler. */ - (*action)(i, 0, 0); + pthread_saved = _get_curthread(); + _set_curthread(pthread); + (*action)(i, &info_queue[i - 1], scp); + _set_curthread(pthread_saved); } } #endif diff --git a/lib/libpthread/uthread/uthread_sigaction.c b/lib/libpthread/uthread/uthread_sigaction.c index de0aaeb7bfe..61463f7ef99 100644 --- a/lib/libpthread/uthread/uthread_sigaction.c +++ b/lib/libpthread/uthread/uthread_sigaction.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_sigaction.c,v 1.5 1999/11/25 07:01:44 d Exp $ */ +/* $OpenBSD: uthread_sigaction.c,v 1.6 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -75,12 +75,9 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact) */ if (act != NULL && sig != _SCHED_SIGNAL && sig != SIGCHLD && sig != SIGINFO) { - /* Initialise the global signal action structure: */ gact.sa_mask = act->sa_mask; - gact.sa_flags = 0; - - /* Ensure the scheduling signal is masked: */ sigaddset(&gact.sa_mask, _SCHED_SIGNAL); + gact.sa_flags = act->sa_flags | SA_SIGINFO; /* * Check if the signal handler is being set to @@ -91,14 +88,12 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact) /* 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; + /* 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) + if (_thread_sys_sigaction(sig, &gact, NULL) != 0) ret = -1; } } diff --git a/lib/libpthread/uthread/uthread_signal.c b/lib/libpthread/uthread/uthread_signal.c index bd9b488b3d0..3cc2373fc64 100644 --- a/lib/libpthread/uthread/uthread_signal.c +++ b/lib/libpthread/uthread/uthread_signal.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_signal.c,v 1.4 1999/11/25 07:01:45 d Exp $ */ +/* $OpenBSD: uthread_signal.c,v 1.5 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -46,7 +46,7 @@ _thread_sys_signal(int s, sig_t a) /* Initialise the signal action structure: */ sigemptyset(&sa.sa_mask); sa.sa_handler = a; - sa.sa_flags = 0; + sa.sa_flags = SA_SIGINFO; /* Perform the sigaction syscall: */ if (_thread_sys_sigaction(s, &sa, &osa) < 0) { diff --git a/lib/libpthread/uthread/uthread_sigwait.c b/lib/libpthread/uthread/uthread_sigwait.c index 0d1bf618be1..b7b72c7ea09 100644 --- a/lib/libpthread/uthread/uthread_sigwait.c +++ b/lib/libpthread/uthread/uthread_sigwait.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_sigwait.c,v 1.10 2002/02/21 20:57:41 fgsch Exp $ */ +/* $OpenBSD: uthread_sigwait.c,v 1.11 2002/10/30 19:11:56 marc Exp $ */ /* * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -53,7 +53,7 @@ sigwait(const sigset_t * set, int *sig) * Specify the thread kernel signal handler. */ act.sa_handler = (void (*) ()) _thread_sig_handler; - act.sa_flags = SA_RESTART; + act.sa_flags = SA_SIGINFO | SA_RESTART; /* Ensure the signal handler cannot be interrupted by other signals: */ sigfillset(&act.sa_mask); |