diff options
author | deischen <deischen@FreeBSD.org> | 2000-11-09 05:08:26 +0000 |
---|---|---|
committer | deischen <deischen@FreeBSD.org> | 2000-11-09 05:08:26 +0000 |
commit | 69c0393f8e4b9bd522c1e9afe2f481e040dcbac3 (patch) | |
tree | a9d526e7ccca466ce303b1c6202f807942d274db /lib/libpthread/thread/thr_kern.c | |
parent | e1d8dafb1c246b5ecfd3bf52b6e9ff947e171314 (diff) | |
download | FreeBSD-src-69c0393f8e4b9bd522c1e9afe2f481e040dcbac3.zip FreeBSD-src-69c0393f8e4b9bd522c1e9afe2f481e040dcbac3.tar.gz |
Don't needlessly poll file descriptors when there are no
file descriptors needing to be polled (Doh!). Reported
by Dan Nelson <dnelson@emsphone.com>.
Don't install and start the scheduling timer until the
first thread is created. This prevents the overhead of
having a periodic scheduling signal in a single threaded
program. Reported by Dan Nelson <dnelson@emsphone.com>.
Allow builtin longjmps out of application installed
signal handlers without the need perform any post-handler
cleanup:
o Change signal handling to save the threads interrupted
context on the stack. The threads current context is
now always stored in the same place (in the pthread).
If and when a signal handler returns, the interrupted
context is copied back to the storage area in the pthread.
o Before calling invoking a signal handler for a thread,
back the thread out of any internal waiting queues
(mutex, CV, join, etc) to which it belongs.
Rework uthread_info.c a bit to make it easier to change
the format of a thread dump.
Use an alternal signal stack for the thread library's
signal handler. This allows us to fiddle with the main
threads stack without fear of it being in use.
Reviewed by: jasone
Diffstat (limited to 'lib/libpthread/thread/thr_kern.c')
-rw-r--r-- | lib/libpthread/thread/thr_kern.c | 87 |
1 files changed, 45 insertions, 42 deletions
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c index 23f16bc..67844e1 100644 --- a/lib/libpthread/thread/thr_kern.c +++ b/lib/libpthread/thread/thr_kern.c @@ -60,7 +60,7 @@ #endif /* Static function prototype definitions: */ -static void +static void thread_kern_poll(int wait_reqd); static void @@ -77,7 +77,7 @@ static int last_tick = 0; * return to a previous frame. */ void -_thread_kern_sched_frame(int frame) +_thread_kern_sched_frame(struct pthread_signal_frame *psf) { /* * Flag the pthread kernel as executing scheduler code @@ -86,13 +86,8 @@ _thread_kern_sched_frame(int frame) */ _thread_kern_in_sched = 1; - /* Return to the specified frame: */ - _thread_run->curframe = _thread_run->sigframes[frame]; - _thread_run->sigframe_count = frame; - - if (_thread_run->sigframe_count == 0) - /* Restore the threads priority: */ - _thread_run->active_priority &= ~PTHREAD_SIGNAL_PRIORITY; + /* Restore the signal frame: */ + _thread_sigframe_restore(_thread_run, psf); /* Switch to the thread scheduler: */ ___longjmp(_thread_kern_sched_jb, 1); @@ -127,16 +122,16 @@ _thread_kern_sched(ucontext_t *scp) _thread_kern_scheduler(); } else { /* Save the state of the current thread: */ - if (_setjmp(_thread_run->curframe->ctx.jb) == 0) { + if (_setjmp(_thread_run->ctx.jb) == 0) { /* Flag the jump buffer was the last state saved: */ - _thread_run->curframe->ctxtype = CTX_JB_NOSIG; - _thread_run->curframe->longjmp_val = 1; + _thread_run->ctxtype = CTX_JB_NOSIG; + _thread_run->longjmp_val = 1; } else { DBG_MSG("Returned from ___longjmp, thread %p\n", _thread_run); /* * This point is reached when a longjmp() is called - * to restore the state of a thread. + * to restore the state of a thread. * * This is the normal way out of the scheduler. */ @@ -147,7 +142,7 @@ _thread_kern_sched(ucontext_t *scp) PTHREAD_AT_CANCEL_POINT) == 0) && ((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) - /* + /* * Cancellations override signals. * * Stick a cancellation point at the @@ -183,7 +178,6 @@ _thread_kern_sched_sig(void) void _thread_kern_scheduler(void) { - struct pthread_signal_frame *psf; struct timespec ts; struct timeval tv; pthread_t pthread, pthread_h; @@ -205,7 +199,7 @@ _thread_kern_scheduler(void) * ready to run. This loop completes when there are no more threads * in the global list or when a thread has its state restored by * either a sigreturn (if the state was saved as a sigcontext) or a - * longjmp (if the state was saved by a setjmp). + * longjmp (if the state was saved by a setjmp). */ while (!(TAILQ_EMPTY(&_thread_list))) { /* Get the current time of day: */ @@ -229,7 +223,7 @@ _thread_kern_scheduler(void) if (_thread_run->state != PS_RUNNING) { /* * Save the current time as the time that the - * thread became inactive: + * thread became inactive: */ _thread_run->last_inactive = (long)current_tick; if (_thread_run->last_inactive < @@ -266,7 +260,7 @@ _thread_kern_scheduler(void) /* * States which do not depend on file descriptor I/O - * operations or timeouts: + * operations or timeouts: */ case PS_DEADLOCK: case PS_FDLR_WAIT: @@ -326,10 +320,16 @@ _thread_kern_scheduler(void) } /* + * Avoid polling file descriptors if there are none + * waiting: + */ + if (TAILQ_EMPTY(&_workq) == 0) { + } + /* * Poll file descriptors only if a new scheduling signal * has occurred or if we have no more runnable threads. */ - if (((current_tick = _sched_ticks) != last_tick) || + else if (((current_tick = _sched_ticks) != last_tick) || ((_thread_run->state != PS_RUNNING) && (PTHREAD_PRIOQ_FIRST() == NULL))) { /* Unprotect the scheduling queues: */ @@ -337,7 +337,7 @@ _thread_kern_scheduler(void) /* * Poll file descriptors to update the state of threads - * waiting on file I/O where data may be available: + * waiting on file I/O where data may be available: */ thread_kern_poll(0); @@ -392,7 +392,7 @@ _thread_kern_scheduler(void) if (add_to_prioq != 0) { /* * Save the current time as the time that the - * thread became inactive: + * thread became inactive: */ current_tick = _sched_ticks; _thread_run->last_inactive = (long)current_tick; @@ -445,7 +445,7 @@ _thread_kern_scheduler(void) /* * Lock the pthread kernel by changing the pointer to * the running thread to point to the global kernel - * thread structure: + * thread structure: */ _thread_run = &_thread_kern_thread; DBG_MSG("No runnable threads, using kernel thread %p\n", @@ -456,7 +456,7 @@ _thread_kern_scheduler(void) /* * There are no threads ready to run, so wait until - * something happens that changes this condition: + * something happens that changes this condition: */ thread_kern_poll(1); @@ -524,7 +524,7 @@ _thread_kern_scheduler(void) /* * Save the current time as the time that the thread - * became active: + * became active: */ current_tick = _sched_ticks; _thread_run->last_active = (long) current_tick; @@ -532,7 +532,7 @@ _thread_kern_scheduler(void) /* * Check if this thread is running for the first time * or running again after using its full time slice - * allocation: + * allocation: */ if (_thread_run->slice_usec == -1) { /* Reset the accumulated time slice period: */ @@ -551,36 +551,39 @@ _thread_kern_scheduler(void) /* * Continue the thread at its current frame: */ - psf = _thread_run->curframe; - switch(psf->ctxtype) { + switch(_thread_run->ctxtype) { case CTX_JB_NOSIG: - ___longjmp(psf->ctx.jb, psf->longjmp_val); + ___longjmp(_thread_run->ctx.jb, + _thread_run->longjmp_val); break; case CTX_JB: - __longjmp(psf->ctx.jb, psf->longjmp_val); + __longjmp(_thread_run->ctx.jb, + _thread_run->longjmp_val); break; case CTX_SJB: - __siglongjmp(psf->ctx.sigjb, psf->longjmp_val); + __siglongjmp(_thread_run->ctx.sigjb, + _thread_run->longjmp_val); break; case CTX_UC: /* XXX - Restore FP regsisters? */ - FP_RESTORE_UC(&psf->ctx.uc); + FP_RESTORE_UC(&_thread_run->ctx.uc); /* * Do a sigreturn to restart the thread that - * was interrupted by a signal: + * was interrupted by a signal: */ _thread_kern_in_sched = 0; #if NOT_YET - _setcontext(&psf->ctx.uc); + _setcontext(&_thread_run->ctx.uc); #else /* * Ensure the process signal mask is set * correctly: */ - psf->ctx.uc.uc_sigmask = _process_sigmask; - _thread_sys_sigreturn(&psf->ctx.uc); + _thread_run->ctx.uc.uc_sigmask = + _process_sigmask; + _thread_sys_sigreturn(&_thread_run->ctx.uc); #endif break; } @@ -800,14 +803,14 @@ thread_kern_poll(int wait_reqd) /* * Wait for a file descriptor to be ready for read, write, or - * an exception, or a timeout to occur: + * an exception, or a timeout to occur: */ count = _thread_sys_poll(_thread_pfd_table, nfds, timeout_ms); if (kern_pipe_added != 0) /* * Remove the pthread kernel pipe file descriptor - * from the pollfd table: + * from the pollfd table: */ nfds = 1; else @@ -821,7 +824,7 @@ thread_kern_poll(int wait_reqd) (_thread_pfd_table[0].revents & POLLRDNORM))) { /* * If the kernel read pipe was included in the - * count: + * count: */ if (count > 0) { /* Decrement the count of file descriptors: */ @@ -843,7 +846,7 @@ thread_kern_poll(int wait_reqd) /* * Enter a loop to look for threads waiting on file * descriptors that are flagged as available by the - * _poll syscall: + * _poll syscall: */ PTHREAD_WAITQ_SETACTIVE(); TAILQ_FOREACH(pthread, &_workq, qe) { @@ -986,7 +989,7 @@ _thread_kern_set_timeout(const struct timespec * timeout) if (timeout == NULL) { /* * Set the wakeup time to something that can be recognised as - * different to an actual time of day: + * different to an actual time of day: */ _thread_run->wakeup_time.tv_sec = -1; _thread_run->wakeup_time.tv_nsec = -1; @@ -1042,7 +1045,7 @@ _thread_kern_sig_undefer(void) if (_sigq_check_reqd != 0) _thread_kern_sched(NULL); - /* + /* * Check for asynchronous cancellation before delivering any * pending signals: */ @@ -1071,7 +1074,7 @@ dequeue_signals(void) int num; /* - * Enter a loop to clear the pthread kernel pipe: + * Enter a loop to clear the pthread kernel pipe: */ while (((num = _thread_sys_read(_thread_kern_pipe[0], bufr, sizeof(bufr))) > 0) || (num == -1 && errno == EINTR)) { |