diff options
Diffstat (limited to 'lib/libkse/thread/thr_sig.c')
-rw-r--r-- | lib/libkse/thread/thr_sig.c | 51 |
1 files changed, 39 insertions, 12 deletions
diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c index 3e55d65..e51d949 100644 --- a/lib/libkse/thread/thr_sig.c +++ b/lib/libkse/thread/thr_sig.c @@ -38,6 +38,19 @@ #include <pthread.h> #include "pthread_private.h" +/* + * State change macro for signal handler: + */ +#define PTHREAD_SIG_NEW_STATE(thrd, newstate) { \ + if ((_thread_run->sched_defer_count == 0) && \ + (_thread_kern_in_sched == 0)) { \ + PTHREAD_NEW_STATE(thrd, newstate); \ + } else { \ + _waitingq_check_reqd = 1; \ + PTHREAD_SET_STATE(thrd, newstate); \ + } \ +} + /* Static variables: */ static int volatile yield_on_unlock_thread = 0; static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER; @@ -94,14 +107,13 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp) */ _thread_sys_write(_thread_kern_pipe[1], &c, 1); } - /* 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 == SIGVTALRM) { + else if (sig == _SCHED_SIGNAL) { /* Check if the scheduler interrupt has come at an * unfortunate time which one of the threads is * modifying the thread list: @@ -115,6 +127,14 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp) yield_on_unlock_thread = 1; /* + * Check if the scheduler interrupt has come when + * the currently running thread has deferred thread + * scheduling. + */ + else if (_thread_run->sched_defer_count) + _thread_run->yield_on_sched_undefer = 1; + + /* * Check if the kernel has not been interrupted while * executing scheduler code: */ @@ -170,18 +190,17 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp) } /* - * Enter a loop to process each thread in the linked + * Enter a loop to process each thread in the waiting * list that is sigwait-ing on a signal. Since POSIX * doesn't specify which thread will get the signal * if there are multiple waiters, we'll give it to the * first one we find. */ - for (pthread = _thread_link_list; pthread != NULL; - pthread = pthread->nxt) { + TAILQ_FOREACH(pthread, &_waitingq, pqe) { if ((pthread->state == PS_SIGWAIT) && sigismember(pthread->data.sigwait, sig)) { /* Change the state of the thread to run: */ - PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING); /* Return the signal number: */ pthread->signo = sig; @@ -201,11 +220,19 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp) * list: */ for (pthread = _thread_link_list; pthread != NULL; - pthread = pthread->nxt) + pthread = pthread->nxt) { + pthread_t pthread_saved = _thread_run; + + _thread_run = pthread; _thread_signal(pthread,sig); - /* Dispatch pending signals to the running thread: */ - _dispatch_signals(); + /* + * Dispatch pending signals to the + * running thread: + */ + _dispatch_signals(); + _thread_run = pthread_saved; + } } /* Returns nothing. */ @@ -257,7 +284,7 @@ _thread_signal(pthread_t pthread, int sig) pthread->interrupted = 1; /* Change the state of the thread to run: */ - PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING); /* Return the signal number: */ pthread->signo = sig; @@ -277,7 +304,7 @@ _thread_signal(pthread_t pthread, int sig) pthread->interrupted = 1; /* Change the state of the thread to run: */ - PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING); /* Return the signal number: */ pthread->signo = sig; @@ -292,7 +319,7 @@ _thread_signal(pthread_t pthread, int sig) if (!sigismember(&pthread->sigmask, sig) && _thread_sigact[sig - 1].sa_handler != SIG_DFL) { /* Change the state of the thread to run: */ - PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING); /* Return the signal number: */ pthread->signo = sig; |