summaryrefslogtreecommitdiffstats
path: root/lib/libpthread/thread/thr_kern.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread/thread/thr_kern.c')
-rw-r--r--lib/libpthread/thread/thr_kern.c1739
1 files changed, 0 insertions, 1739 deletions
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c
deleted file mode 100644
index ba8e250..0000000
--- a/lib/libpthread/thread/thr_kern.c
+++ /dev/null
@@ -1,1739 +0,0 @@
-/*
- * Copyright (c) 1995 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 <errno.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <setjmp.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/syscall.h>
-#include <fcntl.h>
-#ifdef _THREAD_SAFE
-#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)
-{
-#ifndef __alpha
- char *fdata;
-#endif
- int i;
- int prio = -1;
- pthread_t pthread;
- pthread_t pthread_h = NULL;
- pthread_t pthread_nxt = NULL;
- pthread_t pthread_prv = NULL;
- pthread_t pthread_s = NULL;
- struct itimerval itimer;
- struct timespec ts;
- struct timespec ts1;
- struct timeval tv;
- struct timeval tv1;
-
- /* Block signals: */
- _thread_kern_sig_block(NULL);
-
- /* Check if this function was called from the signal handler: */
- if (scp != NULL) {
- /*
- * Copy the signal context to the current thread's jump
- * buffer:
- */
- memcpy(&_thread_run->saved_sigcontext, scp, sizeof(_thread_run->saved_sigcontext));
-
-#ifndef __alpha
- /* Point to the floating point data in the running thread: */
- fdata = _thread_run->saved_fp;
-
- /* Save the floating point data: */
-__asm__("fnsave %0": :"m"(*fdata));
-#endif
-
- /* Flag the signal context as the last state saved: */
- _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);
-
- /*
- * This point is reached when a longjmp() is called to
- * restore the state of a thread.
- */
- return;
- } else {
- /* Flag the jump buffer was the last state saved: */
- _thread_run->sig_saved = 0;
- }
-
- /* Point to the first dead thread (if there are any): */
- pthread = _thread_dead;
-
- /* There is no previous dead thread: */
- pthread_prv = NULL;
-
- /* Enter a loop to cleanup after dead threads: */
- while (pthread != NULL) {
- /* Save a pointer to the next thread: */
- pthread_nxt = pthread->nxt;
-
- /* Check if this thread is one which is running: */
- if (pthread == _thread_run || pthread == _thread_initial) {
- /*
- * Don't destroy the running thread or the initial
- * thread.
- */
- pthread_prv = pthread;
- }
- /*
- * Check if this thread has detached or if it is a signal
- * handler thread:
- */
- else if (((pthread->attr.flags & PTHREAD_DETACHED) != 0) || pthread->parent_thread != NULL) {
- /* Check if there is no previous dead thread: */
- if (pthread_prv == NULL) {
- /*
- * The dead thread is at the head of the
- * list:
- */
- _thread_dead = pthread_nxt;
- } else {
- /*
- * The dead thread is not at the head of the
- * list:
- */
- pthread_prv->nxt = pthread->nxt;
- }
-
- /*
- * Check if the stack was not specified by the caller
- * to pthread_create and has not been destroyed yet:
- */
- if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) {
- /* Free the stack of the dead thread: */
- free(pthread->stack);
- }
- /* Free the memory allocated to the thread structure: */
- free(pthread);
- } else {
- /*
- * This thread has not detached, so do not destroy
- * it:
- */
- pthread_prv = pthread;
-
- /*
- * Check if the stack was not specified by the caller
- * to pthread_create and has not been destroyed yet:
- */
- if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) {
- /* Free the stack of the dead thread: */
- free(pthread->stack);
-
- /*
- * NULL the stack pointer now that the memory
- * has been freed:
- */
- pthread->stack = NULL;
- }
- }
-
- /* Point to the next thread: */
- pthread = pthread_nxt;
- }
-
- /*
- * Enter a the scheduling loop that finds the next thread that is
- * 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).
- */
- while (_thread_link_list != NULL) {
- /* Get the current time of day: */
- gettimeofday(&tv, NULL);
- TIMEVAL_TO_TIMESPEC(&tv, &ts);
-
- /*
- * Poll file descriptors to update the state of threads
- * waiting on file I/O where data may be available:
- */
- _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:
- */
- 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;
- }
- }
-
- /* Check if this thread is to timeout: */
- if (pthread->state == PS_COND_WAIT ||
- pthread->state == PS_SLEEP_WAIT ||
- pthread->state == PS_FDR_WAIT ||
- pthread->state == PS_FDW_WAIT ||
- pthread->state == PS_SELECT_WAIT) {
- /* Check if this thread is to wait forever: */
- if (pthread->wakeup_time.tv_sec == -1) {
- }
- /*
- * Check if this thread is to wakeup
- * immediately or if it is past its wakeup
- * time:
- */
- else if ((pthread->wakeup_time.tv_sec == 0 &&
- pthread->wakeup_time.tv_nsec == 0) ||
- (ts.tv_sec > pthread->wakeup_time.tv_sec) ||
- ((ts.tv_sec == pthread->wakeup_time.tv_sec) &&
- (ts.tv_nsec >= pthread->wakeup_time.tv_nsec))) {
- /*
- * Check if this thread is waiting on
- * select:
- */
- if (pthread->state == PS_SELECT_WAIT) {
- /*
- * The select has timed out,
- * so zero the file
- * descriptor sets:
- */
- FD_ZERO(&pthread->data.select_data->readfds);
- FD_ZERO(&pthread->data.select_data->writefds);
- FD_ZERO(&pthread->data.select_data->exceptfds);
- pthread->data.select_data->nfds = 0;
- }
- /*
- * Return an error as an interrupted
- * wait:
- */
- _thread_seterrno(pthread, EINTR);
-
- /*
- * Flag the timeout in the thread
- * structure:
- */
- pthread->timeout = 1;
-
- /*
- * Change the threads state to allow
- * it to be restarted:
- */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
- }
- }
- }
-
- /* Check if there is a current thread: */
- if (_thread_run != &_thread_kern_thread) {
- /*
- * Save the current time as the time that the thread
- * became inactive:
- */
- _thread_run->last_inactive.tv_sec = tv.tv_sec;
- _thread_run->last_inactive.tv_usec = tv.tv_usec;
-
- /*
- * Accumulate the number of microseconds that this
- * thread has run for:
- */
- _thread_run->slice_usec += (_thread_run->last_inactive.tv_sec -
- _thread_run->last_active.tv_sec) * 1000000 +
- _thread_run->last_inactive.tv_usec -
- _thread_run->last_active.tv_usec;
-
- /*
- * Check if this thread has reached its allocated
- * time slice period:
- */
- if (_thread_run->slice_usec > TIMESLICE_USEC) {
- /*
- * Flag the allocated time slice period as
- * up:
- */
- _thread_run->slice_usec = -1;
- }
- }
- /* Check if an incremental priority update is required: */
- if (((tv.tv_sec - kern_inc_prio_time.tv_sec) * 1000000 +
- tv.tv_usec - kern_inc_prio_time.tv_usec) > INC_PRIO_USEC) {
- /*
- * Enter a loop to look for run-enabled threads that
- * have not run since the last time that an
- * incremental priority update was performed:
- */
- for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
- /* Check if this thread is unable to run: */
- if (pthread->state != PS_RUNNING) {
- }
- /*
- * Check if the last time that this thread
- * was run (as indicated by the last time it
- * became inactive) is before the time that
- * the last incremental priority check was
- * made:
- */
- else if (timercmp(&_thread_run->last_inactive, &kern_inc_prio_time, >)) {
- /*
- * Increment the incremental priority
- * for this thread in the hope that
- * it will eventually get a chance to
- * run:
- */
- (pthread->inc_prio)++;
- }
- }
-
- /* Save the new incremental priority update time: */
- kern_inc_prio_time.tv_sec = tv.tv_sec;
- kern_inc_prio_time.tv_usec = tv.tv_usec;
- }
- /*
- * Enter a loop to look for the first thread of the highest
- * 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) {
- }
- /*
- * Check if no run-enabled thread has been seen or if
- * the current thread has a priority higher than the
- * highest seen so far:
- */
- else if (pthread_h == NULL || (pthread->pthread_priority + pthread->inc_prio) > prio) {
- /*
- * Save this thread as the highest priority
- * thread seen so far:
- */
- pthread_h = pthread;
- prio = pthread->pthread_priority + pthread->inc_prio;
- }
- }
-
- /*
- * Enter a loop to look for a thread that: 1. Is run-enabled.
- * 2. Has the required agregate priority. 3. Has not been
- * allocated its allocated time slice. 4. 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: */
- 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
- * above:
- */
- else if ((pthread->pthread_priority + pthread->inc_prio) != prio) {
- /*
- * Ignore threads which have lower agregate
- * priority.
- */
- }
- /*
- * Check if the current thread reached its time slice
- * allocation last time it ran (or if it has not run
- * yet):
- */
- 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
- * earlier than the last one seen:
- */
- else if (pthread_s == NULL || timercmp(&pthread->last_inactive, &tv1, <)) {
- /*
- * Save the pointer to the current thread as
- * the most eligible thread seen so far:
- */
- pthread_s = pthread;
-
- /*
- * Save the time that the selected thread
- * became inactive:
- */
- tv1.tv_sec = pthread->last_inactive.tv_sec;
- tv1.tv_usec = pthread->last_inactive.tv_usec;
- }
- }
-
- /*
- * Check if no thread was selected according to incomplete
- * time slice allocation:
- */
- if (pthread_s == NULL) {
- /*
- * Enter a loop to look for any other thread that: 1.
- * Is run-enabled. 2. Has the required agregate
- * 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:
- */
- 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 above:
- */
- else if ((pthread->pthread_priority + pthread->inc_prio) != prio) {
- /*
- * Ignore threads which have lower
- * agregate priority.
- */
- }
- /*
- * Check if an eligible thread has not been
- * found yet, or if the current thread has an
- * inactive time earlier than the last one
- * seen:
- */
- else if (pthread_s == NULL || timercmp(&pthread->last_inactive, &tv1, <)) {
- /*
- * Save the pointer to the current
- * thread as the most eligible thread
- * seen so far:
- */
- pthread_s = pthread;
-
- /*
- * Save the time that the selected
- * thread became inactive:
- */
- tv1.tv_sec = pthread->last_inactive.tv_sec;
- tv1.tv_usec = pthread->last_inactive.tv_usec;
- }
- }
- }
- /* Check if there are no threads ready to run: */
- if (pthread_s == NULL) {
- /*
- * Lock the pthread kernel by changing the pointer to
- * the running thread to point to the global kernel
- * thread structure:
- */
- _thread_run = &_thread_kern_thread;
-
- /*
- * There are no threads ready to run, so wait until
- * something happens that changes this condition:
- */
- _thread_kern_select(1);
- } else {
- /* Make the selected thread the current thread: */
- _thread_run = pthread_s;
-
- /*
- * Save the current time as the time that the thread
- * became active:
- */
- _thread_run->last_active.tv_sec = tv.tv_sec;
- _thread_run->last_active.tv_usec = tv.tv_usec;
-
- /*
- * Check if this thread is running for the first time
- * or running again after using its full time slice
- * allocation:
- */
- if (_thread_run->slice_usec == -1) {
- /* Reset the accumulated time slice period: */
- _thread_run->slice_usec = 0;
- }
- /*
- * Reset the incremental priority now that this
- * thread has been given the chance to run:
- */
- _thread_run->inc_prio = 0;
-
- /* Check if there is more than one thread: */
- if (_thread_run != _thread_link_list || _thread_run->nxt != NULL) {
- /*
- * Define the maximum time before a SIGVTALRM
- * is required:
- */
- itimer.it_value.tv_sec = 0;
- itimer.it_value.tv_usec = TIMESLICE_USEC;
-
- /*
- * The interval timer is not reloaded when it
- * times out. The interval time needs to be
- * calculated every time.
- */
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_usec = 0;
-
- /*
- * Enter a loop to look for threads waiting
- * for a time:
- */
- 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 ||
- pthread->state == PS_FDR_WAIT ||
- pthread->state == PS_FDW_WAIT ||
- pthread->state == PS_SELECT_WAIT) {
- /*
- * Check if this thread is to
- * wait forever:
- */
- if (pthread->wakeup_time.tv_sec == -1) {
- }
- /*
- * Check if this thread is to
- * wakeup immediately:
- */
- else if (pthread->wakeup_time.tv_sec == 0 &&
- pthread->wakeup_time.tv_nsec == 0) {
- }
- /*
- * Check if the current time
- * is after the wakeup time:
- */
- else if ((ts.tv_sec > pthread->wakeup_time.tv_sec) ||
- ((ts.tv_sec == pthread->wakeup_time.tv_sec) &&
- (ts.tv_nsec > pthread->wakeup_time.tv_nsec))) {
- } else {
- /*
- * Calculate the time
- * until this thread
- * is ready, allowing
- * for the clock
- * resolution:
- */
- ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec;
- ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec +
- CLOCK_RES_NSEC;
-
- /*
- * Check for
- * underflow of the
- * nanosecond field:
- */
- if (ts1.tv_nsec < 0) {
- /*
- * Allow for
- * the
- * underflow
- * of the
- * nanosecond
- * field:
- */
- ts1.tv_sec--;
- ts1.tv_nsec += 1000000000;
- }
- /*
- * Check for overflow
- * of the nanosecond
- * field:
- */
- if (ts1.tv_nsec >= 1000000000) {
- /*
- * Allow for
- * the
- * overflow
- * of the
- * nanosecond
- * field:
- */
- ts1.tv_sec++;
- ts1.tv_nsec -= 1000000000;
- }
- /*
- * Convert the
- * timespec structure
- * to a timeval
- * structure:
- */
- TIMESPEC_TO_TIMEVAL(&tv, &ts1);
-
- /*
- * Check if the
- * thread will be
- * ready sooner than
- * the earliest one
- * found so far:
- */
- if (timercmp(&tv, &itimer.it_value, <)) {
- /*
- * Update the
- * time
- * value:
- */
- itimer.it_value.tv_sec = tv.tv_sec;
- itimer.it_value.tv_usec = tv.tv_usec;
- }
- }
- }
- }
-
- /*
- * Start the interval timer for the
- * calculated time interval:
- */
- if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) != 0) {
- /*
- * Cannot initialise the timer, so
- * abort this process:
- */
- PANIC("Cannot set virtual timer");
- }
- }
- /* Check if a signal context was saved: */
- if (_thread_run->sig_saved == 1) {
-#ifndef __alpha
- /*
- * Point to the floating point data in the
- * running thread:
- */
- fdata = _thread_run->saved_fp;
-
- /* Restore the floating point state: */
- __asm__("frstor %0": :"m"(*fdata));
-#endif
-
- /*
- * Do a sigreturn to restart the thread that
- * was interrupted by a signal:
- */
- _thread_sys_sigreturn(&_thread_run->saved_sigcontext);
- } 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);
- }
-
- /* This point should not be reached. */
- PANIC("Thread has returned from sigreturn or longjmp");
- }
- }
-
- /* There are no more threads, so exit this process: */
- 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_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:
- /* 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;
-
- /* Waiting on a signal: */
- case PS_SIGWAIT:
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
-
- /* Return the signal number: */
- pthread->signo = sig;
-
- /* Flag the signal as dealt with: */
- done = 1;
- 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;
-
- /* 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)
-{
- /* Change the state of the current thread: */
- _thread_run->state = state;
- _thread_run->fname = fname;
- _thread_run->lineno = lineno;
-
- /* Schedule the next thread that is ready: */
- _thread_kern_sched(NULL);
- return;
-}
-
-static void
-_thread_kern_select(int wait_reqd)
-{
- char bufr[128];
- fd_set fd_set_except;
- fd_set fd_set_read;
- fd_set fd_set_write;
- int count = 0;
- int count_dec;
- int found_one;
- int i;
- int nfds = -1;
- int settimeout;
- pthread_t pthread;
- ssize_t num;
- struct timespec ts;
- struct timespec ts1;
- struct timeval *p_tv;
- struct timeval tv;
- struct timeval tv1;
-
- /* Zero the file descriptor sets: */
- FD_ZERO(&fd_set_read);
- FD_ZERO(&fd_set_write);
- FD_ZERO(&fd_set_except);
-
- /* Check if the caller wants to wait: */
- if (wait_reqd) {
- /*
- * Add the pthread kernel pipe file descriptor to the read
- * set:
- */
- FD_SET(_thread_kern_pipe[0], &fd_set_read);
- nfds = _thread_kern_pipe[0];
-
- /* Get the current time of day: */
- gettimeofday(&tv, NULL);
- TIMEVAL_TO_TIMESPEC(&tv, &ts);
- }
- /* Initialise the time value structure: */
- tv.tv_sec = 0;
- tv.tv_usec = 0;
-
- /*
- * Enter a loop to process threads waiting on either file descriptors
- * or times:
- */
- for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
- /* Assume that this state does not time out: */
- settimeout = 0;
-
- /* Process according to thread state: */
- switch (pthread->state) {
- /*
- * States which do not depend on file descriptor I/O
- * operations or timeouts:
- */
- case PS_DEAD:
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- case PS_JOIN:
- case PS_MUTEX_WAIT:
- case PS_RUNNING:
- case PS_SIGTHREAD:
- case PS_SIGWAIT:
- case PS_STATE_MAX:
- case PS_WAIT_WAIT:
- case PS_SUSPENDED:
- /* Nothing to do here. */
- break;
-
- /* File descriptor read wait: */
- case PS_FDR_WAIT:
- /* Add the file descriptor to the read set: */
- FD_SET(pthread->data.fd.fd, &fd_set_read);
-
- /*
- * Check if this file descriptor is greater than any
- * of those seen so far:
- */
- if (pthread->data.fd.fd > nfds) {
- /* Remember this file descriptor: */
- nfds = pthread->data.fd.fd;
- }
- /* Increment the file descriptor count: */
- count++;
-
- /* This state can time out: */
- settimeout = 1;
- break;
-
- /* File descriptor write wait: */
- case PS_FDW_WAIT:
- /* Add the file descriptor to the write set: */
- FD_SET(pthread->data.fd.fd, &fd_set_write);
-
- /*
- * Check if this file descriptor is greater than any
- * of those seen so far:
- */
- if (pthread->data.fd.fd > nfds) {
- /* Remember this file descriptor: */
- nfds = pthread->data.fd.fd;
- }
- /* Increment the file descriptor count: */
- count++;
-
- /* This state can time out: */
- settimeout = 1;
- break;
-
- /* States that time out: */
- case PS_SLEEP_WAIT:
- case PS_COND_WAIT:
- /* Flag a timeout as required: */
- settimeout = 1;
- break;
-
- /* Select wait: */
- case PS_SELECT_WAIT:
- /*
- * Enter a loop to process each file descriptor in
- * the thread-specific file descriptor sets:
- */
- for (i = 0; i < pthread->data.select_data->nfds; i++) {
- /*
- * Check if this file descriptor is set for
- * exceptions:
- */
- if (FD_ISSET(i, &pthread->data.select_data->exceptfds)) {
- /*
- * Add the file descriptor to the
- * exception set:
- */
- FD_SET(i, &fd_set_except);
-
- /*
- * Increment the file descriptor
- * count:
- */
- count++;
-
- /*
- * Check if this file descriptor is
- * greater than any of those seen so
- * far:
- */
- if (i > nfds) {
- /*
- * Remember this file
- * descriptor:
- */
- nfds = i;
- }
- }
- /*
- * Check if this file descriptor is set for
- * write:
- */
- if (FD_ISSET(i, &pthread->data.select_data->writefds)) {
- /*
- * Add the file descriptor to the
- * write set:
- */
- FD_SET(i, &fd_set_write);
-
- /*
- * Increment the file descriptor
- * count:
- */
- count++;
-
- /*
- * Check if this file descriptor is
- * greater than any of those seen so
- * far:
- */
- if (i > nfds) {
- /*
- * Remember this file
- * descriptor:
- */
- nfds = i;
- }
- }
- /*
- * Check if this file descriptor is set for
- * read:
- */
- if (FD_ISSET(i, &pthread->data.select_data->readfds)) {
- /*
- * Add the file descriptor to the
- * read set:
- */
- FD_SET(i, &fd_set_read);
-
- /*
- * Increment the file descriptor
- * count:
- */
- count++;
-
- /*
- * Check if this file descriptor is
- * greater than any of those seen so
- * far:
- */
- if (i > nfds) {
- /*
- * Remember this file
- * descriptor:
- */
- nfds = i;
- }
- }
- }
-
- /* This state can time out: */
- settimeout = 1;
- break;
- }
-
- /*
- * Check if the caller wants to wait and if the thread state
- * is one that times out:
- */
- if (wait_reqd && settimeout) {
- /* Check if this thread wants to wait forever: */
- if (pthread->wakeup_time.tv_sec == -1) {
- }
- /* Check if this thread doesn't want to wait at all: */
- else if (pthread->wakeup_time.tv_sec == 0 &&
- pthread->wakeup_time.tv_nsec == 0) {
- /* Override the caller's request to wait: */
- wait_reqd = 0;
- } else {
- /*
- * Calculate the time until this thread is
- * ready, allowing for the clock resolution:
- */
- ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec;
- ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec +
- CLOCK_RES_NSEC;
-
- /*
- * Check for underflow of the nanosecond
- * field:
- */
- if (ts1.tv_nsec < 0) {
- /*
- * Allow for the underflow of the
- * nanosecond field:
- */
- ts1.tv_sec--;
- ts1.tv_nsec += 1000000000;
- }
- /*
- * Check for overflow of the nanosecond
- * field:
- */
- if (ts1.tv_nsec >= 1000000000) {
- /*
- * Allow for the overflow of the
- * nanosecond field:
- */
- ts1.tv_sec++;
- ts1.tv_nsec -= 1000000000;
- }
- /*
- * Convert the timespec structure to a
- * timeval structure:
- */
- TIMESPEC_TO_TIMEVAL(&tv1, &ts1);
-
- /*
- * Check if no time value has been found yet,
- * or if the thread will be ready sooner that
- * the earliest one found so far:
- */
- if ((tv.tv_sec == 0 && tv.tv_usec == 0) || timercmp(&tv1, &tv, <)) {
- /* Update the time value: */
- tv.tv_sec = tv1.tv_sec;
- tv.tv_usec = tv1.tv_usec;
- }
- }
- }
- }
-
- /* Check if the caller wants to wait: */
- if (wait_reqd) {
- /* Check if no threads were found with timeouts: */
- if (tv.tv_sec == 0 && tv.tv_usec == 0) {
- /* Wait forever: */
- p_tv = NULL;
- } else {
- /*
- * Point to the time value structure which contains
- * the earliest time that a thread will be ready:
- */
- p_tv = &tv;
- }
-
- /*
- * Flag the pthread kernel as in a select. This is to avoid
- * the window between the next statement that unblocks
- * signals and the select statement which follows.
- */
- _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;
-
- /*
- * Check if it is possible that there are bytes in the kernel
- * read pipe waiting to be read:
- */
- if (count < 0 || FD_ISSET(_thread_kern_pipe[0], &fd_set_read)) {
- /*
- * Check if the kernel read pipe was included in the
- * count:
- */
- if (count > 0) {
- /*
- * Remove the kernel read pipe from the
- * count:
- */
- FD_CLR(_thread_kern_pipe[0], &fd_set_read);
-
- /* Decrement the count of file descriptors: */
- count--;
- }
- /*
- * Enter a loop to read (and trash) bytes from the
- * pthread kernel pipe:
- */
- while ((num = _thread_sys_read(_thread_kern_pipe[0], bufr, sizeof(bufr))) > 0) {
- /*
- * The buffer read contains one byte per
- * 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
- * to complete if the signal occurred between
- * the time when signals were unblocked and
- * the _thread_sys_select select call being
- * made.
- */
- }
- }
- }
- /* Check if there are file descriptors to poll: */
- 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:
- */
- 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:
- */
- 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 {
- /*
- * Enter a loop to look for threads waiting on file
- * descriptors that are flagged as available by the
- * _thread_sys_select syscall:
- */
- for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
- /* Process according to thread state: */
- switch (pthread->state) {
- /*
- * States which do not depend on file
- * descriptor I/O operations:
- */
- case PS_RUNNING:
- case PS_COND_WAIT:
- case PS_DEAD:
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- case PS_JOIN:
- case PS_MUTEX_WAIT:
- case PS_SIGWAIT:
- case PS_SLEEP_WAIT:
- case PS_WAIT_WAIT:
- case PS_SIGTHREAD:
- case PS_STATE_MAX:
- case PS_SUSPENDED:
- /* Nothing to do here. */
- break;
-
- /* File descriptor read wait: */
- case PS_FDR_WAIT:
- /*
- * Check if the file descriptor is available
- * for read:
- */
- if (FD_ISSET(pthread->data.fd.fd, &fd_set_read)) {
- /*
- * Change the thread state to allow
- * it to read from the file when it
- * is scheduled next:
- */
- pthread->state = PS_RUNNING;
- }
- break;
-
- /* File descriptor write wait: */
- case PS_FDW_WAIT:
- /*
- * Check if the file descriptor is available
- * for write:
- */
- if (FD_ISSET(pthread->data.fd.fd, &fd_set_write)) {
- /*
- * Change the thread state to allow
- * it to write to the file when it is
- * scheduled next:
- */
- pthread->state = PS_RUNNING;
- }
- break;
-
- /* Select wait: */
- case PS_SELECT_WAIT:
- /*
- * Reset the flag that indicates if a file
- * descriptor is ready for some type of
- * operation:
- */
- count_dec = 0;
-
- /*
- * Enter a loop to search though the
- * thread-specific select file descriptors
- * for the first descriptor that is ready:
- */
- for (i = 0; i < pthread->data.select_data->nfds && count_dec == 0; i++) {
- /*
- * Check if this file descriptor does
- * not have an exception:
- */
- if (FD_ISSET(i, &pthread->data.select_data->exceptfds) && FD_ISSET(i, &fd_set_except)) {
- /*
- * Flag this file descriptor
- * as ready:
- */
- count_dec = 1;
- }
- /*
- * Check if this file descriptor is
- * not ready for write:
- */
- if (FD_ISSET(i, &pthread->data.select_data->writefds) && FD_ISSET(i, &fd_set_write)) {
- /*
- * Flag this file descriptor
- * as ready:
- */
- count_dec = 1;
- }
- /*
- * Check if this file descriptor is
- * not ready for read:
- */
- if (FD_ISSET(i, &pthread->data.select_data->readfds) && FD_ISSET(i, &fd_set_read)) {
- /*
- * Flag this file descriptor
- * as ready:
- */
- count_dec = 1;
- }
- }
-
- /*
- * Check if any file descriptors are ready
- * for the current thread:
- */
- if (count_dec) {
- /*
- * Reset the count of file
- * descriptors that are ready for
- * this thread:
- */
- found_one = 0;
-
- /*
- * Enter a loop to search though the
- * thread-specific select file
- * descriptors:
- */
- for (i = 0; i < pthread->data.select_data->nfds; i++) {
- /*
- * Reset the count of
- * operations for which the
- * current file descriptor is
- * ready:
- */
- count_dec = 0;
-
- /*
- * Check if this file
- * descriptor is selected for
- * exceptions:
- */
- if (FD_ISSET(i, &pthread->data.select_data->exceptfds)) {
- /*
- * Check if this file
- * descriptor has an
- * exception:
- */
- if (FD_ISSET(i, &fd_set_except)) {
- /*
- * Increment
- * the count
- * for this
- * file:
- */
- count_dec++;
- } else {
- /*
- * Clear the
- * file
- * descriptor
- * in the
- * thread-spec
- * ific file
- * descriptor
- * set:
- */
- FD_CLR(i, &pthread->data.select_data->exceptfds);
- }
- }
- /*
- * Check if this file
- * descriptor is selected for
- * write:
- */
- if (FD_ISSET(i, &pthread->data.select_data->writefds)) {
- /*
- * Check if this file
- * descriptor is
- * ready for write:
- */
- if (FD_ISSET(i, &fd_set_write)) {
- /*
- * Increment
- * the count
- * for this
- * file:
- */
- count_dec++;
- } else {
- /*
- * Clear the
- * file
- * descriptor
- * in the
- * thread-spec
- * ific file
- * descriptor
- * set:
- */
- FD_CLR(i, &pthread->data.select_data->writefds);
- }
- }
- /*
- * Check if this file
- * descriptor is selected for
- * read:
- */
- if (FD_ISSET(i, &pthread->data.select_data->readfds)) {
- /*
- * Check if this file
- * descriptor is
- * ready for read:
- */
- if (FD_ISSET(i, &fd_set_read)) {
- /*
- * Increment
- * the count
- * for this
- * file:
- */
- count_dec++;
- } else {
- /*
- * Clear the
- * file
- * descriptor
- * in the
- * thread-spec
- * ific file
- * descriptor
- * set:
- */
- FD_CLR(i, &pthread->data.select_data->readfds);
- }
- }
- /*
- * Check if the current file
- * descriptor is ready for
- * any one of the operations:
- */
- if (count_dec > 0) {
- /*
- * Increment the
- * count of file
- * descriptors that
- * are ready for the
- * current thread:
- */
- found_one++;
- }
- }
-
- /*
- * Return the number of file
- * descriptors that are ready:
- */
- pthread->data.select_data->nfds = found_one;
-
- /*
- * Change the state of the current
- * thread to run:
- */
- pthread->state = PS_RUNNING;
- }
- break;
- }
- }
- }
-
- /* Nothing to return. */
- return;
-}
-
-void
-_thread_kern_set_timeout(struct timespec * timeout)
-{
- struct timespec current_time;
- struct timeval tv;
-
- /* Reset the timeout flag for the running thread: */
- _thread_run->timeout = 0;
-
- /* Check if the thread is to wait forever: */
- if (timeout == NULL) {
- /*
- * Set the wakeup time to something that can be recognised as
- * different to an actual time of day:
- */
- _thread_run->wakeup_time.tv_sec = -1;
- _thread_run->wakeup_time.tv_nsec = -1;
- }
- /* Check if no waiting is required: */
- else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
- /* Set the wake up time to 'immediately': */
- _thread_run->wakeup_time.tv_sec = 0;
- _thread_run->wakeup_time.tv_nsec = 0;
- } else {
- /* Get the current time: */
- gettimeofday(&tv, NULL);
- TIMEVAL_TO_TIMESPEC(&tv, &current_time);
-
- /* Calculate the time for the current thread to wake up: */
- _thread_run->wakeup_time.tv_sec = current_time.tv_sec + timeout->tv_sec;
- _thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + timeout->tv_nsec;
-
- /* Check if the nanosecond field needs to wrap: */
- if (_thread_run->wakeup_time.tv_nsec >= 1000000000) {
- /* Wrap the nanosecond field: */
- _thread_run->wakeup_time.tv_sec += 1;
- _thread_run->wakeup_time.tv_nsec -= 1000000000;
- }
- }
- return;
-}
-#endif
OpenPOWER on IntegriCloud