diff options
author | Marco S Hyman <marc@cvs.openbsd.org> | 2003-01-24 21:03:16 +0000 |
---|---|---|
committer | Marco S Hyman <marc@cvs.openbsd.org> | 2003-01-24 21:03:16 +0000 |
commit | c2d1f9d7206a0c18bda06f5221e4803b0c899249 (patch) | |
tree | 6f660d4c630b91051063dba780382b9b9beb9f7f /lib | |
parent | 0452d1ce15ba874fc9fe42f63b8e3a714ed3d91b (diff) |
save and restore fp state when switching threads. This, with
an arch/i386 patch previously commited and arch/sparc64 patches
from jason@ make the preemption_float test pass on those two
architectures.
Do not run signal handlers for a thread until the thread has
been made current, ensuring the proper context. Solves several
(if not all) of the '_pq_insert_tail: Already in priority queue'
problems.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libpthread/uthread/pthread_private.h | 4 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_kern.c | 80 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_sig.c | 39 |
3 files changed, 46 insertions, 77 deletions
diff --git a/lib/libpthread/uthread/pthread_private.h b/lib/libpthread/uthread/pthread_private.h index 83389b6008b..78d34b82804 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.40 2002/12/11 23:21:19 marc Exp $ */ +/* $OpenBSD: pthread_private.h,v 1.41 2003/01/24 21:03:15 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -1073,7 +1073,7 @@ 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(pthread_t, struct sigcontext *); +void _dispatch_signals(struct sigcontext *); void _thread_signal(pthread_t, int); int _mutex_cv_lock(pthread_mutex_t *); int _mutex_cv_unlock(pthread_mutex_t *); diff --git a/lib/libpthread/uthread/uthread_kern.c b/lib/libpthread/uthread/uthread_kern.c index cf1a6dcf6ac..9930098a974 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.23 2002/11/04 21:28:49 marc Exp $ */ +/* $OpenBSD: uthread_kern.c,v 1.24 2003/01/24 21:03:15 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -115,11 +115,6 @@ _thread_kern_sched(struct sigcontext * scp) memcpy(&curthread->saved_sigcontext, scp, sizeof(curthread->saved_sigcontext)); - /* - * Save floating point state. - */ - _thread_machdep_save_float_state(&curthread->_machdep); - /* Flag the signal context as the last state saved: */ curthread->sig_saved = 1; } else @@ -130,6 +125,9 @@ _thread_kern_sched(struct sigcontext * scp) if ((curthread->flags & PTHREAD_FLAGS_PRIVATE) == 0) _last_user_thread = curthread; + /* Save floating point state. */ + _thread_machdep_save_float_state(&curthread->_machdep); + /* Save errno. */ curthread->error = errno; @@ -501,41 +499,38 @@ _thread_kern_sched(struct sigcontext * scp) /* Restore errno. */ errno = curthread->error; + /* Restore floating point state. */ + _thread_machdep_restore_float_state(&curthread->_machdep); + /* * Restore the new thread, saving current. */ _thread_machdep_switch(&curthread->_machdep, - &old_thread_run->_machdep); - - /* Check if a signal context was saved: */ - if (curthread->sig_saved == 1) { - /* - * Restore floating point state. - */ - _thread_machdep_restore_float_state(&curthread->_machdep); - - /* - * Do a sigreturn to restart the thread that - * was interrupted by a signal: - */ - _thread_kern_in_sched = 0; + &old_thread_run->_machdep); - /* - * If we had a context switch, run any - * installed switch hooks. - */ - if ((_sched_switch_hook != NULL) && - (_last_user_thread != curthread)) { - _thread_run_switch_hook(_last_user_thread, - curthread); - } + /* + * Process any pending signals for the thread we + * just switched to. + */ + _thread_kern_in_sched = 0; + _dispatch_signals(scp); + + /* run any installed switch-hooks */ + if ((_sched_switch_hook != NULL) && + (_last_user_thread != curthread)) { + _thread_run_switch_hook(_last_user_thread, + curthread); + } - if (((curthread->cancelflags & - PTHREAD_AT_CANCEL_POINT) == 0) && - ((curthread->cancelflags & - PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) - pthread_testcancel(); + /* check for thread cancellation */ + if (((curthread->cancelflags & + PTHREAD_AT_CANCEL_POINT) == 0) && + ((curthread->cancelflags & + PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) + pthread_testcancel(); + /* Check if a signal context was saved: */ + if (curthread->sig_saved == 1) { /* return to signal handler. This code should be: _thread_sys_sigreturn(&curthread->saved_sigcontext); @@ -543,22 +538,7 @@ _thread_kern_sched(struct sigcontext * scp) sparc */ return; } else { - /* - * This is the normal way out of the scheduler. - */ - _thread_kern_in_sched = 0; - - if (_sched_switch_hook != NULL) { - /* Run the installed switch hook: */ - _thread_run_switch_hook(_last_user_thread, - curthread); - } - - if (((curthread->cancelflags & - PTHREAD_AT_CANCEL_POINT) == 0) && - ((curthread->cancelflags & - PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) - pthread_testcancel(); + /* This is the normal way out */ return; } diff --git a/lib/libpthread/uthread/uthread_sig.c b/lib/libpthread/uthread/uthread_sig.c index 1d64e077cde..17eef3fa38e 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.16 2002/11/08 23:18:25 todd Exp $ */ +/* $OpenBSD: uthread_sig.c,v 1.17 2003/01/24 21:03:15 marc Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -75,8 +75,8 @@ _thread_sig_process(int sig, struct sigcontext * scp) locked = 1; if (locked || _thread_sigact[sig - 1].sa_flags & SA_NODEFER) { - _thread_sig_handle(sig, scp); pending_sigs[sig - 1] = 0; + _thread_sig_handle(sig, scp); } else check_pending = 1; if (locked) @@ -167,7 +167,7 @@ _thread_sig_handler(int sig, siginfo_t *info, struct sigcontext * scp) signal_lock = _SPINLOCK_UNLOCKED; for (i = 1; i < NSIG; i++) if (pending_sigs[i - 1]) - _thread_sig_process(i, scp); + _thread_sig_process(i, scp); } } @@ -268,22 +268,14 @@ _thread_sig_handle(int sig, struct sigcontext * scp) pthread->sig_defer_count--; } /* - * give each thread a chance to dispatch pending - * signals. + * Give the current thread a chance to dispatch + * the signals. Other threads will get thier + * chance (if the signal is still pending) later. */ - 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--; - } + _dispatch_signals(scp); + } } - - /* Returns nothing. */ - return; } /* Perform thread specific actions in response to a signal: */ @@ -385,12 +377,12 @@ _thread_signal(pthread_t pthread, int sig) } /* - * possibly dispatch a signal to the given thread. + * possibly dispatch a signal to the current thread. */ void -_dispatch_signals(pthread_t pthread, struct sigcontext * scp) +_dispatch_signals(struct sigcontext * scp) { - pthread_t pthread_saved; + struct pthread *curthread = _get_curthread(); struct sigaction act; void (*action)(int, siginfo_t *, void *); int i; @@ -399,7 +391,7 @@ _dispatch_signals(pthread_t pthread, struct sigcontext * scp) * Check if there are pending signals for the running * thread that aren't blocked: */ - if ((pthread->sigpend & ~pthread->sigmask) != 0) + if ((curthread->sigpend & ~curthread->sigmask) != 0) /* Look for all possible pending signals: */ for (i = 1; i < NSIG; i++) /* @@ -408,8 +400,8 @@ _dispatch_signals(pthread_t pthread, struct sigcontext * scp) */ if (_thread_sigact[i - 1].sa_handler != SIG_DFL && _thread_sigact[i - 1].sa_handler != SIG_IGN && - sigismember(&pthread->sigpend,i) && - !sigismember(&pthread->sigmask,i)) { + sigismember(&curthread->sigpend,i) && + !sigismember(&curthread->sigmask,i)) { action = _thread_sigact[i - 1].sa_sigaction; _clear_pending_flag(i); @@ -426,10 +418,7 @@ _dispatch_signals(pthread_t pthread, struct sigcontext * scp) * Dispatch the signal via the custom signal * handler. */ - pthread_saved = _get_curthread(); - _set_curthread(pthread); (*action)(i, &info_queue[i - 1], scp); - _set_curthread(pthread_saved); } } #endif |