o Use a daemon thread to monitor signal events in kernel, if pending

signals were changed in kernel, it will retrieve the pending set and
  try to find a thread to dispatch the signal. The dispatching process
  can be rolled back if the signal is no longer in kernel.

o Create two functions _thr_signal_init() and _thr_signal_deinit(),
  all signal action settings are retrieved from kernel when threading
  mode is turned on, after a fork(), child process will reset them to
  user settings by calling _thr_signal_deinit(). when threading mode
  is not turned on, all signal operations are direct past to kernel.

o When a thread generated a synchoronous signals and its context returned
  from completed list, UTS will retrieve the signal from its mailbox and try
  to deliver the signal to thread.

o Context signal mask is now only used when delivering signals, thread's
  current signal mask is always the one in pthread structure.

o Remove have_signals field in pthread structure, replace it with
  psf_valid in pthread_signal_frame. when psf_valid is true, in context
  switch time, thread will backout itself from some mutex/condition
  internal queues, then begin to process signals. when a thread is not
  at blocked state and running, check_pending indicates there are signals
  for the thread, after preempted and then resumed time, UTS will try to
  deliver signals to the thread.

o At signal delivering time, not only pending signals in thread will be
  scanned, process's pending signals will be scanned too.

o Change sigwait code a bit, remove field sigwait in pthread_wait_data,
  replace it with oldsigmask in pthread structure, when a thread calls
  sigwait(), its current signal mask is backuped to oldsigmask, and waitset
  is copied to its signal mask and when the thread gets a signal in the
  waitset range, its current signal mask is restored from oldsigmask,
  these are done in atomic fashion.

o Two additional POSIX APIs are implemented, sigwaitinfo() and sigtimedwait().

o Signal code locking is better than previous, there is fewer race conditions.

o Temporary disable most of code in _kse_single_thread as it is not safe
  after fork().
This commit is contained in:
davidxu 2003-06-28 09:55:02 +00:00
parent 8109f8e495
commit 8980e28992
27 changed files with 1624 additions and 1174 deletions

View File

@ -54,5 +54,8 @@ __strong_reference(memcpy, _thr_memcpy);
__strong_reference(strcpy, _thr_strcpy); __strong_reference(strcpy, _thr_strcpy);
__strong_reference(strlen, _thr_strlen); __strong_reference(strlen, _thr_strlen);
__strong_reference(bzero, _thr_bzero); __strong_reference(bzero, _thr_bzero);
__strong_reference(bcopy, _thr_bcopy);
__strong_reference(__sys_write, _thr__sys_write); __strong_reference(__sys_write, _thr__sys_write);
__strong_reference(__sys_sigtimedwait, _thr__sys_sigtimedwait);

View File

@ -77,7 +77,7 @@ _thread_dump_info(void)
int fd, i; int fd, i;
for (i = 0; i < 100000; i++) { for (i = 0; i < 100000; i++) {
snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i", snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i",
getpid(), i); getpid(), i);
/* Open the dump file for append and create it if necessary: */ /* Open the dump file for append and create it if necessary: */
if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL, if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
@ -166,11 +166,26 @@ dump_thread(int fd, pthread_t pthread, int long_version)
strcpy(s, "This is the initial thread\n"); strcpy(s, "This is the initial thread\n");
__sys_write(fd, s, strlen(s)); __sys_write(fd, s, strlen(s));
} }
/* Check if this is the signal daemon thread: */
if (pthread == _thr_sig_daemon) {
/* Output a record for the signal thread: */
strcpy(s, "This is the signal daemon thread\n");
__sys_write(fd, s, strlen(s));
}
/* Process according to thread state: */ /* Process according to thread state: */
switch (pthread->state) { switch (pthread->state) {
case PS_SIGWAIT: case PS_SIGWAIT:
snprintf(s, sizeof(s), "sigmask (hi)"); snprintf(s, sizeof(s), "sigmask (hi)");
__sys_write(fd, s, strlen(s)); __sys_write(fd, s, strlen(s));
for (i = _SIG_WORDS - 1; i >= 0; i--) {
snprintf(s, sizeof(s), "%08x\n",
pthread->oldsigmask.__bits[i]);
__sys_write(fd, s, strlen(s));
}
snprintf(s, sizeof(s), "(lo)\n");
__sys_write(fd, s, strlen(s));
snprintf(s, sizeof(s), "waitset (hi)");
__sys_write(fd, s, strlen(s));
for (i = _SIG_WORDS - 1; i >= 0; i--) { for (i = _SIG_WORDS - 1; i >= 0; i--) {
snprintf(s, sizeof(s), "%08x\n", snprintf(s, sizeof(s), "%08x\n",
pthread->sigmask.__bits[i]); pthread->sigmask.__bits[i]);

View File

@ -39,6 +39,7 @@
#include "namespace.h" #include "namespace.h"
#include <sys/param.h> #include <sys/param.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/signalvar.h>
#include <machine/reg.h> #include <machine/reg.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -365,14 +366,13 @@ init_main_thread(struct pthread *thread)
thread->name = strdup("initial thread"); thread->name = strdup("initial thread");
/* Initialize the thread for signals: */ /* Initialize the thread for signals: */
sigemptyset(&thread->sigmask); SIGEMPTYSET(thread->sigmask);
/* /*
* Set up the thread mailbox. The threads saved context * Set up the thread mailbox. The threads saved context
* is also in the mailbox. * is also in the mailbox.
*/ */
thread->tmbx.tm_udata = thread; thread->tmbx.tm_udata = thread;
thread->tmbx.tm_context.uc_sigmask = thread->sigmask;
thread->tmbx.tm_context.uc_stack.ss_size = thread->attr.stacksize_attr; thread->tmbx.tm_context.uc_stack.ss_size = thread->attr.stacksize_attr;
thread->tmbx.tm_context.uc_stack.ss_sp = thread->attr.stackaddr_attr; thread->tmbx.tm_context.uc_stack.ss_sp = thread->attr.stackaddr_attr;
@ -407,10 +407,8 @@ static void
init_private(void) init_private(void)
{ {
struct clockinfo clockinfo; struct clockinfo clockinfo;
struct sigaction act;
size_t len; size_t len;
int mib[2]; int mib[2];
int i;
/* /*
* Avoid reinitializing some things if they don't need to be, * Avoid reinitializing some things if they don't need to be,
@ -448,36 +446,6 @@ init_private(void)
_thr_page_size = getpagesize(); _thr_page_size = getpagesize();
_thr_guard_default = _thr_page_size; _thr_guard_default = _thr_page_size;
/* Enter a loop to get the existing signal status: */
for (i = 1; i < NSIG; i++) {
/* Check for signals which cannot be trapped: */
if (i == SIGKILL || i == SIGSTOP) {
}
/* Get the signal handler details: */
else if (__sys_sigaction(i, NULL,
&_thread_sigact[i - 1]) != 0) {
/*
* Abort this process if signal
* initialisation fails:
*/
PANIC("Cannot read signal handler info");
}
}
/*
* Install the signal handler for SIGINFO. It isn't
* really needed, but it is nice to have for debugging
* purposes.
*/
if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
/*
* Abort this process if signal initialisation fails:
*/
PANIC("Cannot initialize signal handler");
}
_thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
init_once = 1; /* Don't do this again. */ init_once = 1; /* Don't do this again. */
} else { } else {
/* /*
@ -495,8 +463,6 @@ init_private(void)
TAILQ_INIT(&_thread_list); TAILQ_INIT(&_thread_list);
TAILQ_INIT(&_thread_gc_list); TAILQ_INIT(&_thread_gc_list);
/* Enter a loop to get the existing signal status: */
/* Initialize the SIG_DFL dummy handler count. */ /* Initialize the SIG_DFL dummy handler count. */
bzero(_thread_dfl_count, sizeof(_thread_dfl_count)); bzero(_thread_dfl_count, sizeof(_thread_dfl_count));
@ -520,8 +486,7 @@ init_private(void)
_thr_spinlock_init(); _thr_spinlock_init();
/* Clear pending signals and get the process signal mask. */ /* Clear pending signals and get the process signal mask. */
sigemptyset(&_thr_proc_sigpending); SIGEMPTYSET(_thr_proc_sigpending);
__sys_sigprocmask(SIG_SETMASK, NULL, &_thr_proc_sigmask);
/* /*
* _thread_list_lock and _kse_count are initialized * _thread_list_lock and _kse_count are initialized

View File

@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/signalvar.h> #include <sys/signalvar.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <machine/atomic.h> #include <machine/atomic.h>
#include <machine/sigframe.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
@ -125,7 +126,6 @@ static void dump_queues(struct kse *curkse);
#endif #endif
static void kse_check_completed(struct kse *kse); static void kse_check_completed(struct kse *kse);
static void kse_check_waitq(struct kse *kse); static void kse_check_waitq(struct kse *kse);
static void kse_check_signals(struct kse *kse);
static void kse_fini(struct kse *curkse); static void kse_fini(struct kse *curkse);
static void kse_reinit(struct kse *kse); static void kse_reinit(struct kse *kse);
static void kse_sched_multi(struct kse *curkse); static void kse_sched_multi(struct kse *curkse);
@ -143,27 +143,39 @@ static void kse_wakeup_multi(struct kse *curkse);
static void kse_wakeup_one(struct pthread *thread); static void kse_wakeup_one(struct pthread *thread);
static void thr_cleanup(struct kse *kse, struct pthread *curthread); static void thr_cleanup(struct kse *kse, struct pthread *curthread);
static void thr_link(struct pthread *thread); static void thr_link(struct pthread *thread);
static void thr_resume_wrapper(int unused_1, siginfo_t *unused_2, static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
ucontext_t *ucp);
static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp, static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf); struct pthread_sigframe *psf);
static int thr_timedout(struct pthread *thread, struct timespec *curtime); static int thr_timedout(struct pthread *thread, struct timespec *curtime);
static void thr_unlink(struct pthread *thread); static void thr_unlink(struct pthread *thread);
/* /*
* This is called after a fork(). * This is called after a fork().
* No locks need to be taken here since we are guaranteed to be * No locks need to be taken here since we are guaranteed to be
* single threaded. * single threaded.
*
* XXX
* POSIX says for threaded process, fork() function is used
* only to run new programs, and the effects of calling functions
* that require certain resources between the call to fork() and
* the call to an exec function are undefined.
*
* Here it is not safe to reinitialize the library after fork().
* Because memory management may be corrupted, further calling
* malloc()/free() may cause undefined behavior.
*/ */
void void
_kse_single_thread(struct pthread *curthread) _kse_single_thread(struct pthread *curthread)
{ {
#ifdef NOTYET
struct kse *kse; struct kse *kse;
struct kse_group *kseg; struct kse_group *kseg;
struct pthread *thread; struct pthread *thread;
kse_critical_t crit; kse_critical_t crit;
int i; int i;
/* /*
* Disable upcalls and clear the threaded flag. * Disable upcalls and clear the threaded flag.
* XXX - I don't think we need to disable upcalls after a fork(). * XXX - I don't think we need to disable upcalls after a fork().
@ -172,6 +184,7 @@ _kse_single_thread(struct pthread *curthread)
crit = _kse_critical_enter(); crit = _kse_critical_enter();
__isthreaded = 0; __isthreaded = 0;
active_threads = 1; active_threads = 1;
_thr_signal_deinit();
/* /*
* Enter a loop to remove and free all threads other than * Enter a loop to remove and free all threads other than
@ -201,7 +214,7 @@ _kse_single_thread(struct pthread *curthread)
TAILQ_INIT(&curthread->mutexq); /* initialize mutex queue */ TAILQ_INIT(&curthread->mutexq); /* initialize mutex queue */
curthread->joiner = NULL; /* no joining threads yet */ curthread->joiner = NULL; /* no joining threads yet */
curthread->refcount = 0; curthread->refcount = 0;
sigemptyset(&curthread->sigpend); /* clear pending signals */ SIGEMPTYSET(curthread->sigpend); /* clear pending signals */
if (curthread->specific != NULL) { if (curthread->specific != NULL) {
free(curthread->specific); free(curthread->specific);
curthread->specific = NULL; curthread->specific = NULL;
@ -307,6 +320,12 @@ _kse_single_thread(struct pthread *curthread)
curthread->kseg = NULL; curthread->kseg = NULL;
_kse_initial = NULL; _kse_initial = NULL;
_libpthread_init(curthread); _libpthread_init(curthread);
#else
_ksd_readandclear_tmbx();
__isthreaded = 0;
active_threads = 0;
_thr_signal_deinit();
#endif
} }
/* /*
@ -363,15 +382,17 @@ _kse_setthreaded(int threaded)
* Tell the kernel to create a KSE for the initial thread * Tell the kernel to create a KSE for the initial thread
* and enable upcalls in it. * and enable upcalls in it.
*/ */
_thr_signal_init();
_kse_initial->k_flags |= KF_STARTED; _kse_initial->k_flags |= KF_STARTED;
if (kse_create(&_kse_initial->k_mbx, 0) != 0) { if (kse_create(&_kse_initial->k_mbx, 0) != 0) {
_kse_initial->k_flags &= ~KF_STARTED; _kse_initial->k_flags &= ~KF_STARTED;
__isthreaded = 0; __isthreaded = 0;
/* may abort() */ /* may abort() */
DBG_MSG("kse_create failed\n"); PANIC("kse_create() failed\n");
return (-1); return (-1);
} }
KSE_SET_MBOX(_kse_initial, _thr_initial); KSE_SET_MBOX(_kse_initial, _thr_initial);
_thr_start_sig_daemon();
_thr_setmaxconcurrency(); _thr_setmaxconcurrency();
} }
return (0); return (0);
@ -536,6 +557,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
int ret; int ret;
volatile int uts_once; volatile int uts_once;
volatile int resume_once = 0; volatile int resume_once = 0;
ucontext_t uc;
/* We're in the scheduler, 5 by 5: */ /* We're in the scheduler, 5 by 5: */
curkse = _get_curkse(); curkse = _get_curkse();
@ -552,7 +574,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
* a thread can be interrupted by other signals while * a thread can be interrupted by other signals while
* it is running down pending signals. * it is running down pending signals.
*/ */
sigemptyset(&psf.psf_sigset); psf.psf_valid = 0;
curthread->curframe = &psf; curthread->curframe = &psf;
/* /*
@ -561,6 +583,8 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
* o The current thread is dead; it's stack needs to be * o The current thread is dead; it's stack needs to be
* cleaned up and it can't be done while operating on * cleaned up and it can't be done while operating on
* it. * it.
* o The current thread has signals pending, should
* let scheduler install signal trampoline for us.
* o There are no runnable threads. * o There are no runnable threads.
* o The next thread to run won't unlock the scheduler * o The next thread to run won't unlock the scheduler
* lock. A side note: the current thread may be run * lock. A side note: the current thread may be run
@ -570,8 +594,10 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
if ((curthread->state == PS_DEAD) || if ((curthread->state == PS_DEAD) ||
(((td = KSE_RUNQ_FIRST(curkse)) == NULL) && (((td = KSE_RUNQ_FIRST(curkse)) == NULL) &&
(curthread->state != PS_RUNNING)) || (curthread->state != PS_RUNNING)) ||
((td != NULL) && (td->lock_switch == 0))) ((td != NULL) && (td->lock_switch == 0))) {
curkse->k_switch = 1;
_thread_enter_uts(&curthread->tmbx, &curkse->k_mbx); _thread_enter_uts(&curthread->tmbx, &curkse->k_mbx);
}
else { else {
uts_once = 0; uts_once = 0;
THR_GETCONTEXT(&curthread->tmbx.tm_context); THR_GETCONTEXT(&curthread->tmbx.tm_context);
@ -623,6 +649,15 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
} }
} }
if (psf.psf_valid) {
/*
* It is ugly we must increase critical count, because we
* have a frame saved, we must backout state in psf
* before we can process signals.
*/
curthread->critical_count++;
}
if (curthread->lock_switch != 0) { if (curthread->lock_switch != 0) {
/* /*
* Unlock the scheduling queue and leave the * Unlock the scheduling queue and leave the
@ -638,11 +673,15 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
/* /*
* This thread is being resumed; check for cancellations. * This thread is being resumed; check for cancellations.
*/ */
if ((resume_once == 0) && (!THR_IN_CRITICAL(curthread))) { if ((psf.psf_valid || curthread->check_pending)) {
resume_once = 0;
THR_GETCONTEXT(&uc);
if (resume_once == 0) {
resume_once = 1; resume_once = 1;
thr_resume_check(curthread, &curthread->tmbx.tm_context, &psf); curthread->check_pending = 0;
thr_resume_check(curthread, &uc, &psf);
}
} }
THR_ACTIVATE_LAST_LOCK(curthread); THR_ACTIVATE_LAST_LOCK(curthread);
} }
@ -747,9 +786,6 @@ kse_sched_single(struct kse *curkse)
KSE_WAITQ_REMOVE(curkse, td_wait); KSE_WAITQ_REMOVE(curkse, td_wait);
} }
} }
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
kse_check_signals(curkse);
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
} }
/* Remove the frame reference. */ /* Remove the frame reference. */
@ -810,12 +846,12 @@ kse_sched_multi(struct kse *curkse)
KSE_CLEAR_WAIT(curkse); KSE_CLEAR_WAIT(curkse);
} }
/* Lock the scheduling lock. */ /*If this is an upcall; take the scheduler lock. */
curthread = curkse->k_curthread; if (curkse->k_switch == 0)
if ((curthread == NULL) || (curthread->need_switchout == 0)) {
/* This is an upcall; take the scheduler lock. */
KSE_SCHED_LOCK(curkse, curkse->k_kseg); KSE_SCHED_LOCK(curkse, curkse->k_kseg);
} curkse->k_switch = 0;
curthread = curkse->k_curthread;
if (KSE_IS_IDLE(curkse)) { if (KSE_IS_IDLE(curkse)) {
KSE_CLEAR_IDLE(curkse); KSE_CLEAR_IDLE(curkse);
@ -879,11 +915,6 @@ kse_sched_multi(struct kse *curkse)
kse_wakeup_multi(curkse); kse_wakeup_multi(curkse);
/* This has to be done without the scheduling lock held. */
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
kse_check_signals(curkse);
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
#ifdef DEBUG_THREAD_KERN #ifdef DEBUG_THREAD_KERN
dump_queues(curkse); dump_queues(curkse);
#endif #endif
@ -899,9 +930,6 @@ kse_sched_multi(struct kse *curkse)
kse_wait(curkse, td_wait); kse_wait(curkse, td_wait);
kse_check_completed(curkse); kse_check_completed(curkse);
kse_check_waitq(curkse); kse_check_waitq(curkse);
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
kse_check_signals(curkse);
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
} }
/* Check for no more threads: */ /* Check for no more threads: */
@ -966,15 +994,19 @@ kse_sched_multi(struct kse *curkse)
* signal frame to the thread's context. * signal frame to the thread's context.
*/ */
#ifdef NOT_YET #ifdef NOT_YET
if ((curframe == NULL) && ((curthread->have_signals != 0) || if ((((curframe == NULL) && (curthread->check_pending != 0)) ||
(((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) && (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)))) ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))) &&
!THR_IN_CRITICAL(curthread))
signalcontext(&curthread->tmbx.tm_context, 0, signalcontext(&curthread->tmbx.tm_context, 0,
(__sighandler_t *)thr_resume_wrapper); (__sighandler_t *)thr_resume_wrapper);
#else #else
if ((curframe == NULL) && (curthread->have_signals != 0)) if ((curframe == NULL) && (curthread->check_pending != 0) &&
!THR_IN_CRITICAL(curthread)) {
curthread->check_pending = 0;
signalcontext(&curthread->tmbx.tm_context, 0, signalcontext(&curthread->tmbx.tm_context, 0,
(__sighandler_t *)thr_resume_wrapper); (__sighandler_t *)thr_resume_wrapper);
}
#endif #endif
/* /*
* Continue the thread at its current frame: * Continue the thread at its current frame:
@ -999,61 +1031,31 @@ kse_sched_multi(struct kse *curkse)
} }
static void static void
kse_check_signals(struct kse *curkse) thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
{
sigset_t sigset;
int i;
/* Deliver posted signals. */
for (i = 0; i < _SIG_WORDS; i++) {
atomic_swap_int(&curkse->k_mbx.km_sigscaught.__bits[i],
0, &sigset.__bits[i]);
}
if (SIGNOTEMPTY(sigset)) {
/*
* Dispatch each signal.
*
* XXX - There is no siginfo for any of these.
* I think there should be, especially for
* signals from other processes (si_pid, si_uid).
*/
for (i = 1; i < NSIG; i++) {
if (sigismember(&sigset, i) != 0) {
DBG_MSG("Dispatching signal %d\n", i);
_thr_sig_dispatch(curkse, i,
NULL /* no siginfo */);
}
}
sigemptyset(&sigset);
__sys_sigprocmask(SIG_SETMASK, &sigset, NULL);
}
}
static void
thr_resume_wrapper(int unused_1, siginfo_t *unused_2, ucontext_t *ucp)
{ {
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
struct kse *curkse;
int ret;
DBG_MSG(">>> sig wrapper\n");
if (curthread->lock_switch)
PANIC("thr_resume_wrapper, lock_switch != 0\n");
thr_resume_check(curthread, ucp, NULL); thr_resume_check(curthread, ucp, NULL);
_kse_critical_enter();
curkse = _get_curkse();
curthread->tmbx.tm_context = *ucp;
ret = _thread_switch(&curthread->tmbx, &curkse->k_mbx.km_curthread);
if (ret != 0)
PANIC("thr_resume_wrapper: thread has returned "
"from _thread_switch");
/* THR_SETCONTEXT(ucp); */ /* not work, why ? */
} }
static void static void
thr_resume_check(struct pthread *curthread, ucontext_t *ucp, thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf) struct pthread_sigframe *psf)
{ {
/* Check signals before cancellations. */
while (curthread->have_signals != 0) {
/* Clear the pending flag. */
curthread->have_signals = 0;
/*
* It's perfectly valid, though not portable, for
* signal handlers to munge their interrupted context
* and expect to return to it. Ensure we use the
* correct context when running down signals.
*/
_thr_sig_rundown(curthread, ucp, psf); _thr_sig_rundown(curthread, ucp, psf);
}
#ifdef NOT_YET #ifdef NOT_YET
if (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) && if (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
@ -1124,7 +1126,7 @@ thr_cleanup(struct kse *curkse, struct pthread *thread)
THR_GCLIST_ADD(thread); THR_GCLIST_ADD(thread);
/* Use thread_list_lock */ /* Use thread_list_lock */
active_threads--; active_threads--;
if (active_threads == 0) { if (active_threads == 1) {
KSE_LOCK_RELEASE(curkse, &_thread_list_lock); KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
exit(0); exit(0);
} }
@ -1203,8 +1205,15 @@ _thr_gc(struct pthread *curthread)
KSE_LOCK_RELEASE(curthread->kse, &kse_lock); KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
_kse_critical_leave(crit); _kse_critical_leave(crit);
} }
/*
* XXX we don't free initial thread, because there might
* have some code referencing initial thread.
*/
if (td != _thr_initial) {
DBG_MSG("Freeing thread %p\n", td); DBG_MSG("Freeing thread %p\n", td);
_thr_free(curthread, td); _thr_free(curthread, td);
} else
DBG_MSG("Initial thread won't be freed\n");
} }
/* XXX free kse and ksegrp list should be looked as well */ /* XXX free kse and ksegrp list should be looked as well */
} }
@ -1216,7 +1225,6 @@ _thr_gc(struct pthread *curthread)
int int
_thr_schedule_add(struct pthread *curthread, struct pthread *newthread) _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
{ {
struct kse *curkse;
kse_critical_t crit; kse_critical_t crit;
int ret; int ret;
@ -1250,15 +1258,11 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
/* /*
* This thread needs a new KSE and KSEG. * This thread needs a new KSE and KSEG.
*/ */
crit = _kse_critical_enter(); newthread->kse->k_flags &= ~KF_INITIALIZED;
curkse = _get_curkse(); newthread->kse->k_flags |= KF_STARTED;
_ksd_setprivate(&newthread->kse->k_ksd);
newthread->kse->k_flags |= KF_INITIALIZED|KF_STARTED;
ret = kse_create(&newthread->kse->k_mbx, 1); ret = kse_create(&newthread->kse->k_mbx, 1);
if (ret != 0) if (ret != 0)
ret = errno; ret = errno;
_ksd_setprivate(&curkse->k_ksd);
_kse_critical_leave(crit);
} }
else { else {
/* /*
@ -1266,6 +1270,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
* assigned threads. If the new thread is runnable, also * assigned threads. If the new thread is runnable, also
* add it to the KSE's run queue. * add it to the KSE's run queue.
*/ */
crit = _kse_critical_enter();
KSE_SCHED_LOCK(curthread->kse, newthread->kseg); KSE_SCHED_LOCK(curthread->kse, newthread->kseg);
KSEG_THRQ_ADD(newthread->kseg, newthread); KSEG_THRQ_ADD(newthread->kseg, newthread);
if (newthread->state == PS_RUNNING) if (newthread->state == PS_RUNNING)
@ -1288,6 +1293,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
kse_wakeup_one(newthread); kse_wakeup_one(newthread);
} }
KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg); KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg);
_kse_critical_leave(crit);
ret = 0; ret = 0;
} }
if (ret != 0) if (ret != 0)
@ -1328,6 +1334,7 @@ kse_check_completed(struct kse *kse)
{ {
struct pthread *thread; struct pthread *thread;
struct kse_thr_mailbox *completed; struct kse_thr_mailbox *completed;
int sig;
if ((completed = kse->k_mbx.km_completed) != NULL) { if ((completed = kse->k_mbx.km_completed) != NULL) {
kse->k_mbx.km_completed = NULL; kse->k_mbx.km_completed = NULL;
@ -1348,6 +1355,13 @@ kse_check_completed(struct kse *kse)
thread->active = 0; thread->active = 0;
} }
} }
if ((sig = thread->tmbx.tm_syncsig.si_signo) != 0) {
if (SIGISMEMBER(thread->sigmask, sig))
SIGADDSET(thread->sigpend, sig);
else
_thr_sig_add(thread, sig, &thread->tmbx.tm_syncsig);
thread->tmbx.tm_syncsig.si_signo = 0;
}
completed = completed->tm_next; completed = completed->tm_next;
} }
} }
@ -1446,6 +1460,8 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
{ {
int level; int level;
int i; int i;
int restart;
siginfo_t siginfo;
/* /*
* Place the currently running thread into the * Place the currently running thread into the
@ -1459,15 +1475,25 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
thread->need_switchout = 0; thread->need_switchout = 0;
/* This thread must have blocked in the kernel. */ /* This thread must have blocked in the kernel. */
/* thread->slice_usec = -1;*/ /* restart timeslice */ /* thread->slice_usec = -1;*/ /* restart timeslice */
/*
* XXX - Check for pending signals for this thread to
* see if we need to interrupt it in the kernel.
*/
/* if (thread->check_pending != 0) */
if ((thread->slice_usec != -1) && if ((thread->slice_usec != -1) &&
(thread->attr.sched_policy != SCHED_FIFO)) (thread->attr.sched_policy != SCHED_FIFO))
thread->slice_usec += (thread->tmbx.tm_uticks thread->slice_usec += (thread->tmbx.tm_uticks
+ thread->tmbx.tm_sticks) * _clock_res_usec; + thread->tmbx.tm_sticks) * _clock_res_usec;
/*
* Check for pending signals for this thread to
* see if we need to interrupt it in the kernel.
*/
if (thread->check_pending != 0) {
for (i = 1; i <= _SIG_MAXSIG; ++i) {
if (SIGISMEMBER(thread->sigpend, i) &&
!SIGISMEMBER(thread->sigmask, i)) {
restart = _thread_sigact[1 - 1].sa_flags & SA_RESTART;
kse_thr_interrupt(&thread->tmbx,
restart ? -2 : -1);
break;
}
}
}
} }
else { else {
switch (thread->state) { switch (thread->state) {
@ -1507,10 +1533,12 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
THR_SET_STATE(thread, PS_RUNNING); THR_SET_STATE(thread, PS_RUNNING);
break; break;
case PS_SIGWAIT:
KSE_WAITQ_INSERT(kse, thread);
break;
case PS_JOIN: case PS_JOIN:
case PS_MUTEX_WAIT: case PS_MUTEX_WAIT:
case PS_SIGSUSPEND: case PS_SIGSUSPEND:
case PS_SIGWAIT:
case PS_SUSPENDED: case PS_SUSPENDED:
case PS_DEADLOCK: case PS_DEADLOCK:
default: default:
@ -1564,12 +1592,19 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
if (thread->check_pending != 0) { if (thread->check_pending != 0) {
/* Install pending signals into the frame. */ /* Install pending signals into the frame. */
thread->check_pending = 0; thread->check_pending = 0;
for (i = 0; i < _SIG_MAXSIG; i++) { KSE_LOCK_ACQUIRE(kse, &_thread_signal_lock);
if (sigismember(&thread->sigpend, i) && for (i = 1; i <= _SIG_MAXSIG; i++) {
!sigismember(&thread->tmbx.tm_context.uc_sigmask, i)) if (SIGISMEMBER(thread->sigmask, i))
continue;
if (SIGISMEMBER(thread->sigpend, i))
_thr_sig_add(thread, i, &thread->siginfo[i]); _thr_sig_add(thread, i, &thread->siginfo[i]);
else if (SIGISMEMBER(_thr_proc_sigpending, i) &&
_thr_getprocsig_unlocked(i, &siginfo)) {
_thr_sig_add(thread, i, &siginfo);
} }
} }
KSE_LOCK_RELEASE(kse, &_thread_signal_lock);
}
} }
/* /*
@ -2016,6 +2051,10 @@ _kse_alloc(struct pthread *curthread)
_lockuser_destroy(&kse->k_lockusers[i]); _lockuser_destroy(&kse->k_lockusers[i]);
} }
free(kse); free(kse);
if (curthread != NULL) {
KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
_kse_critical_leave(crit);
}
return (NULL); return (NULL);
} }
kse->k_flags = 0; kse->k_flags = 0;
@ -2044,7 +2083,7 @@ kse_reinit(struct kse *kse)
kse->k_kseg = 0; kse->k_kseg = 0;
kse->k_schedq = 0; kse->k_schedq = 0;
kse->k_locklevel = 0; kse->k_locklevel = 0;
sigemptyset(&kse->k_sigmask); SIGEMPTYSET(kse->k_sigmask);
bzero(&kse->k_sigq, sizeof(kse->k_sigq)); bzero(&kse->k_sigq, sizeof(kse->k_sigq));
kse->k_check_sigq = 0; kse->k_check_sigq = 0;
kse->k_flags = 0; kse->k_flags = 0;
@ -2053,6 +2092,7 @@ kse_reinit(struct kse *kse)
kse->k_error = 0; kse->k_error = 0;
kse->k_cpu = 0; kse->k_cpu = 0;
kse->k_done = 0; kse->k_done = 0;
kse->k_switch = 0;
} }
void void
@ -2171,10 +2211,12 @@ thr_link(struct pthread *thread)
{ {
kse_critical_t crit; kse_critical_t crit;
struct kse *curkse; struct kse *curkse;
struct pthread *curthread;
crit = _kse_critical_enter(); crit = _kse_critical_enter();
curkse = _get_curkse(); curkse = _get_curkse();
curthread = _get_curthread();
thread->sigmask = curthread->sigmask;
KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
/* /*
* Initialize the unique id (which GDB uses to track * Initialize the unique id (which GDB uses to track

View File

@ -45,7 +45,7 @@ _pthread_kill(pthread_t pthread, int sig)
int ret; int ret;
/* Check for invalid signal numbers: */ /* Check for invalid signal numbers: */
if (sig < 0 || sig >= NSIG) if (sig < 0 || sig > _SIG_MAXSIG)
/* Invalid signal: */ /* Invalid signal: */
ret = EINVAL; ret = EINVAL;
/* /*

View File

@ -171,7 +171,7 @@ typedef struct kse_thr_mailbox *kse_critical_t;
struct kse_group; struct kse_group;
#define MAX_KSE_LOCKLEVEL 3 #define MAX_KSE_LOCKLEVEL 5
struct kse { struct kse {
struct kse_mailbox k_mbx; /* kernel kse mailbox */ struct kse_mailbox k_mbx; /* kernel kse mailbox */
/* -- location and order specific items for gdb -- */ /* -- location and order specific items for gdb -- */
@ -190,7 +190,7 @@ struct kse {
struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL]; struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL];
int k_locklevel; int k_locklevel;
sigset_t k_sigmask; sigset_t k_sigmask;
struct sigstatus k_sigq[NSIG]; struct sigstatus k_sigq[_SIG_MAXSIG];
stack_t k_stack; stack_t k_stack;
int k_check_sigq; int k_check_sigq;
int k_flags; int k_flags;
@ -201,6 +201,7 @@ struct kse {
int k_error; /* syscall errno in critical */ int k_error; /* syscall errno in critical */
int k_cpu; /* CPU ID when bound */ int k_cpu; /* CPU ID when bound */
int k_done; /* this KSE is done */ int k_done; /* this KSE is done */
int k_switch; /* thread switch in UTS */
}; };
/* /*
@ -546,8 +547,8 @@ enum pthread_state {
union pthread_wait_data { union pthread_wait_data {
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cond; pthread_cond_t cond;
const sigset_t *sigwait; /* Waiting on a signal in sigwait */
struct lock *lock; struct lock *lock;
siginfo_t *sigwaitinfo; /* used to save siginfo for sigwaitinfo() */
}; };
/* /*
@ -563,6 +564,7 @@ typedef void (*thread_continuation_t) (void *);
* state is restored from here. * state is restored from here.
*/ */
struct pthread_sigframe { struct pthread_sigframe {
int psf_valid;
int psf_flags; int psf_flags;
int psf_interrupted; int psf_interrupted;
int psf_signo; int psf_signo;
@ -586,7 +588,7 @@ struct pthread_specific_elem {
}; };
#define MAX_THR_LOCKLEVEL 3 #define MAX_THR_LOCKLEVEL 5
/* /*
* Thread structure. * Thread structure.
*/ */
@ -640,7 +642,7 @@ struct pthread {
* Used for tracking delivery of signal handlers. * Used for tracking delivery of signal handlers.
*/ */
struct pthread_sigframe *curframe; struct pthread_sigframe *curframe;
siginfo_t siginfo[NSIG]; siginfo_t siginfo[_SIG_MAXSIG];
/* /*
* Cancelability flags - the lower 2 bits are used by cancel * Cancelability flags - the lower 2 bits are used by cancel
@ -657,11 +659,10 @@ struct pthread {
* The thread's base and pending signal masks. The active * The thread's base and pending signal masks. The active
* signal mask is stored in the thread's context (in mailbox). * signal mask is stored in the thread's context (in mailbox).
*/ */
sigset_t oldsigmask;
sigset_t sigmask; sigset_t sigmask;
sigset_t sigpend; sigset_t sigpend;
int sigmask_seqno;
int check_pending; int check_pending;
int have_signals;
int refcount; int refcount;
/* Thread state: */ /* Thread state: */
@ -997,14 +998,14 @@ SCLASS struct pthread_cond_attr _pthread_condattr_default
SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC); SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC);
/* Array of signal actions for this process: */ /* Array of signal actions for this process: */
SCLASS struct sigaction _thread_sigact[NSIG]; SCLASS struct sigaction _thread_sigact[_SIG_MAXSIG];
/* /*
* Array of counts of dummy handlers for SIG_DFL signals. This is used to * Array of counts of dummy handlers for SIG_DFL signals. This is used to
* assure that there is always a dummy signal handler installed while there * assure that there is always a dummy signal handler installed while there
* is a thread sigwait()ing on the corresponding signal. * is a thread sigwait()ing on the corresponding signal.
*/ */
SCLASS int _thread_dfl_count[NSIG]; SCLASS int _thread_dfl_count[_SIG_MAXSIG];
/* /*
* Lock for above count of dummy handlers and for the process signal * Lock for above count of dummy handlers and for the process signal
@ -1014,8 +1015,7 @@ SCLASS struct lock _thread_signal_lock;
/* Pending signals and mask for this process: */ /* Pending signals and mask for this process: */
SCLASS sigset_t _thr_proc_sigpending; SCLASS sigset_t _thr_proc_sigpending;
SCLASS sigset_t _thr_proc_sigmask SCLASS_PRESET({{0, 0, 0, 0}}); SCLASS siginfo_t _thr_proc_siginfo[_SIG_MAXSIG];
SCLASS siginfo_t _thr_proc_siginfo[NSIG];
SCLASS pid_t _thr_pid SCLASS_PRESET(0); SCLASS pid_t _thr_pid SCLASS_PRESET(0);
@ -1030,7 +1030,7 @@ SCLASS struct lock _keytable_lock;
SCLASS struct lock _thread_list_lock; SCLASS struct lock _thread_list_lock;
SCLASS int _thr_guard_default; SCLASS int _thr_guard_default;
SCLASS int _thr_page_size; SCLASS int _thr_page_size;
SCLASS pthread_t _thr_sig_daemon;
SCLASS int _thr_debug_flags SCLASS_PRESET(0); SCLASS int _thr_debug_flags SCLASS_PRESET(0);
/* Undefine the storage class and preset specifiers: */ /* Undefine the storage class and preset specifiers: */
@ -1116,7 +1116,6 @@ void _thr_panic_exit(char *, int, char *);
void _thread_cleanupspecific(void); void _thread_cleanupspecific(void);
void _thread_dump_info(void); void _thread_dump_info(void);
void _thread_printf(int, const char *, ...); void _thread_printf(int, const char *, ...);
void _thr_sched_frame(struct pthread_sigframe *);
void _thr_sched_switch(struct pthread *); void _thr_sched_switch(struct pthread *);
void _thr_sched_switch_unlocked(struct pthread *); void _thr_sched_switch_unlocked(struct pthread *);
void _thr_set_timeout(const struct timespec *); void _thr_set_timeout(const struct timespec *);
@ -1126,13 +1125,17 @@ void _thr_sig_check_pending(struct pthread *);
void _thr_sig_rundown(struct pthread *, ucontext_t *, void _thr_sig_rundown(struct pthread *, ucontext_t *,
struct pthread_sigframe *); struct pthread_sigframe *);
void _thr_sig_send(struct pthread *pthread, int sig); void _thr_sig_send(struct pthread *pthread, int sig);
void _thr_sig_wrapper(void);
void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf); void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf);
void _thr_spinlock_init(void); void _thr_spinlock_init(void);
void _thr_enter_cancellation_point(struct pthread *); void _thr_enter_cancellation_point(struct pthread *);
void _thr_leave_cancellation_point(struct pthread *); void _thr_leave_cancellation_point(struct pthread *);
int _thr_setconcurrency(int new_level); int _thr_setconcurrency(int new_level);
int _thr_setmaxconcurrency(void); int _thr_setmaxconcurrency(void);
int _thr_start_sig_daemon(void);
int _thr_getprocsig(int sig, siginfo_t *siginfo);
int _thr_getprocsig_unlocked(int sig, siginfo_t *siginfo);
void _thr_signal_init(void);
void _thr_signal_deinit(void);
/* /*
* Aliases for _pthread functions. Should be called instead of * Aliases for _pthread functions. Should be called instead of
@ -1216,6 +1219,8 @@ int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
ssize_t __sys_read(int, void *, size_t); ssize_t __sys_read(int, void *, size_t);
ssize_t __sys_write(int, const void *, size_t); ssize_t __sys_write(int, const void *, size_t);
void __sys_exit(int); void __sys_exit(int);
int __sys_sigwait(const sigset_t *, int *);
int __sys_sigtimedwait(sigset_t *, siginfo_t *, struct timespec *);
#endif #endif
/* #include <poll.h> */ /* #include <poll.h> */

File diff suppressed because it is too large Load Diff

View File

@ -43,16 +43,21 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
{ {
int ret = 0; int ret = 0;
struct sigaction gact; struct sigaction gact;
struct pthread *curthread;
kse_critical_t crit;
/* Check if the signal number is out of range: */ /* Check if the signal number is out of range: */
if (sig < 1 || sig > NSIG) { if (sig < 1 || sig > _SIG_MAXSIG) {
/* Return an invalid argument: */ /* Return an invalid argument: */
errno = EINVAL; errno = EINVAL;
ret = -1; ret = -1;
} else { } else {
if (_thr_initial == NULL) if (!_kse_isthreaded())
_libpthread_init(NULL); return __sys_sigaction(sig, act, oact);
crit = _kse_critical_enter();
curthread = _get_curthread();
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
/* /*
* Check if the existing signal action structure contents are * Check if the existing signal action structure contents are
* to be returned: * to be returned:
@ -99,6 +104,8 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
if (__sys_sigaction(sig, &gact, NULL) != 0) if (__sys_sigaction(sig, &gact, NULL) != 0)
ret = -1; ret = -1;
} }
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
_kse_critical_leave(crit);
} }
/* Return the completion status: */ /* Return the completion status: */

View File

@ -48,33 +48,35 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
int ret; int ret;
if (! _kse_isthreaded())
_kse_setthreaded(1);
THR_SCHED_LOCK(curthread, curthread);
ret = 0; ret = 0;
if (oset != NULL) if (oset != NULL)
/* Return the current mask: */ /* Return the current mask: */
*oset = curthread->tmbx.tm_context.uc_sigmask; *oset = curthread->sigmask;
/* Check if a new signal set was provided by the caller: */ /* Check if a new signal set was provided by the caller: */
if (set != NULL) { if (set != NULL) {
THR_SCHED_LOCK(curthread, curthread);
/* Process according to what to do: */ /* Process according to what to do: */
switch (how) { switch (how) {
/* Block signals: */ /* Block signals: */
case SIG_BLOCK: case SIG_BLOCK:
/* Add signals to the existing mask: */ /* Add signals to the existing mask: */
SIGSETOR(curthread->tmbx.tm_context.uc_sigmask, *set); SIGSETOR(curthread->sigmask, *set);
break; break;
/* Unblock signals: */ /* Unblock signals: */
case SIG_UNBLOCK: case SIG_UNBLOCK:
/* Clear signals from the existing mask: */ /* Clear signals from the existing mask: */
SIGSETNAND(curthread->tmbx.tm_context.uc_sigmask, *set); SIGSETNAND(curthread->sigmask, *set);
break; break;
/* Set the signal process mask: */ /* Set the signal process mask: */
case SIG_SETMASK: case SIG_SETMASK:
/* Set the new mask: */ /* Set the new mask: */
curthread->tmbx.tm_context.uc_sigmask = *set; curthread->sigmask = *set;
break; break;
/* Trap invalid actions: */ /* Trap invalid actions: */
@ -84,13 +86,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
ret = -1; ret = -1;
break; break;
} }
SIG_CANTMASK(curthread->sigmask);
if (ret == 0) {
curthread->sigmask =
curthread->tmbx.tm_context.uc_sigmask;
curthread->sigmask_seqno++;
}
THR_SCHED_UNLOCK(curthread, curthread); THR_SCHED_UNLOCK(curthread, curthread);
/* /*
@ -98,6 +94,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
*/ */
if (ret == 0) if (ret == 0)
_thr_sig_check_pending(curthread); _thr_sig_check_pending(curthread);
} } else
THR_SCHED_UNLOCK(curthread, curthread);
return (ret); return (ret);
} }

View File

@ -54,8 +54,13 @@ _sigpending(sigset_t *set)
ret = EINVAL; ret = EINVAL;
} }
else { else {
*set = curthread->sigpend; if (!_kse_isthreaded())
return __sys_sigpending(set);
crit = _kse_critical_enter(); crit = _kse_critical_enter();
KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
*set = curthread->sigpend;
KSE_SCHED_UNLOCK(curthread->kse, curthread->kseg);
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock); KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
SIGSETOR(*set, _thr_proc_sigpending); SIGSETOR(*set, _thr_proc_sigpending);
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock); KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);

View File

@ -46,8 +46,9 @@ _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
{ {
int ret; int ret;
ret = pthread_sigmask(how, set, oset); if (_kse_isthreaded() == 0)
if ((ret == 0) && (_kse_isthreaded() == 0))
ret = __sys_sigprocmask(how, set, oset); ret = __sys_sigprocmask(how, set, oset);
else
ret = pthread_sigmask(how, set, oset);
return (ret); return (ret);
} }

View File

@ -44,14 +44,19 @@ _sigsuspend(const sigset_t *set)
{ {
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
int ret = -1; int ret = -1;
sigset_t osigmask;
if (!_kse_isthreaded())
return __sys_sigsuspend(set);
/* Check if a new signal set was provided by the caller: */ /* Check if a new signal set was provided by the caller: */
if (set != NULL) { if (set != NULL) {
THR_LOCK_SWITCH(curthread); THR_LOCK_SWITCH(curthread);
/* Save current sigmask */
memcpy(&osigmask, &curthread->sigmask, sizeof(osigmask));
/* Change the caller's mask: */ /* Change the caller's mask: */
memcpy(&curthread->tmbx.tm_context.uc_sigmask, memcpy(&curthread->sigmask, set, sizeof(sigset_t));
set, sizeof(sigset_t));
THR_SET_STATE(curthread, PS_SIGSUSPEND); THR_SET_STATE(curthread, PS_SIGSUSPEND);
@ -61,9 +66,15 @@ _sigsuspend(const sigset_t *set)
/* Always return an interrupted error: */ /* Always return an interrupted error: */
errno = EINTR; errno = EINTR;
THR_SCHED_LOCK(curthread, curthread);
/* Restore the signal mask: */ /* Restore the signal mask: */
memcpy(&curthread->tmbx.tm_context.uc_sigmask, memcpy(&curthread->sigmask, &osigmask, sizeof(sigset_t));
&curthread->sigmask, sizeof(sigset_t)); THR_SCHED_UNLOCK(curthread, curthread);
/*
* signal mask is reloaded, need to check if there is
* pending proc signal I can handle.
*/
_thr_sig_check_pending(curthread);
} else { } else {
/* Return an invalid argument error: */ /* Return an invalid argument error: */
errno = EINVAL; errno = EINVAL;

View File

@ -39,10 +39,13 @@
#include <pthread.h> #include <pthread.h>
#include "thr_private.h" #include "thr_private.h"
__weak_reference(_sigwait, sigwait); __weak_reference(__sigwait, sigwait);
__weak_reference(__sigtimedwait, sigtimedwait);
__weak_reference(__sigwaitinfo, sigwaitinfo);
int static int
_sigwait(const sigset_t *set, int *sig) lib_sigtimedwait(const sigset_t *set, siginfo_t *info,
const struct timespec * timeout)
{ {
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
int ret = 0; int ret = 0;
@ -50,8 +53,14 @@ _sigwait(const sigset_t *set, int *sig)
sigset_t tempset, waitset; sigset_t tempset, waitset;
struct sigaction act; struct sigaction act;
kse_critical_t crit; kse_critical_t crit;
siginfo_t siginfo;
_thr_enter_cancellation_point(curthread); if (!_kse_isthreaded()) {
if (info == NULL)
info = &siginfo;
return __sys_sigtimedwait((sigset_t *)set, info,
(struct timespec *)timeout);
}
/* /*
* Specify the thread kernel signal handler. * Specify the thread kernel signal handler.
@ -59,7 +68,7 @@ _sigwait(const sigset_t *set, int *sig)
act.sa_handler = (void (*) ()) _thr_sig_handler; act.sa_handler = (void (*) ()) _thr_sig_handler;
act.sa_flags = SA_RESTART | SA_SIGINFO; act.sa_flags = SA_RESTART | SA_SIGINFO;
/* Ensure the signal handler cannot be interrupted by other signals: */ /* Ensure the signal handler cannot be interrupted by other signals: */
sigfillset(&act.sa_mask); SIGFILLSET(act.sa_mask);
/* /*
* Initialize the set of signals that will be waited on: * Initialize the set of signals that will be waited on:
@ -67,38 +76,11 @@ _sigwait(const sigset_t *set, int *sig)
waitset = *set; waitset = *set;
/* These signals can't be waited on. */ /* These signals can't be waited on. */
sigdelset(&waitset, SIGKILL); SIGDELSET(waitset, SIGKILL);
sigdelset(&waitset, SIGSTOP); SIGDELSET(waitset, SIGSTOP);
/*
* Check to see if a pending signal is in the wait mask.
* This has to be atomic.
*/
tempset = curthread->sigpend;
crit = _kse_critical_enter(); crit = _kse_critical_enter();
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock); KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
SIGSETOR(tempset, _thr_proc_sigpending);
SIGSETAND(tempset, waitset);
if (SIGNOTEMPTY(tempset)) {
/* Enter a loop to find a pending signal: */
for (i = 1; i < NSIG; i++) {
if (sigismember (&tempset, i))
break;
}
/* Clear the pending signal: */
if (sigismember(&curthread->sigpend, i))
sigdelset(&curthread->sigpend, i);
else
sigdelset(&_thr_proc_sigpending, i);
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
_kse_critical_leave(crit);
_thr_leave_cancellation_point(curthread);
/* Return the signal number to the caller: */
*sig = i;
return (0);
}
/* /*
* Enter a loop to find the signals that are SIG_DFL. For * Enter a loop to find the signals that are SIG_DFL. For
@ -110,66 +92,158 @@ _sigwait(const sigset_t *set, int *sig)
* mask because a subsequent sigaction could enable an * mask because a subsequent sigaction could enable an
* ignored signal. * ignored signal.
*/ */
sigemptyset(&tempset); SIGEMPTYSET(tempset);
for (i = 1; i < NSIG; i++) { for (i = 1; i <= _SIG_MAXSIG; i++) {
if (sigismember(&waitset, i) && if (SIGISMEMBER(waitset, i) &&
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) { (_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
_thread_dfl_count[i]++; _thread_dfl_count[i - 1]++;
sigaddset(&tempset, i); SIGADDSET(tempset, i);
if (_thread_dfl_count[i] == 1) { if (_thread_dfl_count[i - 1] == 1) {
if (__sys_sigaction(i, &act, NULL) != 0) if (__sys_sigaction(i, &act, NULL) != 0)
ret = -1; /* ret = -1 */;
} }
} }
} }
if (ret == 0) {
/* Done accessing _thread_dfl_count for now. */ /* Done accessing _thread_dfl_count for now. */
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock); KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
for (i = 1; i <= _SIG_MAXSIG; ++i) {
if (SIGISMEMBER(waitset, i) &&
SIGISMEMBER(curthread->sigpend, i)) {
SIGDELSET(curthread->sigpend, i);
*info = curthread->siginfo[i];
KSE_SCHED_UNLOCK(curthread->kse,
curthread->kseg);
_kse_critical_leave(crit); _kse_critical_leave(crit);
if (ret == 0) { return (i);
/* }
* Save the wait signal mask. The wait signal }
* mask is independent of the threads signal mask curthread->timeout = 0;
* and requires separate storage. _thr_set_timeout(timeout);
*/
curthread->data.sigwait = &waitset;
/* Wait for a signal: */ /* Wait for a signal: */
THR_LOCK_SWITCH(curthread); curthread->oldsigmask = curthread->sigmask;
siginfo.si_signo = 0;
curthread->data.sigwaitinfo = &siginfo;
SIGFILLSET(curthread->sigmask);
SIGSETNAND(curthread->sigmask, waitset);
THR_SET_STATE(curthread, PS_SIGWAIT); THR_SET_STATE(curthread, PS_SIGWAIT);
_thr_sched_switch_unlocked(curthread); _thr_sched_switch_unlocked(curthread);
/* Return the signal number to the caller: */ /*
*sig = curthread->signo; * Return the signal number to the caller:
* XXX Here is race, how about a signal come in before
* we reach here? so we might got an incorrect timeout
* status.
*/
if (siginfo.si_signo > 0) {
if (info)
*info = siginfo;
ret = siginfo.si_signo;
} else {
if (curthread->timeout)
errno = EAGAIN;
ret = -1;
}
/* /*
* Probably unnecessary, but since it's in a union struct * Probably unnecessary, but since it's in a union struct
* we don't know how it could be used in the future. * we don't know how it could be used in the future.
*/ */
curthread->data.sigwait = NULL; crit = _kse_critical_enter();
} curthread->data.sigwaitinfo = NULL;
/* /*
* Relock the array of SIG_DFL wait counts. * Relock the array of SIG_DFL wait counts.
*/ */
crit = _kse_critical_enter();
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock); KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
}
/* Restore the sigactions: */ /* Restore the sigactions: */
act.sa_handler = SIG_DFL; act.sa_handler = SIG_DFL;
for (i = 1; i < NSIG; i++) { for (i = 1; i <= _SIG_MAXSIG; i++) {
if (sigismember(&tempset, i)) { if (SIGISMEMBER(tempset, i)) {
_thread_dfl_count[i]--; _thread_dfl_count[i - 1]--;
if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) && if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
(_thread_dfl_count[i] == 0)) { (_thread_dfl_count[i - 1] == 0)) {
if (__sys_sigaction(i, &act, NULL) != 0) if (__sys_sigaction(i, &act, NULL) != 0)
ret = -1; /* ret = -1 */ ;
} }
} }
} }
/* Done accessing _thread_dfl_count. */ /* Done accessing _thread_dfl_count. */
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock); KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
_kse_critical_leave(crit); _kse_critical_leave(crit);
_thr_leave_cancellation_point(curthread);
/* Return the completion status: */
return (ret); return (ret);
} }
int
__sigtimedwait(const sigset_t *set, siginfo_t *info,
const struct timespec * timeout)
{
struct pthread *curthread = _get_curthread();
int ret;
_thr_enter_cancellation_point(curthread);
ret = lib_sigtimedwait(set, info, timeout);
_thr_leave_cancellation_point(curthread);
return (ret);
}
int _sigtimedwait(const sigset_t *set, siginfo_t *info,
const struct timespec * timeout)
{
return lib_sigtimedwait(set, info, timeout);
}
int
__sigwaitinfo(const sigset_t *set, siginfo_t *info)
{
struct pthread *curthread = _get_curthread();
int ret;
_thr_enter_cancellation_point(curthread);
ret = lib_sigtimedwait(set, info, NULL);
_thr_leave_cancellation_point(curthread);
return (ret);
}
int
_sigwaitinfo(const sigset_t *set, siginfo_t *info)
{
return lib_sigtimedwait(set, info, NULL);
}
int
__sigwait(const sigset_t *set, int *sig)
{
struct pthread *curthread = _get_curthread();
int ret;
_thr_enter_cancellation_point(curthread);
ret = lib_sigtimedwait(set, NULL, NULL);
if (ret > 0) {
*sig = ret;
ret = 0;
}
else
ret = -1;
_thr_leave_cancellation_point(curthread);
return (ret);
}
int
_sigwait(const sigset_t *set, int *sig)
{
int ret;
ret = lib_sigtimedwait(set, NULL, NULL);
if (ret > 0) {
*sig = ret;
ret = 0;
} else {
ret = -1;
}
return (ret);
}

View File

@ -138,6 +138,8 @@ global:
_sigprocmask; _sigprocmask;
_sigsuspend; _sigsuspend;
_sigwait; _sigwait;
_sigtimedwait;
_sigwaitinfo;
_sleep; _sleep;
_spinlock; _spinlock;
_spinlock_debug; _spinlock_debug;
@ -271,6 +273,8 @@ global:
sigprocmask; sigprocmask;
sigsuspend; sigsuspend;
sigwait; sigwait;
sigwaitinfo;
sigtimedwait;
sleep; sleep;
system; system;
tcdrain; tcdrain;

View File

@ -54,5 +54,8 @@ __strong_reference(memcpy, _thr_memcpy);
__strong_reference(strcpy, _thr_strcpy); __strong_reference(strcpy, _thr_strcpy);
__strong_reference(strlen, _thr_strlen); __strong_reference(strlen, _thr_strlen);
__strong_reference(bzero, _thr_bzero); __strong_reference(bzero, _thr_bzero);
__strong_reference(bcopy, _thr_bcopy);
__strong_reference(__sys_write, _thr__sys_write); __strong_reference(__sys_write, _thr__sys_write);
__strong_reference(__sys_sigtimedwait, _thr__sys_sigtimedwait);

View File

@ -77,7 +77,7 @@ _thread_dump_info(void)
int fd, i; int fd, i;
for (i = 0; i < 100000; i++) { for (i = 0; i < 100000; i++) {
snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i", snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i",
getpid(), i); getpid(), i);
/* Open the dump file for append and create it if necessary: */ /* Open the dump file for append and create it if necessary: */
if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL, if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
@ -166,11 +166,26 @@ dump_thread(int fd, pthread_t pthread, int long_version)
strcpy(s, "This is the initial thread\n"); strcpy(s, "This is the initial thread\n");
__sys_write(fd, s, strlen(s)); __sys_write(fd, s, strlen(s));
} }
/* Check if this is the signal daemon thread: */
if (pthread == _thr_sig_daemon) {
/* Output a record for the signal thread: */
strcpy(s, "This is the signal daemon thread\n");
__sys_write(fd, s, strlen(s));
}
/* Process according to thread state: */ /* Process according to thread state: */
switch (pthread->state) { switch (pthread->state) {
case PS_SIGWAIT: case PS_SIGWAIT:
snprintf(s, sizeof(s), "sigmask (hi)"); snprintf(s, sizeof(s), "sigmask (hi)");
__sys_write(fd, s, strlen(s)); __sys_write(fd, s, strlen(s));
for (i = _SIG_WORDS - 1; i >= 0; i--) {
snprintf(s, sizeof(s), "%08x\n",
pthread->oldsigmask.__bits[i]);
__sys_write(fd, s, strlen(s));
}
snprintf(s, sizeof(s), "(lo)\n");
__sys_write(fd, s, strlen(s));
snprintf(s, sizeof(s), "waitset (hi)");
__sys_write(fd, s, strlen(s));
for (i = _SIG_WORDS - 1; i >= 0; i--) { for (i = _SIG_WORDS - 1; i >= 0; i--) {
snprintf(s, sizeof(s), "%08x\n", snprintf(s, sizeof(s), "%08x\n",
pthread->sigmask.__bits[i]); pthread->sigmask.__bits[i]);

View File

@ -39,6 +39,7 @@
#include "namespace.h" #include "namespace.h"
#include <sys/param.h> #include <sys/param.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/signalvar.h>
#include <machine/reg.h> #include <machine/reg.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -365,14 +366,13 @@ init_main_thread(struct pthread *thread)
thread->name = strdup("initial thread"); thread->name = strdup("initial thread");
/* Initialize the thread for signals: */ /* Initialize the thread for signals: */
sigemptyset(&thread->sigmask); SIGEMPTYSET(thread->sigmask);
/* /*
* Set up the thread mailbox. The threads saved context * Set up the thread mailbox. The threads saved context
* is also in the mailbox. * is also in the mailbox.
*/ */
thread->tmbx.tm_udata = thread; thread->tmbx.tm_udata = thread;
thread->tmbx.tm_context.uc_sigmask = thread->sigmask;
thread->tmbx.tm_context.uc_stack.ss_size = thread->attr.stacksize_attr; thread->tmbx.tm_context.uc_stack.ss_size = thread->attr.stacksize_attr;
thread->tmbx.tm_context.uc_stack.ss_sp = thread->attr.stackaddr_attr; thread->tmbx.tm_context.uc_stack.ss_sp = thread->attr.stackaddr_attr;
@ -407,10 +407,8 @@ static void
init_private(void) init_private(void)
{ {
struct clockinfo clockinfo; struct clockinfo clockinfo;
struct sigaction act;
size_t len; size_t len;
int mib[2]; int mib[2];
int i;
/* /*
* Avoid reinitializing some things if they don't need to be, * Avoid reinitializing some things if they don't need to be,
@ -448,36 +446,6 @@ init_private(void)
_thr_page_size = getpagesize(); _thr_page_size = getpagesize();
_thr_guard_default = _thr_page_size; _thr_guard_default = _thr_page_size;
/* Enter a loop to get the existing signal status: */
for (i = 1; i < NSIG; i++) {
/* Check for signals which cannot be trapped: */
if (i == SIGKILL || i == SIGSTOP) {
}
/* Get the signal handler details: */
else if (__sys_sigaction(i, NULL,
&_thread_sigact[i - 1]) != 0) {
/*
* Abort this process if signal
* initialisation fails:
*/
PANIC("Cannot read signal handler info");
}
}
/*
* Install the signal handler for SIGINFO. It isn't
* really needed, but it is nice to have for debugging
* purposes.
*/
if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
/*
* Abort this process if signal initialisation fails:
*/
PANIC("Cannot initialize signal handler");
}
_thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
init_once = 1; /* Don't do this again. */ init_once = 1; /* Don't do this again. */
} else { } else {
/* /*
@ -495,8 +463,6 @@ init_private(void)
TAILQ_INIT(&_thread_list); TAILQ_INIT(&_thread_list);
TAILQ_INIT(&_thread_gc_list); TAILQ_INIT(&_thread_gc_list);
/* Enter a loop to get the existing signal status: */
/* Initialize the SIG_DFL dummy handler count. */ /* Initialize the SIG_DFL dummy handler count. */
bzero(_thread_dfl_count, sizeof(_thread_dfl_count)); bzero(_thread_dfl_count, sizeof(_thread_dfl_count));
@ -520,8 +486,7 @@ init_private(void)
_thr_spinlock_init(); _thr_spinlock_init();
/* Clear pending signals and get the process signal mask. */ /* Clear pending signals and get the process signal mask. */
sigemptyset(&_thr_proc_sigpending); SIGEMPTYSET(_thr_proc_sigpending);
__sys_sigprocmask(SIG_SETMASK, NULL, &_thr_proc_sigmask);
/* /*
* _thread_list_lock and _kse_count are initialized * _thread_list_lock and _kse_count are initialized

View File

@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/signalvar.h> #include <sys/signalvar.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <machine/atomic.h> #include <machine/atomic.h>
#include <machine/sigframe.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
@ -125,7 +126,6 @@ static void dump_queues(struct kse *curkse);
#endif #endif
static void kse_check_completed(struct kse *kse); static void kse_check_completed(struct kse *kse);
static void kse_check_waitq(struct kse *kse); static void kse_check_waitq(struct kse *kse);
static void kse_check_signals(struct kse *kse);
static void kse_fini(struct kse *curkse); static void kse_fini(struct kse *curkse);
static void kse_reinit(struct kse *kse); static void kse_reinit(struct kse *kse);
static void kse_sched_multi(struct kse *curkse); static void kse_sched_multi(struct kse *curkse);
@ -143,27 +143,39 @@ static void kse_wakeup_multi(struct kse *curkse);
static void kse_wakeup_one(struct pthread *thread); static void kse_wakeup_one(struct pthread *thread);
static void thr_cleanup(struct kse *kse, struct pthread *curthread); static void thr_cleanup(struct kse *kse, struct pthread *curthread);
static void thr_link(struct pthread *thread); static void thr_link(struct pthread *thread);
static void thr_resume_wrapper(int unused_1, siginfo_t *unused_2, static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
ucontext_t *ucp);
static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp, static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf); struct pthread_sigframe *psf);
static int thr_timedout(struct pthread *thread, struct timespec *curtime); static int thr_timedout(struct pthread *thread, struct timespec *curtime);
static void thr_unlink(struct pthread *thread); static void thr_unlink(struct pthread *thread);
/* /*
* This is called after a fork(). * This is called after a fork().
* No locks need to be taken here since we are guaranteed to be * No locks need to be taken here since we are guaranteed to be
* single threaded. * single threaded.
*
* XXX
* POSIX says for threaded process, fork() function is used
* only to run new programs, and the effects of calling functions
* that require certain resources between the call to fork() and
* the call to an exec function are undefined.
*
* Here it is not safe to reinitialize the library after fork().
* Because memory management may be corrupted, further calling
* malloc()/free() may cause undefined behavior.
*/ */
void void
_kse_single_thread(struct pthread *curthread) _kse_single_thread(struct pthread *curthread)
{ {
#ifdef NOTYET
struct kse *kse; struct kse *kse;
struct kse_group *kseg; struct kse_group *kseg;
struct pthread *thread; struct pthread *thread;
kse_critical_t crit; kse_critical_t crit;
int i; int i;
/* /*
* Disable upcalls and clear the threaded flag. * Disable upcalls and clear the threaded flag.
* XXX - I don't think we need to disable upcalls after a fork(). * XXX - I don't think we need to disable upcalls after a fork().
@ -172,6 +184,7 @@ _kse_single_thread(struct pthread *curthread)
crit = _kse_critical_enter(); crit = _kse_critical_enter();
__isthreaded = 0; __isthreaded = 0;
active_threads = 1; active_threads = 1;
_thr_signal_deinit();
/* /*
* Enter a loop to remove and free all threads other than * Enter a loop to remove and free all threads other than
@ -201,7 +214,7 @@ _kse_single_thread(struct pthread *curthread)
TAILQ_INIT(&curthread->mutexq); /* initialize mutex queue */ TAILQ_INIT(&curthread->mutexq); /* initialize mutex queue */
curthread->joiner = NULL; /* no joining threads yet */ curthread->joiner = NULL; /* no joining threads yet */
curthread->refcount = 0; curthread->refcount = 0;
sigemptyset(&curthread->sigpend); /* clear pending signals */ SIGEMPTYSET(curthread->sigpend); /* clear pending signals */
if (curthread->specific != NULL) { if (curthread->specific != NULL) {
free(curthread->specific); free(curthread->specific);
curthread->specific = NULL; curthread->specific = NULL;
@ -307,6 +320,12 @@ _kse_single_thread(struct pthread *curthread)
curthread->kseg = NULL; curthread->kseg = NULL;
_kse_initial = NULL; _kse_initial = NULL;
_libpthread_init(curthread); _libpthread_init(curthread);
#else
_ksd_readandclear_tmbx();
__isthreaded = 0;
active_threads = 0;
_thr_signal_deinit();
#endif
} }
/* /*
@ -363,15 +382,17 @@ _kse_setthreaded(int threaded)
* Tell the kernel to create a KSE for the initial thread * Tell the kernel to create a KSE for the initial thread
* and enable upcalls in it. * and enable upcalls in it.
*/ */
_thr_signal_init();
_kse_initial->k_flags |= KF_STARTED; _kse_initial->k_flags |= KF_STARTED;
if (kse_create(&_kse_initial->k_mbx, 0) != 0) { if (kse_create(&_kse_initial->k_mbx, 0) != 0) {
_kse_initial->k_flags &= ~KF_STARTED; _kse_initial->k_flags &= ~KF_STARTED;
__isthreaded = 0; __isthreaded = 0;
/* may abort() */ /* may abort() */
DBG_MSG("kse_create failed\n"); PANIC("kse_create() failed\n");
return (-1); return (-1);
} }
KSE_SET_MBOX(_kse_initial, _thr_initial); KSE_SET_MBOX(_kse_initial, _thr_initial);
_thr_start_sig_daemon();
_thr_setmaxconcurrency(); _thr_setmaxconcurrency();
} }
return (0); return (0);
@ -536,6 +557,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
int ret; int ret;
volatile int uts_once; volatile int uts_once;
volatile int resume_once = 0; volatile int resume_once = 0;
ucontext_t uc;
/* We're in the scheduler, 5 by 5: */ /* We're in the scheduler, 5 by 5: */
curkse = _get_curkse(); curkse = _get_curkse();
@ -552,7 +574,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
* a thread can be interrupted by other signals while * a thread can be interrupted by other signals while
* it is running down pending signals. * it is running down pending signals.
*/ */
sigemptyset(&psf.psf_sigset); psf.psf_valid = 0;
curthread->curframe = &psf; curthread->curframe = &psf;
/* /*
@ -561,6 +583,8 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
* o The current thread is dead; it's stack needs to be * o The current thread is dead; it's stack needs to be
* cleaned up and it can't be done while operating on * cleaned up and it can't be done while operating on
* it. * it.
* o The current thread has signals pending, should
* let scheduler install signal trampoline for us.
* o There are no runnable threads. * o There are no runnable threads.
* o The next thread to run won't unlock the scheduler * o The next thread to run won't unlock the scheduler
* lock. A side note: the current thread may be run * lock. A side note: the current thread may be run
@ -570,8 +594,10 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
if ((curthread->state == PS_DEAD) || if ((curthread->state == PS_DEAD) ||
(((td = KSE_RUNQ_FIRST(curkse)) == NULL) && (((td = KSE_RUNQ_FIRST(curkse)) == NULL) &&
(curthread->state != PS_RUNNING)) || (curthread->state != PS_RUNNING)) ||
((td != NULL) && (td->lock_switch == 0))) ((td != NULL) && (td->lock_switch == 0))) {
curkse->k_switch = 1;
_thread_enter_uts(&curthread->tmbx, &curkse->k_mbx); _thread_enter_uts(&curthread->tmbx, &curkse->k_mbx);
}
else { else {
uts_once = 0; uts_once = 0;
THR_GETCONTEXT(&curthread->tmbx.tm_context); THR_GETCONTEXT(&curthread->tmbx.tm_context);
@ -623,6 +649,15 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
} }
} }
if (psf.psf_valid) {
/*
* It is ugly we must increase critical count, because we
* have a frame saved, we must backout state in psf
* before we can process signals.
*/
curthread->critical_count++;
}
if (curthread->lock_switch != 0) { if (curthread->lock_switch != 0) {
/* /*
* Unlock the scheduling queue and leave the * Unlock the scheduling queue and leave the
@ -638,11 +673,15 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
/* /*
* This thread is being resumed; check for cancellations. * This thread is being resumed; check for cancellations.
*/ */
if ((resume_once == 0) && (!THR_IN_CRITICAL(curthread))) { if ((psf.psf_valid || curthread->check_pending)) {
resume_once = 0;
THR_GETCONTEXT(&uc);
if (resume_once == 0) {
resume_once = 1; resume_once = 1;
thr_resume_check(curthread, &curthread->tmbx.tm_context, &psf); curthread->check_pending = 0;
thr_resume_check(curthread, &uc, &psf);
}
} }
THR_ACTIVATE_LAST_LOCK(curthread); THR_ACTIVATE_LAST_LOCK(curthread);
} }
@ -747,9 +786,6 @@ kse_sched_single(struct kse *curkse)
KSE_WAITQ_REMOVE(curkse, td_wait); KSE_WAITQ_REMOVE(curkse, td_wait);
} }
} }
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
kse_check_signals(curkse);
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
} }
/* Remove the frame reference. */ /* Remove the frame reference. */
@ -810,12 +846,12 @@ kse_sched_multi(struct kse *curkse)
KSE_CLEAR_WAIT(curkse); KSE_CLEAR_WAIT(curkse);
} }
/* Lock the scheduling lock. */ /*If this is an upcall; take the scheduler lock. */
curthread = curkse->k_curthread; if (curkse->k_switch == 0)
if ((curthread == NULL) || (curthread->need_switchout == 0)) {
/* This is an upcall; take the scheduler lock. */
KSE_SCHED_LOCK(curkse, curkse->k_kseg); KSE_SCHED_LOCK(curkse, curkse->k_kseg);
} curkse->k_switch = 0;
curthread = curkse->k_curthread;
if (KSE_IS_IDLE(curkse)) { if (KSE_IS_IDLE(curkse)) {
KSE_CLEAR_IDLE(curkse); KSE_CLEAR_IDLE(curkse);
@ -879,11 +915,6 @@ kse_sched_multi(struct kse *curkse)
kse_wakeup_multi(curkse); kse_wakeup_multi(curkse);
/* This has to be done without the scheduling lock held. */
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
kse_check_signals(curkse);
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
#ifdef DEBUG_THREAD_KERN #ifdef DEBUG_THREAD_KERN
dump_queues(curkse); dump_queues(curkse);
#endif #endif
@ -899,9 +930,6 @@ kse_sched_multi(struct kse *curkse)
kse_wait(curkse, td_wait); kse_wait(curkse, td_wait);
kse_check_completed(curkse); kse_check_completed(curkse);
kse_check_waitq(curkse); kse_check_waitq(curkse);
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
kse_check_signals(curkse);
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
} }
/* Check for no more threads: */ /* Check for no more threads: */
@ -966,15 +994,19 @@ kse_sched_multi(struct kse *curkse)
* signal frame to the thread's context. * signal frame to the thread's context.
*/ */
#ifdef NOT_YET #ifdef NOT_YET
if ((curframe == NULL) && ((curthread->have_signals != 0) || if ((((curframe == NULL) && (curthread->check_pending != 0)) ||
(((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) && (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)))) ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))) &&
!THR_IN_CRITICAL(curthread))
signalcontext(&curthread->tmbx.tm_context, 0, signalcontext(&curthread->tmbx.tm_context, 0,
(__sighandler_t *)thr_resume_wrapper); (__sighandler_t *)thr_resume_wrapper);
#else #else
if ((curframe == NULL) && (curthread->have_signals != 0)) if ((curframe == NULL) && (curthread->check_pending != 0) &&
!THR_IN_CRITICAL(curthread)) {
curthread->check_pending = 0;
signalcontext(&curthread->tmbx.tm_context, 0, signalcontext(&curthread->tmbx.tm_context, 0,
(__sighandler_t *)thr_resume_wrapper); (__sighandler_t *)thr_resume_wrapper);
}
#endif #endif
/* /*
* Continue the thread at its current frame: * Continue the thread at its current frame:
@ -999,61 +1031,31 @@ kse_sched_multi(struct kse *curkse)
} }
static void static void
kse_check_signals(struct kse *curkse) thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
{
sigset_t sigset;
int i;
/* Deliver posted signals. */
for (i = 0; i < _SIG_WORDS; i++) {
atomic_swap_int(&curkse->k_mbx.km_sigscaught.__bits[i],
0, &sigset.__bits[i]);
}
if (SIGNOTEMPTY(sigset)) {
/*
* Dispatch each signal.
*
* XXX - There is no siginfo for any of these.
* I think there should be, especially for
* signals from other processes (si_pid, si_uid).
*/
for (i = 1; i < NSIG; i++) {
if (sigismember(&sigset, i) != 0) {
DBG_MSG("Dispatching signal %d\n", i);
_thr_sig_dispatch(curkse, i,
NULL /* no siginfo */);
}
}
sigemptyset(&sigset);
__sys_sigprocmask(SIG_SETMASK, &sigset, NULL);
}
}
static void
thr_resume_wrapper(int unused_1, siginfo_t *unused_2, ucontext_t *ucp)
{ {
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
struct kse *curkse;
int ret;
DBG_MSG(">>> sig wrapper\n");
if (curthread->lock_switch)
PANIC("thr_resume_wrapper, lock_switch != 0\n");
thr_resume_check(curthread, ucp, NULL); thr_resume_check(curthread, ucp, NULL);
_kse_critical_enter();
curkse = _get_curkse();
curthread->tmbx.tm_context = *ucp;
ret = _thread_switch(&curthread->tmbx, &curkse->k_mbx.km_curthread);
if (ret != 0)
PANIC("thr_resume_wrapper: thread has returned "
"from _thread_switch");
/* THR_SETCONTEXT(ucp); */ /* not work, why ? */
} }
static void static void
thr_resume_check(struct pthread *curthread, ucontext_t *ucp, thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
struct pthread_sigframe *psf) struct pthread_sigframe *psf)
{ {
/* Check signals before cancellations. */
while (curthread->have_signals != 0) {
/* Clear the pending flag. */
curthread->have_signals = 0;
/*
* It's perfectly valid, though not portable, for
* signal handlers to munge their interrupted context
* and expect to return to it. Ensure we use the
* correct context when running down signals.
*/
_thr_sig_rundown(curthread, ucp, psf); _thr_sig_rundown(curthread, ucp, psf);
}
#ifdef NOT_YET #ifdef NOT_YET
if (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) && if (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
@ -1124,7 +1126,7 @@ thr_cleanup(struct kse *curkse, struct pthread *thread)
THR_GCLIST_ADD(thread); THR_GCLIST_ADD(thread);
/* Use thread_list_lock */ /* Use thread_list_lock */
active_threads--; active_threads--;
if (active_threads == 0) { if (active_threads == 1) {
KSE_LOCK_RELEASE(curkse, &_thread_list_lock); KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
exit(0); exit(0);
} }
@ -1203,8 +1205,15 @@ _thr_gc(struct pthread *curthread)
KSE_LOCK_RELEASE(curthread->kse, &kse_lock); KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
_kse_critical_leave(crit); _kse_critical_leave(crit);
} }
/*
* XXX we don't free initial thread, because there might
* have some code referencing initial thread.
*/
if (td != _thr_initial) {
DBG_MSG("Freeing thread %p\n", td); DBG_MSG("Freeing thread %p\n", td);
_thr_free(curthread, td); _thr_free(curthread, td);
} else
DBG_MSG("Initial thread won't be freed\n");
} }
/* XXX free kse and ksegrp list should be looked as well */ /* XXX free kse and ksegrp list should be looked as well */
} }
@ -1216,7 +1225,6 @@ _thr_gc(struct pthread *curthread)
int int
_thr_schedule_add(struct pthread *curthread, struct pthread *newthread) _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
{ {
struct kse *curkse;
kse_critical_t crit; kse_critical_t crit;
int ret; int ret;
@ -1250,15 +1258,11 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
/* /*
* This thread needs a new KSE and KSEG. * This thread needs a new KSE and KSEG.
*/ */
crit = _kse_critical_enter(); newthread->kse->k_flags &= ~KF_INITIALIZED;
curkse = _get_curkse(); newthread->kse->k_flags |= KF_STARTED;
_ksd_setprivate(&newthread->kse->k_ksd);
newthread->kse->k_flags |= KF_INITIALIZED|KF_STARTED;
ret = kse_create(&newthread->kse->k_mbx, 1); ret = kse_create(&newthread->kse->k_mbx, 1);
if (ret != 0) if (ret != 0)
ret = errno; ret = errno;
_ksd_setprivate(&curkse->k_ksd);
_kse_critical_leave(crit);
} }
else { else {
/* /*
@ -1266,6 +1270,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
* assigned threads. If the new thread is runnable, also * assigned threads. If the new thread is runnable, also
* add it to the KSE's run queue. * add it to the KSE's run queue.
*/ */
crit = _kse_critical_enter();
KSE_SCHED_LOCK(curthread->kse, newthread->kseg); KSE_SCHED_LOCK(curthread->kse, newthread->kseg);
KSEG_THRQ_ADD(newthread->kseg, newthread); KSEG_THRQ_ADD(newthread->kseg, newthread);
if (newthread->state == PS_RUNNING) if (newthread->state == PS_RUNNING)
@ -1288,6 +1293,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
kse_wakeup_one(newthread); kse_wakeup_one(newthread);
} }
KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg); KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg);
_kse_critical_leave(crit);
ret = 0; ret = 0;
} }
if (ret != 0) if (ret != 0)
@ -1328,6 +1334,7 @@ kse_check_completed(struct kse *kse)
{ {
struct pthread *thread; struct pthread *thread;
struct kse_thr_mailbox *completed; struct kse_thr_mailbox *completed;
int sig;
if ((completed = kse->k_mbx.km_completed) != NULL) { if ((completed = kse->k_mbx.km_completed) != NULL) {
kse->k_mbx.km_completed = NULL; kse->k_mbx.km_completed = NULL;
@ -1348,6 +1355,13 @@ kse_check_completed(struct kse *kse)
thread->active = 0; thread->active = 0;
} }
} }
if ((sig = thread->tmbx.tm_syncsig.si_signo) != 0) {
if (SIGISMEMBER(thread->sigmask, sig))
SIGADDSET(thread->sigpend, sig);
else
_thr_sig_add(thread, sig, &thread->tmbx.tm_syncsig);
thread->tmbx.tm_syncsig.si_signo = 0;
}
completed = completed->tm_next; completed = completed->tm_next;
} }
} }
@ -1446,6 +1460,8 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
{ {
int level; int level;
int i; int i;
int restart;
siginfo_t siginfo;
/* /*
* Place the currently running thread into the * Place the currently running thread into the
@ -1459,15 +1475,25 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
thread->need_switchout = 0; thread->need_switchout = 0;
/* This thread must have blocked in the kernel. */ /* This thread must have blocked in the kernel. */
/* thread->slice_usec = -1;*/ /* restart timeslice */ /* thread->slice_usec = -1;*/ /* restart timeslice */
/*
* XXX - Check for pending signals for this thread to
* see if we need to interrupt it in the kernel.
*/
/* if (thread->check_pending != 0) */
if ((thread->slice_usec != -1) && if ((thread->slice_usec != -1) &&
(thread->attr.sched_policy != SCHED_FIFO)) (thread->attr.sched_policy != SCHED_FIFO))
thread->slice_usec += (thread->tmbx.tm_uticks thread->slice_usec += (thread->tmbx.tm_uticks
+ thread->tmbx.tm_sticks) * _clock_res_usec; + thread->tmbx.tm_sticks) * _clock_res_usec;
/*
* Check for pending signals for this thread to
* see if we need to interrupt it in the kernel.
*/
if (thread->check_pending != 0) {
for (i = 1; i <= _SIG_MAXSIG; ++i) {
if (SIGISMEMBER(thread->sigpend, i) &&
!SIGISMEMBER(thread->sigmask, i)) {
restart = _thread_sigact[1 - 1].sa_flags & SA_RESTART;
kse_thr_interrupt(&thread->tmbx,
restart ? -2 : -1);
break;
}
}
}
} }
else { else {
switch (thread->state) { switch (thread->state) {
@ -1507,10 +1533,12 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
THR_SET_STATE(thread, PS_RUNNING); THR_SET_STATE(thread, PS_RUNNING);
break; break;
case PS_SIGWAIT:
KSE_WAITQ_INSERT(kse, thread);
break;
case PS_JOIN: case PS_JOIN:
case PS_MUTEX_WAIT: case PS_MUTEX_WAIT:
case PS_SIGSUSPEND: case PS_SIGSUSPEND:
case PS_SIGWAIT:
case PS_SUSPENDED: case PS_SUSPENDED:
case PS_DEADLOCK: case PS_DEADLOCK:
default: default:
@ -1564,12 +1592,19 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
if (thread->check_pending != 0) { if (thread->check_pending != 0) {
/* Install pending signals into the frame. */ /* Install pending signals into the frame. */
thread->check_pending = 0; thread->check_pending = 0;
for (i = 0; i < _SIG_MAXSIG; i++) { KSE_LOCK_ACQUIRE(kse, &_thread_signal_lock);
if (sigismember(&thread->sigpend, i) && for (i = 1; i <= _SIG_MAXSIG; i++) {
!sigismember(&thread->tmbx.tm_context.uc_sigmask, i)) if (SIGISMEMBER(thread->sigmask, i))
continue;
if (SIGISMEMBER(thread->sigpend, i))
_thr_sig_add(thread, i, &thread->siginfo[i]); _thr_sig_add(thread, i, &thread->siginfo[i]);
else if (SIGISMEMBER(_thr_proc_sigpending, i) &&
_thr_getprocsig_unlocked(i, &siginfo)) {
_thr_sig_add(thread, i, &siginfo);
} }
} }
KSE_LOCK_RELEASE(kse, &_thread_signal_lock);
}
} }
/* /*
@ -2016,6 +2051,10 @@ _kse_alloc(struct pthread *curthread)
_lockuser_destroy(&kse->k_lockusers[i]); _lockuser_destroy(&kse->k_lockusers[i]);
} }
free(kse); free(kse);
if (curthread != NULL) {
KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
_kse_critical_leave(crit);
}
return (NULL); return (NULL);
} }
kse->k_flags = 0; kse->k_flags = 0;
@ -2044,7 +2083,7 @@ kse_reinit(struct kse *kse)
kse->k_kseg = 0; kse->k_kseg = 0;
kse->k_schedq = 0; kse->k_schedq = 0;
kse->k_locklevel = 0; kse->k_locklevel = 0;
sigemptyset(&kse->k_sigmask); SIGEMPTYSET(kse->k_sigmask);
bzero(&kse->k_sigq, sizeof(kse->k_sigq)); bzero(&kse->k_sigq, sizeof(kse->k_sigq));
kse->k_check_sigq = 0; kse->k_check_sigq = 0;
kse->k_flags = 0; kse->k_flags = 0;
@ -2053,6 +2092,7 @@ kse_reinit(struct kse *kse)
kse->k_error = 0; kse->k_error = 0;
kse->k_cpu = 0; kse->k_cpu = 0;
kse->k_done = 0; kse->k_done = 0;
kse->k_switch = 0;
} }
void void
@ -2171,10 +2211,12 @@ thr_link(struct pthread *thread)
{ {
kse_critical_t crit; kse_critical_t crit;
struct kse *curkse; struct kse *curkse;
struct pthread *curthread;
crit = _kse_critical_enter(); crit = _kse_critical_enter();
curkse = _get_curkse(); curkse = _get_curkse();
curthread = _get_curthread();
thread->sigmask = curthread->sigmask;
KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
/* /*
* Initialize the unique id (which GDB uses to track * Initialize the unique id (which GDB uses to track

View File

@ -45,7 +45,7 @@ _pthread_kill(pthread_t pthread, int sig)
int ret; int ret;
/* Check for invalid signal numbers: */ /* Check for invalid signal numbers: */
if (sig < 0 || sig >= NSIG) if (sig < 0 || sig > _SIG_MAXSIG)
/* Invalid signal: */ /* Invalid signal: */
ret = EINVAL; ret = EINVAL;
/* /*

View File

@ -171,7 +171,7 @@ typedef struct kse_thr_mailbox *kse_critical_t;
struct kse_group; struct kse_group;
#define MAX_KSE_LOCKLEVEL 3 #define MAX_KSE_LOCKLEVEL 5
struct kse { struct kse {
struct kse_mailbox k_mbx; /* kernel kse mailbox */ struct kse_mailbox k_mbx; /* kernel kse mailbox */
/* -- location and order specific items for gdb -- */ /* -- location and order specific items for gdb -- */
@ -190,7 +190,7 @@ struct kse {
struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL]; struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL];
int k_locklevel; int k_locklevel;
sigset_t k_sigmask; sigset_t k_sigmask;
struct sigstatus k_sigq[NSIG]; struct sigstatus k_sigq[_SIG_MAXSIG];
stack_t k_stack; stack_t k_stack;
int k_check_sigq; int k_check_sigq;
int k_flags; int k_flags;
@ -201,6 +201,7 @@ struct kse {
int k_error; /* syscall errno in critical */ int k_error; /* syscall errno in critical */
int k_cpu; /* CPU ID when bound */ int k_cpu; /* CPU ID when bound */
int k_done; /* this KSE is done */ int k_done; /* this KSE is done */
int k_switch; /* thread switch in UTS */
}; };
/* /*
@ -546,8 +547,8 @@ enum pthread_state {
union pthread_wait_data { union pthread_wait_data {
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cond; pthread_cond_t cond;
const sigset_t *sigwait; /* Waiting on a signal in sigwait */
struct lock *lock; struct lock *lock;
siginfo_t *sigwaitinfo; /* used to save siginfo for sigwaitinfo() */
}; };
/* /*
@ -563,6 +564,7 @@ typedef void (*thread_continuation_t) (void *);
* state is restored from here. * state is restored from here.
*/ */
struct pthread_sigframe { struct pthread_sigframe {
int psf_valid;
int psf_flags; int psf_flags;
int psf_interrupted; int psf_interrupted;
int psf_signo; int psf_signo;
@ -586,7 +588,7 @@ struct pthread_specific_elem {
}; };
#define MAX_THR_LOCKLEVEL 3 #define MAX_THR_LOCKLEVEL 5
/* /*
* Thread structure. * Thread structure.
*/ */
@ -640,7 +642,7 @@ struct pthread {
* Used for tracking delivery of signal handlers. * Used for tracking delivery of signal handlers.
*/ */
struct pthread_sigframe *curframe; struct pthread_sigframe *curframe;
siginfo_t siginfo[NSIG]; siginfo_t siginfo[_SIG_MAXSIG];
/* /*
* Cancelability flags - the lower 2 bits are used by cancel * Cancelability flags - the lower 2 bits are used by cancel
@ -657,11 +659,10 @@ struct pthread {
* The thread's base and pending signal masks. The active * The thread's base and pending signal masks. The active
* signal mask is stored in the thread's context (in mailbox). * signal mask is stored in the thread's context (in mailbox).
*/ */
sigset_t oldsigmask;
sigset_t sigmask; sigset_t sigmask;
sigset_t sigpend; sigset_t sigpend;
int sigmask_seqno;
int check_pending; int check_pending;
int have_signals;
int refcount; int refcount;
/* Thread state: */ /* Thread state: */
@ -997,14 +998,14 @@ SCLASS struct pthread_cond_attr _pthread_condattr_default
SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC); SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC);
/* Array of signal actions for this process: */ /* Array of signal actions for this process: */
SCLASS struct sigaction _thread_sigact[NSIG]; SCLASS struct sigaction _thread_sigact[_SIG_MAXSIG];
/* /*
* Array of counts of dummy handlers for SIG_DFL signals. This is used to * Array of counts of dummy handlers for SIG_DFL signals. This is used to
* assure that there is always a dummy signal handler installed while there * assure that there is always a dummy signal handler installed while there
* is a thread sigwait()ing on the corresponding signal. * is a thread sigwait()ing on the corresponding signal.
*/ */
SCLASS int _thread_dfl_count[NSIG]; SCLASS int _thread_dfl_count[_SIG_MAXSIG];
/* /*
* Lock for above count of dummy handlers and for the process signal * Lock for above count of dummy handlers and for the process signal
@ -1014,8 +1015,7 @@ SCLASS struct lock _thread_signal_lock;
/* Pending signals and mask for this process: */ /* Pending signals and mask for this process: */
SCLASS sigset_t _thr_proc_sigpending; SCLASS sigset_t _thr_proc_sigpending;
SCLASS sigset_t _thr_proc_sigmask SCLASS_PRESET({{0, 0, 0, 0}}); SCLASS siginfo_t _thr_proc_siginfo[_SIG_MAXSIG];
SCLASS siginfo_t _thr_proc_siginfo[NSIG];
SCLASS pid_t _thr_pid SCLASS_PRESET(0); SCLASS pid_t _thr_pid SCLASS_PRESET(0);
@ -1030,7 +1030,7 @@ SCLASS struct lock _keytable_lock;
SCLASS struct lock _thread_list_lock; SCLASS struct lock _thread_list_lock;
SCLASS int _thr_guard_default; SCLASS int _thr_guard_default;
SCLASS int _thr_page_size; SCLASS int _thr_page_size;
SCLASS pthread_t _thr_sig_daemon;
SCLASS int _thr_debug_flags SCLASS_PRESET(0); SCLASS int _thr_debug_flags SCLASS_PRESET(0);
/* Undefine the storage class and preset specifiers: */ /* Undefine the storage class and preset specifiers: */
@ -1116,7 +1116,6 @@ void _thr_panic_exit(char *, int, char *);
void _thread_cleanupspecific(void); void _thread_cleanupspecific(void);
void _thread_dump_info(void); void _thread_dump_info(void);
void _thread_printf(int, const char *, ...); void _thread_printf(int, const char *, ...);
void _thr_sched_frame(struct pthread_sigframe *);
void _thr_sched_switch(struct pthread *); void _thr_sched_switch(struct pthread *);
void _thr_sched_switch_unlocked(struct pthread *); void _thr_sched_switch_unlocked(struct pthread *);
void _thr_set_timeout(const struct timespec *); void _thr_set_timeout(const struct timespec *);
@ -1126,13 +1125,17 @@ void _thr_sig_check_pending(struct pthread *);
void _thr_sig_rundown(struct pthread *, ucontext_t *, void _thr_sig_rundown(struct pthread *, ucontext_t *,
struct pthread_sigframe *); struct pthread_sigframe *);
void _thr_sig_send(struct pthread *pthread, int sig); void _thr_sig_send(struct pthread *pthread, int sig);
void _thr_sig_wrapper(void);
void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf); void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf);
void _thr_spinlock_init(void); void _thr_spinlock_init(void);
void _thr_enter_cancellation_point(struct pthread *); void _thr_enter_cancellation_point(struct pthread *);
void _thr_leave_cancellation_point(struct pthread *); void _thr_leave_cancellation_point(struct pthread *);
int _thr_setconcurrency(int new_level); int _thr_setconcurrency(int new_level);
int _thr_setmaxconcurrency(void); int _thr_setmaxconcurrency(void);
int _thr_start_sig_daemon(void);
int _thr_getprocsig(int sig, siginfo_t *siginfo);
int _thr_getprocsig_unlocked(int sig, siginfo_t *siginfo);
void _thr_signal_init(void);
void _thr_signal_deinit(void);
/* /*
* Aliases for _pthread functions. Should be called instead of * Aliases for _pthread functions. Should be called instead of
@ -1216,6 +1219,8 @@ int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
ssize_t __sys_read(int, void *, size_t); ssize_t __sys_read(int, void *, size_t);
ssize_t __sys_write(int, const void *, size_t); ssize_t __sys_write(int, const void *, size_t);
void __sys_exit(int); void __sys_exit(int);
int __sys_sigwait(const sigset_t *, int *);
int __sys_sigtimedwait(sigset_t *, siginfo_t *, struct timespec *);
#endif #endif
/* #include <poll.h> */ /* #include <poll.h> */

File diff suppressed because it is too large Load Diff

View File

@ -43,16 +43,21 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
{ {
int ret = 0; int ret = 0;
struct sigaction gact; struct sigaction gact;
struct pthread *curthread;
kse_critical_t crit;
/* Check if the signal number is out of range: */ /* Check if the signal number is out of range: */
if (sig < 1 || sig > NSIG) { if (sig < 1 || sig > _SIG_MAXSIG) {
/* Return an invalid argument: */ /* Return an invalid argument: */
errno = EINVAL; errno = EINVAL;
ret = -1; ret = -1;
} else { } else {
if (_thr_initial == NULL) if (!_kse_isthreaded())
_libpthread_init(NULL); return __sys_sigaction(sig, act, oact);
crit = _kse_critical_enter();
curthread = _get_curthread();
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
/* /*
* Check if the existing signal action structure contents are * Check if the existing signal action structure contents are
* to be returned: * to be returned:
@ -99,6 +104,8 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
if (__sys_sigaction(sig, &gact, NULL) != 0) if (__sys_sigaction(sig, &gact, NULL) != 0)
ret = -1; ret = -1;
} }
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
_kse_critical_leave(crit);
} }
/* Return the completion status: */ /* Return the completion status: */

View File

@ -48,33 +48,35 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
int ret; int ret;
if (! _kse_isthreaded())
_kse_setthreaded(1);
THR_SCHED_LOCK(curthread, curthread);
ret = 0; ret = 0;
if (oset != NULL) if (oset != NULL)
/* Return the current mask: */ /* Return the current mask: */
*oset = curthread->tmbx.tm_context.uc_sigmask; *oset = curthread->sigmask;
/* Check if a new signal set was provided by the caller: */ /* Check if a new signal set was provided by the caller: */
if (set != NULL) { if (set != NULL) {
THR_SCHED_LOCK(curthread, curthread);
/* Process according to what to do: */ /* Process according to what to do: */
switch (how) { switch (how) {
/* Block signals: */ /* Block signals: */
case SIG_BLOCK: case SIG_BLOCK:
/* Add signals to the existing mask: */ /* Add signals to the existing mask: */
SIGSETOR(curthread->tmbx.tm_context.uc_sigmask, *set); SIGSETOR(curthread->sigmask, *set);
break; break;
/* Unblock signals: */ /* Unblock signals: */
case SIG_UNBLOCK: case SIG_UNBLOCK:
/* Clear signals from the existing mask: */ /* Clear signals from the existing mask: */
SIGSETNAND(curthread->tmbx.tm_context.uc_sigmask, *set); SIGSETNAND(curthread->sigmask, *set);
break; break;
/* Set the signal process mask: */ /* Set the signal process mask: */
case SIG_SETMASK: case SIG_SETMASK:
/* Set the new mask: */ /* Set the new mask: */
curthread->tmbx.tm_context.uc_sigmask = *set; curthread->sigmask = *set;
break; break;
/* Trap invalid actions: */ /* Trap invalid actions: */
@ -84,13 +86,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
ret = -1; ret = -1;
break; break;
} }
SIG_CANTMASK(curthread->sigmask);
if (ret == 0) {
curthread->sigmask =
curthread->tmbx.tm_context.uc_sigmask;
curthread->sigmask_seqno++;
}
THR_SCHED_UNLOCK(curthread, curthread); THR_SCHED_UNLOCK(curthread, curthread);
/* /*
@ -98,6 +94,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
*/ */
if (ret == 0) if (ret == 0)
_thr_sig_check_pending(curthread); _thr_sig_check_pending(curthread);
} } else
THR_SCHED_UNLOCK(curthread, curthread);
return (ret); return (ret);
} }

View File

@ -54,8 +54,13 @@ _sigpending(sigset_t *set)
ret = EINVAL; ret = EINVAL;
} }
else { else {
*set = curthread->sigpend; if (!_kse_isthreaded())
return __sys_sigpending(set);
crit = _kse_critical_enter(); crit = _kse_critical_enter();
KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
*set = curthread->sigpend;
KSE_SCHED_UNLOCK(curthread->kse, curthread->kseg);
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock); KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
SIGSETOR(*set, _thr_proc_sigpending); SIGSETOR(*set, _thr_proc_sigpending);
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock); KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);

View File

@ -46,8 +46,9 @@ _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
{ {
int ret; int ret;
ret = pthread_sigmask(how, set, oset); if (_kse_isthreaded() == 0)
if ((ret == 0) && (_kse_isthreaded() == 0))
ret = __sys_sigprocmask(how, set, oset); ret = __sys_sigprocmask(how, set, oset);
else
ret = pthread_sigmask(how, set, oset);
return (ret); return (ret);
} }

View File

@ -44,14 +44,19 @@ _sigsuspend(const sigset_t *set)
{ {
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
int ret = -1; int ret = -1;
sigset_t osigmask;
if (!_kse_isthreaded())
return __sys_sigsuspend(set);
/* Check if a new signal set was provided by the caller: */ /* Check if a new signal set was provided by the caller: */
if (set != NULL) { if (set != NULL) {
THR_LOCK_SWITCH(curthread); THR_LOCK_SWITCH(curthread);
/* Save current sigmask */
memcpy(&osigmask, &curthread->sigmask, sizeof(osigmask));
/* Change the caller's mask: */ /* Change the caller's mask: */
memcpy(&curthread->tmbx.tm_context.uc_sigmask, memcpy(&curthread->sigmask, set, sizeof(sigset_t));
set, sizeof(sigset_t));
THR_SET_STATE(curthread, PS_SIGSUSPEND); THR_SET_STATE(curthread, PS_SIGSUSPEND);
@ -61,9 +66,15 @@ _sigsuspend(const sigset_t *set)
/* Always return an interrupted error: */ /* Always return an interrupted error: */
errno = EINTR; errno = EINTR;
THR_SCHED_LOCK(curthread, curthread);
/* Restore the signal mask: */ /* Restore the signal mask: */
memcpy(&curthread->tmbx.tm_context.uc_sigmask, memcpy(&curthread->sigmask, &osigmask, sizeof(sigset_t));
&curthread->sigmask, sizeof(sigset_t)); THR_SCHED_UNLOCK(curthread, curthread);
/*
* signal mask is reloaded, need to check if there is
* pending proc signal I can handle.
*/
_thr_sig_check_pending(curthread);
} else { } else {
/* Return an invalid argument error: */ /* Return an invalid argument error: */
errno = EINVAL; errno = EINVAL;

View File

@ -39,10 +39,13 @@
#include <pthread.h> #include <pthread.h>
#include "thr_private.h" #include "thr_private.h"
__weak_reference(_sigwait, sigwait); __weak_reference(__sigwait, sigwait);
__weak_reference(__sigtimedwait, sigtimedwait);
__weak_reference(__sigwaitinfo, sigwaitinfo);
int static int
_sigwait(const sigset_t *set, int *sig) lib_sigtimedwait(const sigset_t *set, siginfo_t *info,
const struct timespec * timeout)
{ {
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
int ret = 0; int ret = 0;
@ -50,8 +53,14 @@ _sigwait(const sigset_t *set, int *sig)
sigset_t tempset, waitset; sigset_t tempset, waitset;
struct sigaction act; struct sigaction act;
kse_critical_t crit; kse_critical_t crit;
siginfo_t siginfo;
_thr_enter_cancellation_point(curthread); if (!_kse_isthreaded()) {
if (info == NULL)
info = &siginfo;
return __sys_sigtimedwait((sigset_t *)set, info,
(struct timespec *)timeout);
}
/* /*
* Specify the thread kernel signal handler. * Specify the thread kernel signal handler.
@ -59,7 +68,7 @@ _sigwait(const sigset_t *set, int *sig)
act.sa_handler = (void (*) ()) _thr_sig_handler; act.sa_handler = (void (*) ()) _thr_sig_handler;
act.sa_flags = SA_RESTART | SA_SIGINFO; act.sa_flags = SA_RESTART | SA_SIGINFO;
/* Ensure the signal handler cannot be interrupted by other signals: */ /* Ensure the signal handler cannot be interrupted by other signals: */
sigfillset(&act.sa_mask); SIGFILLSET(act.sa_mask);
/* /*
* Initialize the set of signals that will be waited on: * Initialize the set of signals that will be waited on:
@ -67,38 +76,11 @@ _sigwait(const sigset_t *set, int *sig)
waitset = *set; waitset = *set;
/* These signals can't be waited on. */ /* These signals can't be waited on. */
sigdelset(&waitset, SIGKILL); SIGDELSET(waitset, SIGKILL);
sigdelset(&waitset, SIGSTOP); SIGDELSET(waitset, SIGSTOP);
/*
* Check to see if a pending signal is in the wait mask.
* This has to be atomic.
*/
tempset = curthread->sigpend;
crit = _kse_critical_enter(); crit = _kse_critical_enter();
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock); KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
SIGSETOR(tempset, _thr_proc_sigpending);
SIGSETAND(tempset, waitset);
if (SIGNOTEMPTY(tempset)) {
/* Enter a loop to find a pending signal: */
for (i = 1; i < NSIG; i++) {
if (sigismember (&tempset, i))
break;
}
/* Clear the pending signal: */
if (sigismember(&curthread->sigpend, i))
sigdelset(&curthread->sigpend, i);
else
sigdelset(&_thr_proc_sigpending, i);
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
_kse_critical_leave(crit);
_thr_leave_cancellation_point(curthread);
/* Return the signal number to the caller: */
*sig = i;
return (0);
}
/* /*
* Enter a loop to find the signals that are SIG_DFL. For * Enter a loop to find the signals that are SIG_DFL. For
@ -110,66 +92,158 @@ _sigwait(const sigset_t *set, int *sig)
* mask because a subsequent sigaction could enable an * mask because a subsequent sigaction could enable an
* ignored signal. * ignored signal.
*/ */
sigemptyset(&tempset); SIGEMPTYSET(tempset);
for (i = 1; i < NSIG; i++) { for (i = 1; i <= _SIG_MAXSIG; i++) {
if (sigismember(&waitset, i) && if (SIGISMEMBER(waitset, i) &&
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) { (_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
_thread_dfl_count[i]++; _thread_dfl_count[i - 1]++;
sigaddset(&tempset, i); SIGADDSET(tempset, i);
if (_thread_dfl_count[i] == 1) { if (_thread_dfl_count[i - 1] == 1) {
if (__sys_sigaction(i, &act, NULL) != 0) if (__sys_sigaction(i, &act, NULL) != 0)
ret = -1; /* ret = -1 */;
} }
} }
} }
if (ret == 0) {
/* Done accessing _thread_dfl_count for now. */ /* Done accessing _thread_dfl_count for now. */
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock); KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
for (i = 1; i <= _SIG_MAXSIG; ++i) {
if (SIGISMEMBER(waitset, i) &&
SIGISMEMBER(curthread->sigpend, i)) {
SIGDELSET(curthread->sigpend, i);
*info = curthread->siginfo[i];
KSE_SCHED_UNLOCK(curthread->kse,
curthread->kseg);
_kse_critical_leave(crit); _kse_critical_leave(crit);
if (ret == 0) { return (i);
/* }
* Save the wait signal mask. The wait signal }
* mask is independent of the threads signal mask curthread->timeout = 0;
* and requires separate storage. _thr_set_timeout(timeout);
*/
curthread->data.sigwait = &waitset;
/* Wait for a signal: */ /* Wait for a signal: */
THR_LOCK_SWITCH(curthread); curthread->oldsigmask = curthread->sigmask;
siginfo.si_signo = 0;
curthread->data.sigwaitinfo = &siginfo;
SIGFILLSET(curthread->sigmask);
SIGSETNAND(curthread->sigmask, waitset);
THR_SET_STATE(curthread, PS_SIGWAIT); THR_SET_STATE(curthread, PS_SIGWAIT);
_thr_sched_switch_unlocked(curthread); _thr_sched_switch_unlocked(curthread);
/* Return the signal number to the caller: */ /*
*sig = curthread->signo; * Return the signal number to the caller:
* XXX Here is race, how about a signal come in before
* we reach here? so we might got an incorrect timeout
* status.
*/
if (siginfo.si_signo > 0) {
if (info)
*info = siginfo;
ret = siginfo.si_signo;
} else {
if (curthread->timeout)
errno = EAGAIN;
ret = -1;
}
/* /*
* Probably unnecessary, but since it's in a union struct * Probably unnecessary, but since it's in a union struct
* we don't know how it could be used in the future. * we don't know how it could be used in the future.
*/ */
curthread->data.sigwait = NULL; crit = _kse_critical_enter();
} curthread->data.sigwaitinfo = NULL;
/* /*
* Relock the array of SIG_DFL wait counts. * Relock the array of SIG_DFL wait counts.
*/ */
crit = _kse_critical_enter();
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock); KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
}
/* Restore the sigactions: */ /* Restore the sigactions: */
act.sa_handler = SIG_DFL; act.sa_handler = SIG_DFL;
for (i = 1; i < NSIG; i++) { for (i = 1; i <= _SIG_MAXSIG; i++) {
if (sigismember(&tempset, i)) { if (SIGISMEMBER(tempset, i)) {
_thread_dfl_count[i]--; _thread_dfl_count[i - 1]--;
if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) && if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
(_thread_dfl_count[i] == 0)) { (_thread_dfl_count[i - 1] == 0)) {
if (__sys_sigaction(i, &act, NULL) != 0) if (__sys_sigaction(i, &act, NULL) != 0)
ret = -1; /* ret = -1 */ ;
} }
} }
} }
/* Done accessing _thread_dfl_count. */ /* Done accessing _thread_dfl_count. */
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock); KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
_kse_critical_leave(crit); _kse_critical_leave(crit);
_thr_leave_cancellation_point(curthread);
/* Return the completion status: */
return (ret); return (ret);
} }
int
__sigtimedwait(const sigset_t *set, siginfo_t *info,
const struct timespec * timeout)
{
struct pthread *curthread = _get_curthread();
int ret;
_thr_enter_cancellation_point(curthread);
ret = lib_sigtimedwait(set, info, timeout);
_thr_leave_cancellation_point(curthread);
return (ret);
}
int _sigtimedwait(const sigset_t *set, siginfo_t *info,
const struct timespec * timeout)
{
return lib_sigtimedwait(set, info, timeout);
}
int
__sigwaitinfo(const sigset_t *set, siginfo_t *info)
{
struct pthread *curthread = _get_curthread();
int ret;
_thr_enter_cancellation_point(curthread);
ret = lib_sigtimedwait(set, info, NULL);
_thr_leave_cancellation_point(curthread);
return (ret);
}
int
_sigwaitinfo(const sigset_t *set, siginfo_t *info)
{
return lib_sigtimedwait(set, info, NULL);
}
int
__sigwait(const sigset_t *set, int *sig)
{
struct pthread *curthread = _get_curthread();
int ret;
_thr_enter_cancellation_point(curthread);
ret = lib_sigtimedwait(set, NULL, NULL);
if (ret > 0) {
*sig = ret;
ret = 0;
}
else
ret = -1;
_thr_leave_cancellation_point(curthread);
return (ret);
}
int
_sigwait(const sigset_t *set, int *sig)
{
int ret;
ret = lib_sigtimedwait(set, NULL, NULL);
if (ret > 0) {
*sig = ret;
ret = 0;
} else {
ret = -1;
}
return (ret);
}