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:
parent
8109f8e495
commit
8980e28992
@ -54,5 +54,8 @@ __strong_reference(memcpy, _thr_memcpy);
|
||||
__strong_reference(strcpy, _thr_strcpy);
|
||||
__strong_reference(strlen, _thr_strlen);
|
||||
__strong_reference(bzero, _thr_bzero);
|
||||
__strong_reference(bcopy, _thr_bcopy);
|
||||
|
||||
__strong_reference(__sys_write, _thr__sys_write);
|
||||
__strong_reference(__sys_sigtimedwait, _thr__sys_sigtimedwait);
|
||||
|
||||
|
@ -77,7 +77,7 @@ _thread_dump_info(void)
|
||||
int fd, 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);
|
||||
/* Open the dump file for append and create it if necessary: */
|
||||
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");
|
||||
__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: */
|
||||
switch (pthread->state) {
|
||||
case PS_SIGWAIT:
|
||||
snprintf(s, sizeof(s), "sigmask (hi)");
|
||||
__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--) {
|
||||
snprintf(s, sizeof(s), "%08x\n",
|
||||
pthread->sigmask.__bits[i]);
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "namespace.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
@ -304,7 +305,7 @@ _libpthread_init(struct pthread *curthread)
|
||||
_thr_initial->kse->k_curthread = _thr_initial;
|
||||
_thr_initial->kse->k_flags |= KF_INITIALIZED;
|
||||
_kse_initial->k_curthread = _thr_initial;
|
||||
|
||||
|
||||
_thr_rtld_init();
|
||||
}
|
||||
|
||||
@ -365,14 +366,13 @@ init_main_thread(struct pthread *thread)
|
||||
thread->name = strdup("initial thread");
|
||||
|
||||
/* Initialize the thread for signals: */
|
||||
sigemptyset(&thread->sigmask);
|
||||
SIGEMPTYSET(thread->sigmask);
|
||||
|
||||
/*
|
||||
* Set up the thread mailbox. The threads saved context
|
||||
* is also in the mailbox.
|
||||
*/
|
||||
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_sp = thread->attr.stackaddr_attr;
|
||||
|
||||
@ -407,10 +407,8 @@ static void
|
||||
init_private(void)
|
||||
{
|
||||
struct clockinfo clockinfo;
|
||||
struct sigaction act;
|
||||
size_t len;
|
||||
int mib[2];
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Avoid reinitializing some things if they don't need to be,
|
||||
@ -448,36 +446,6 @@ init_private(void)
|
||||
|
||||
_thr_page_size = getpagesize();
|
||||
_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. */
|
||||
} else {
|
||||
/*
|
||||
@ -495,8 +463,6 @@ init_private(void)
|
||||
TAILQ_INIT(&_thread_list);
|
||||
TAILQ_INIT(&_thread_gc_list);
|
||||
|
||||
/* Enter a loop to get the existing signal status: */
|
||||
|
||||
/* Initialize the SIG_DFL dummy handler count. */
|
||||
bzero(_thread_dfl_count, sizeof(_thread_dfl_count));
|
||||
|
||||
@ -520,8 +486,7 @@ init_private(void)
|
||||
_thr_spinlock_init();
|
||||
|
||||
/* Clear pending signals and get the process signal mask. */
|
||||
sigemptyset(&_thr_proc_sigpending);
|
||||
__sys_sigprocmask(SIG_SETMASK, NULL, &_thr_proc_sigmask);
|
||||
SIGEMPTYSET(_thr_proc_sigpending);
|
||||
|
||||
/*
|
||||
* _thread_list_lock and _kse_count are initialized
|
||||
|
@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/queue.h>
|
||||
#include <machine/atomic.h>
|
||||
#include <machine/sigframe.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
@ -125,7 +126,6 @@ static void dump_queues(struct kse *curkse);
|
||||
#endif
|
||||
static void kse_check_completed(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_reinit(struct kse *kse);
|
||||
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 thr_cleanup(struct kse *kse, struct pthread *curthread);
|
||||
static void thr_link(struct pthread *thread);
|
||||
static void thr_resume_wrapper(int unused_1, siginfo_t *unused_2,
|
||||
ucontext_t *ucp);
|
||||
static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
|
||||
static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
|
||||
struct pthread_sigframe *psf);
|
||||
static int thr_timedout(struct pthread *thread, struct timespec *curtime);
|
||||
static void thr_unlink(struct pthread *thread);
|
||||
|
||||
|
||||
/*
|
||||
* This is called after a fork().
|
||||
* No locks need to be taken here since we are guaranteed to be
|
||||
* 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
|
||||
_kse_single_thread(struct pthread *curthread)
|
||||
{
|
||||
#ifdef NOTYET
|
||||
struct kse *kse;
|
||||
struct kse_group *kseg;
|
||||
struct pthread *thread;
|
||||
kse_critical_t crit;
|
||||
int i;
|
||||
|
||||
|
||||
/*
|
||||
* Disable upcalls and clear the threaded flag.
|
||||
* 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();
|
||||
__isthreaded = 0;
|
||||
active_threads = 1;
|
||||
_thr_signal_deinit();
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
curthread->joiner = NULL; /* no joining threads yet */
|
||||
curthread->refcount = 0;
|
||||
sigemptyset(&curthread->sigpend); /* clear pending signals */
|
||||
SIGEMPTYSET(curthread->sigpend); /* clear pending signals */
|
||||
if (curthread->specific != NULL) {
|
||||
free(curthread->specific);
|
||||
curthread->specific = NULL;
|
||||
@ -307,6 +320,12 @@ _kse_single_thread(struct pthread *curthread)
|
||||
curthread->kseg = NULL;
|
||||
_kse_initial = NULL;
|
||||
_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
|
||||
* and enable upcalls in it.
|
||||
*/
|
||||
_thr_signal_init();
|
||||
_kse_initial->k_flags |= KF_STARTED;
|
||||
if (kse_create(&_kse_initial->k_mbx, 0) != 0) {
|
||||
_kse_initial->k_flags &= ~KF_STARTED;
|
||||
__isthreaded = 0;
|
||||
/* may abort() */
|
||||
DBG_MSG("kse_create failed\n");
|
||||
PANIC("kse_create() failed\n");
|
||||
return (-1);
|
||||
}
|
||||
KSE_SET_MBOX(_kse_initial, _thr_initial);
|
||||
_thr_start_sig_daemon();
|
||||
_thr_setmaxconcurrency();
|
||||
}
|
||||
return (0);
|
||||
@ -536,6 +557,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
|
||||
int ret;
|
||||
volatile int uts_once;
|
||||
volatile int resume_once = 0;
|
||||
ucontext_t uc;
|
||||
|
||||
/* We're in the scheduler, 5 by 5: */
|
||||
curkse = _get_curkse();
|
||||
@ -552,7 +574,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
|
||||
* a thread can be interrupted by other signals while
|
||||
* it is running down pending signals.
|
||||
*/
|
||||
sigemptyset(&psf.psf_sigset);
|
||||
psf.psf_valid = 0;
|
||||
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
|
||||
* cleaned up and it can't be done while operating on
|
||||
* it.
|
||||
* o The current thread has signals pending, should
|
||||
* let scheduler install signal trampoline for us.
|
||||
* o There are no runnable threads.
|
||||
* o The next thread to run won't unlock the scheduler
|
||||
* 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) ||
|
||||
(((td = KSE_RUNQ_FIRST(curkse)) == NULL) &&
|
||||
(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);
|
||||
}
|
||||
else {
|
||||
uts_once = 0;
|
||||
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) {
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if ((resume_once == 0) && (!THR_IN_CRITICAL(curthread))) {
|
||||
resume_once = 1;
|
||||
thr_resume_check(curthread, &curthread->tmbx.tm_context, &psf);
|
||||
if ((psf.psf_valid || curthread->check_pending)) {
|
||||
resume_once = 0;
|
||||
THR_GETCONTEXT(&uc);
|
||||
if (resume_once == 0) {
|
||||
resume_once = 1;
|
||||
curthread->check_pending = 0;
|
||||
thr_resume_check(curthread, &uc, &psf);
|
||||
}
|
||||
}
|
||||
|
||||
THR_ACTIVATE_LAST_LOCK(curthread);
|
||||
}
|
||||
|
||||
@ -747,9 +786,6 @@ kse_sched_single(struct kse *curkse)
|
||||
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. */
|
||||
@ -810,12 +846,12 @@ kse_sched_multi(struct kse *curkse)
|
||||
KSE_CLEAR_WAIT(curkse);
|
||||
}
|
||||
|
||||
/* Lock the scheduling lock. */
|
||||
curthread = curkse->k_curthread;
|
||||
if ((curthread == NULL) || (curthread->need_switchout == 0)) {
|
||||
/* This is an upcall; take the scheduler lock. */
|
||||
/*If this is an upcall; take the scheduler lock. */
|
||||
if (curkse->k_switch == 0)
|
||||
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
|
||||
}
|
||||
curkse->k_switch = 0;
|
||||
|
||||
curthread = curkse->k_curthread;
|
||||
|
||||
if (KSE_IS_IDLE(curkse)) {
|
||||
KSE_CLEAR_IDLE(curkse);
|
||||
@ -879,11 +915,6 @@ kse_sched_multi(struct kse *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
|
||||
dump_queues(curkse);
|
||||
#endif
|
||||
@ -899,9 +930,6 @@ kse_sched_multi(struct kse *curkse)
|
||||
kse_wait(curkse, td_wait);
|
||||
kse_check_completed(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: */
|
||||
@ -966,15 +994,19 @@ kse_sched_multi(struct kse *curkse)
|
||||
* signal frame to the thread's context.
|
||||
*/
|
||||
#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 & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))))
|
||||
((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))) &&
|
||||
!THR_IN_CRITICAL(curthread))
|
||||
signalcontext(&curthread->tmbx.tm_context, 0,
|
||||
(__sighandler_t *)thr_resume_wrapper);
|
||||
#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,
|
||||
(__sighandler_t *)thr_resume_wrapper);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Continue the thread at its current frame:
|
||||
@ -999,61 +1031,31 @@ kse_sched_multi(struct kse *curkse)
|
||||
}
|
||||
|
||||
static void
|
||||
kse_check_signals(struct kse *curkse)
|
||||
{
|
||||
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)
|
||||
thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
|
||||
{
|
||||
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);
|
||||
_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
|
||||
thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
|
||||
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
|
||||
if (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
|
||||
@ -1124,7 +1126,7 @@ thr_cleanup(struct kse *curkse, struct pthread *thread)
|
||||
THR_GCLIST_ADD(thread);
|
||||
/* Use thread_list_lock */
|
||||
active_threads--;
|
||||
if (active_threads == 0) {
|
||||
if (active_threads == 1) {
|
||||
KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
|
||||
exit(0);
|
||||
}
|
||||
@ -1203,8 +1205,15 @@ _thr_gc(struct pthread *curthread)
|
||||
KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
|
||||
_kse_critical_leave(crit);
|
||||
}
|
||||
DBG_MSG("Freeing thread %p\n", td);
|
||||
_thr_free(curthread, td);
|
||||
/*
|
||||
* 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);
|
||||
_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 */
|
||||
}
|
||||
@ -1216,7 +1225,6 @@ _thr_gc(struct pthread *curthread)
|
||||
int
|
||||
_thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
|
||||
{
|
||||
struct kse *curkse;
|
||||
kse_critical_t crit;
|
||||
int ret;
|
||||
|
||||
@ -1250,15 +1258,11 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
|
||||
/*
|
||||
* This thread needs a new KSE and KSEG.
|
||||
*/
|
||||
crit = _kse_critical_enter();
|
||||
curkse = _get_curkse();
|
||||
_ksd_setprivate(&newthread->kse->k_ksd);
|
||||
newthread->kse->k_flags |= KF_INITIALIZED|KF_STARTED;
|
||||
newthread->kse->k_flags &= ~KF_INITIALIZED;
|
||||
newthread->kse->k_flags |= KF_STARTED;
|
||||
ret = kse_create(&newthread->kse->k_mbx, 1);
|
||||
if (ret != 0)
|
||||
ret = errno;
|
||||
_ksd_setprivate(&curkse->k_ksd);
|
||||
_kse_critical_leave(crit);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
@ -1266,6 +1270,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
|
||||
* assigned threads. If the new thread is runnable, also
|
||||
* add it to the KSE's run queue.
|
||||
*/
|
||||
crit = _kse_critical_enter();
|
||||
KSE_SCHED_LOCK(curthread->kse, newthread->kseg);
|
||||
KSEG_THRQ_ADD(newthread->kseg, newthread);
|
||||
if (newthread->state == PS_RUNNING)
|
||||
@ -1288,6 +1293,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
|
||||
kse_wakeup_one(newthread);
|
||||
}
|
||||
KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg);
|
||||
_kse_critical_leave(crit);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret != 0)
|
||||
@ -1328,6 +1334,7 @@ kse_check_completed(struct kse *kse)
|
||||
{
|
||||
struct pthread *thread;
|
||||
struct kse_thr_mailbox *completed;
|
||||
int sig;
|
||||
|
||||
if ((completed = 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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1446,6 +1460,8 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
|
||||
{
|
||||
int level;
|
||||
int i;
|
||||
int restart;
|
||||
siginfo_t siginfo;
|
||||
|
||||
/*
|
||||
* Place the currently running thread into the
|
||||
@ -1459,15 +1475,25 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
|
||||
thread->need_switchout = 0;
|
||||
/* This thread must have blocked in the kernel. */
|
||||
/* 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) &&
|
||||
(thread->attr.sched_policy != SCHED_FIFO))
|
||||
thread->slice_usec += (thread->tmbx.tm_uticks
|
||||
+ 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 {
|
||||
switch (thread->state) {
|
||||
@ -1507,10 +1533,12 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
|
||||
THR_SET_STATE(thread, PS_RUNNING);
|
||||
break;
|
||||
|
||||
case PS_SIGWAIT:
|
||||
KSE_WAITQ_INSERT(kse, thread);
|
||||
break;
|
||||
case PS_JOIN:
|
||||
case PS_MUTEX_WAIT:
|
||||
case PS_SIGSUSPEND:
|
||||
case PS_SIGWAIT:
|
||||
case PS_SUSPENDED:
|
||||
case PS_DEADLOCK:
|
||||
default:
|
||||
@ -1564,11 +1592,18 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
|
||||
if (thread->check_pending != 0) {
|
||||
/* Install pending signals into the frame. */
|
||||
thread->check_pending = 0;
|
||||
for (i = 0; i < _SIG_MAXSIG; i++) {
|
||||
if (sigismember(&thread->sigpend, i) &&
|
||||
!sigismember(&thread->tmbx.tm_context.uc_sigmask, i))
|
||||
KSE_LOCK_ACQUIRE(kse, &_thread_signal_lock);
|
||||
for (i = 1; i <= _SIG_MAXSIG; i++) {
|
||||
if (SIGISMEMBER(thread->sigmask, i))
|
||||
continue;
|
||||
if (SIGISMEMBER(thread->sigpend, 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]);
|
||||
}
|
||||
free(kse);
|
||||
if (curthread != NULL) {
|
||||
KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
|
||||
_kse_critical_leave(crit);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
kse->k_flags = 0;
|
||||
@ -2044,7 +2083,7 @@ kse_reinit(struct kse *kse)
|
||||
kse->k_kseg = 0;
|
||||
kse->k_schedq = 0;
|
||||
kse->k_locklevel = 0;
|
||||
sigemptyset(&kse->k_sigmask);
|
||||
SIGEMPTYSET(kse->k_sigmask);
|
||||
bzero(&kse->k_sigq, sizeof(kse->k_sigq));
|
||||
kse->k_check_sigq = 0;
|
||||
kse->k_flags = 0;
|
||||
@ -2053,6 +2092,7 @@ kse_reinit(struct kse *kse)
|
||||
kse->k_error = 0;
|
||||
kse->k_cpu = 0;
|
||||
kse->k_done = 0;
|
||||
kse->k_switch = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -2171,10 +2211,12 @@ thr_link(struct pthread *thread)
|
||||
{
|
||||
kse_critical_t crit;
|
||||
struct kse *curkse;
|
||||
struct pthread *curthread;
|
||||
|
||||
crit = _kse_critical_enter();
|
||||
curkse = _get_curkse();
|
||||
|
||||
curthread = _get_curthread();
|
||||
thread->sigmask = curthread->sigmask;
|
||||
KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
|
||||
/*
|
||||
* Initialize the unique id (which GDB uses to track
|
||||
|
@ -45,7 +45,7 @@ _pthread_kill(pthread_t pthread, int sig)
|
||||
int ret;
|
||||
|
||||
/* Check for invalid signal numbers: */
|
||||
if (sig < 0 || sig >= NSIG)
|
||||
if (sig < 0 || sig > _SIG_MAXSIG)
|
||||
/* Invalid signal: */
|
||||
ret = EINVAL;
|
||||
/*
|
||||
|
@ -171,7 +171,7 @@ typedef struct kse_thr_mailbox *kse_critical_t;
|
||||
|
||||
struct kse_group;
|
||||
|
||||
#define MAX_KSE_LOCKLEVEL 3
|
||||
#define MAX_KSE_LOCKLEVEL 5
|
||||
struct kse {
|
||||
struct kse_mailbox k_mbx; /* kernel kse mailbox */
|
||||
/* -- location and order specific items for gdb -- */
|
||||
@ -190,7 +190,7 @@ struct kse {
|
||||
struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL];
|
||||
int k_locklevel;
|
||||
sigset_t k_sigmask;
|
||||
struct sigstatus k_sigq[NSIG];
|
||||
struct sigstatus k_sigq[_SIG_MAXSIG];
|
||||
stack_t k_stack;
|
||||
int k_check_sigq;
|
||||
int k_flags;
|
||||
@ -201,6 +201,7 @@ struct kse {
|
||||
int k_error; /* syscall errno in critical */
|
||||
int k_cpu; /* CPU ID when bound */
|
||||
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 {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
const sigset_t *sigwait; /* Waiting on a signal in sigwait */
|
||||
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.
|
||||
*/
|
||||
struct pthread_sigframe {
|
||||
int psf_valid;
|
||||
int psf_flags;
|
||||
int psf_interrupted;
|
||||
int psf_signo;
|
||||
@ -586,7 +588,7 @@ struct pthread_specific_elem {
|
||||
};
|
||||
|
||||
|
||||
#define MAX_THR_LOCKLEVEL 3
|
||||
#define MAX_THR_LOCKLEVEL 5
|
||||
/*
|
||||
* Thread structure.
|
||||
*/
|
||||
@ -640,7 +642,7 @@ struct pthread {
|
||||
* Used for tracking delivery of signal handlers.
|
||||
*/
|
||||
struct pthread_sigframe *curframe;
|
||||
siginfo_t siginfo[NSIG];
|
||||
siginfo_t siginfo[_SIG_MAXSIG];
|
||||
|
||||
/*
|
||||
* 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
|
||||
* signal mask is stored in the thread's context (in mailbox).
|
||||
*/
|
||||
sigset_t oldsigmask;
|
||||
sigset_t sigmask;
|
||||
sigset_t sigpend;
|
||||
int sigmask_seqno;
|
||||
int check_pending;
|
||||
int have_signals;
|
||||
int refcount;
|
||||
|
||||
/* Thread state: */
|
||||
@ -997,14 +998,14 @@ SCLASS struct pthread_cond_attr _pthread_condattr_default
|
||||
SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC);
|
||||
|
||||
/* 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
|
||||
* assure that there is always a dummy signal handler installed while there
|
||||
* 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
|
||||
@ -1014,8 +1015,7 @@ SCLASS struct lock _thread_signal_lock;
|
||||
|
||||
/* Pending signals and mask for this process: */
|
||||
SCLASS sigset_t _thr_proc_sigpending;
|
||||
SCLASS sigset_t _thr_proc_sigmask SCLASS_PRESET({{0, 0, 0, 0}});
|
||||
SCLASS siginfo_t _thr_proc_siginfo[NSIG];
|
||||
SCLASS siginfo_t _thr_proc_siginfo[_SIG_MAXSIG];
|
||||
|
||||
SCLASS pid_t _thr_pid SCLASS_PRESET(0);
|
||||
|
||||
@ -1030,7 +1030,7 @@ SCLASS struct lock _keytable_lock;
|
||||
SCLASS struct lock _thread_list_lock;
|
||||
SCLASS int _thr_guard_default;
|
||||
SCLASS int _thr_page_size;
|
||||
|
||||
SCLASS pthread_t _thr_sig_daemon;
|
||||
SCLASS int _thr_debug_flags SCLASS_PRESET(0);
|
||||
|
||||
/* Undefine the storage class and preset specifiers: */
|
||||
@ -1116,7 +1116,6 @@ void _thr_panic_exit(char *, int, char *);
|
||||
void _thread_cleanupspecific(void);
|
||||
void _thread_dump_info(void);
|
||||
void _thread_printf(int, const char *, ...);
|
||||
void _thr_sched_frame(struct pthread_sigframe *);
|
||||
void _thr_sched_switch(struct pthread *);
|
||||
void _thr_sched_switch_unlocked(struct pthread *);
|
||||
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 *,
|
||||
struct pthread_sigframe *);
|
||||
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_spinlock_init(void);
|
||||
void _thr_enter_cancellation_point(struct pthread *);
|
||||
void _thr_leave_cancellation_point(struct pthread *);
|
||||
int _thr_setconcurrency(int new_level);
|
||||
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
|
||||
@ -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_write(int, const void *, size_t);
|
||||
void __sys_exit(int);
|
||||
int __sys_sigwait(const sigset_t *, int *);
|
||||
int __sys_sigtimedwait(sigset_t *, siginfo_t *, struct timespec *);
|
||||
#endif
|
||||
|
||||
/* #include <poll.h> */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,16 +43,21 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sigaction gact;
|
||||
struct pthread *curthread;
|
||||
kse_critical_t crit;
|
||||
|
||||
/* Check if the signal number is out of range: */
|
||||
if (sig < 1 || sig > NSIG) {
|
||||
if (sig < 1 || sig > _SIG_MAXSIG) {
|
||||
/* Return an invalid argument: */
|
||||
errno = EINVAL;
|
||||
ret = -1;
|
||||
} else {
|
||||
if (_thr_initial == NULL)
|
||||
_libpthread_init(NULL);
|
||||
if (!_kse_isthreaded())
|
||||
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
|
||||
* to be returned:
|
||||
@ -99,6 +104,8 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
|
||||
if (__sys_sigaction(sig, &gact, NULL) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
|
||||
_kse_critical_leave(crit);
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
@ -48,33 +48,35 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
struct pthread *curthread = _get_curthread();
|
||||
int ret;
|
||||
|
||||
if (! _kse_isthreaded())
|
||||
_kse_setthreaded(1);
|
||||
|
||||
THR_SCHED_LOCK(curthread, curthread);
|
||||
ret = 0;
|
||||
if (oset != NULL)
|
||||
/* 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: */
|
||||
if (set != NULL) {
|
||||
THR_SCHED_LOCK(curthread, curthread);
|
||||
|
||||
/* Process according to what to do: */
|
||||
switch (how) {
|
||||
/* Block signals: */
|
||||
case SIG_BLOCK:
|
||||
/* Add signals to the existing mask: */
|
||||
SIGSETOR(curthread->tmbx.tm_context.uc_sigmask, *set);
|
||||
SIGSETOR(curthread->sigmask, *set);
|
||||
break;
|
||||
|
||||
/* Unblock signals: */
|
||||
case SIG_UNBLOCK:
|
||||
/* Clear signals from the existing mask: */
|
||||
SIGSETNAND(curthread->tmbx.tm_context.uc_sigmask, *set);
|
||||
SIGSETNAND(curthread->sigmask, *set);
|
||||
break;
|
||||
|
||||
/* Set the signal process mask: */
|
||||
case SIG_SETMASK:
|
||||
/* Set the new mask: */
|
||||
curthread->tmbx.tm_context.uc_sigmask = *set;
|
||||
curthread->sigmask = *set;
|
||||
break;
|
||||
|
||||
/* Trap invalid actions: */
|
||||
@ -84,13 +86,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
curthread->sigmask =
|
||||
curthread->tmbx.tm_context.uc_sigmask;
|
||||
curthread->sigmask_seqno++;
|
||||
}
|
||||
|
||||
SIG_CANTMASK(curthread->sigmask);
|
||||
THR_SCHED_UNLOCK(curthread, curthread);
|
||||
|
||||
/*
|
||||
@ -98,6 +94,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
*/
|
||||
if (ret == 0)
|
||||
_thr_sig_check_pending(curthread);
|
||||
}
|
||||
} else
|
||||
THR_SCHED_UNLOCK(curthread, curthread);
|
||||
return (ret);
|
||||
}
|
||||
|
@ -54,8 +54,13 @@ _sigpending(sigset_t *set)
|
||||
ret = EINVAL;
|
||||
}
|
||||
else {
|
||||
*set = curthread->sigpend;
|
||||
if (!_kse_isthreaded())
|
||||
return __sys_sigpending(set);
|
||||
|
||||
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);
|
||||
SIGSETOR(*set, _thr_proc_sigpending);
|
||||
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
|
||||
|
@ -46,8 +46,9 @@ _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_sigmask(how, set, oset);
|
||||
if ((ret == 0) && (_kse_isthreaded() == 0))
|
||||
if (_kse_isthreaded() == 0)
|
||||
ret = __sys_sigprocmask(how, set, oset);
|
||||
else
|
||||
ret = pthread_sigmask(how, set, oset);
|
||||
return (ret);
|
||||
}
|
||||
|
@ -44,14 +44,19 @@ _sigsuspend(const sigset_t *set)
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
int ret = -1;
|
||||
sigset_t osigmask;
|
||||
|
||||
if (!_kse_isthreaded())
|
||||
return __sys_sigsuspend(set);
|
||||
|
||||
/* Check if a new signal set was provided by the caller: */
|
||||
if (set != NULL) {
|
||||
THR_LOCK_SWITCH(curthread);
|
||||
|
||||
/* Save current sigmask */
|
||||
memcpy(&osigmask, &curthread->sigmask, sizeof(osigmask));
|
||||
/* Change the caller's mask: */
|
||||
memcpy(&curthread->tmbx.tm_context.uc_sigmask,
|
||||
set, sizeof(sigset_t));
|
||||
memcpy(&curthread->sigmask, set, sizeof(sigset_t));
|
||||
|
||||
THR_SET_STATE(curthread, PS_SIGSUSPEND);
|
||||
|
||||
@ -61,9 +66,15 @@ _sigsuspend(const sigset_t *set)
|
||||
/* Always return an interrupted error: */
|
||||
errno = EINTR;
|
||||
|
||||
THR_SCHED_LOCK(curthread, curthread);
|
||||
/* Restore the signal mask: */
|
||||
memcpy(&curthread->tmbx.tm_context.uc_sigmask,
|
||||
&curthread->sigmask, sizeof(sigset_t));
|
||||
memcpy(&curthread->sigmask, &osigmask, 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 {
|
||||
/* Return an invalid argument error: */
|
||||
errno = EINVAL;
|
||||
|
@ -39,10 +39,13 @@
|
||||
#include <pthread.h>
|
||||
#include "thr_private.h"
|
||||
|
||||
__weak_reference(_sigwait, sigwait);
|
||||
__weak_reference(__sigwait, sigwait);
|
||||
__weak_reference(__sigtimedwait, sigtimedwait);
|
||||
__weak_reference(__sigwaitinfo, sigwaitinfo);
|
||||
|
||||
int
|
||||
_sigwait(const sigset_t *set, int *sig)
|
||||
static int
|
||||
lib_sigtimedwait(const sigset_t *set, siginfo_t *info,
|
||||
const struct timespec * timeout)
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
int ret = 0;
|
||||
@ -50,8 +53,14 @@ _sigwait(const sigset_t *set, int *sig)
|
||||
sigset_t tempset, waitset;
|
||||
struct sigaction act;
|
||||
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.
|
||||
@ -59,7 +68,7 @@ _sigwait(const sigset_t *set, int *sig)
|
||||
act.sa_handler = (void (*) ()) _thr_sig_handler;
|
||||
act.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
/* 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:
|
||||
@ -67,41 +76,14 @@ _sigwait(const sigset_t *set, int *sig)
|
||||
waitset = *set;
|
||||
|
||||
/* These signals can't be waited on. */
|
||||
sigdelset(&waitset, SIGKILL);
|
||||
sigdelset(&waitset, SIGSTOP);
|
||||
SIGDELSET(waitset, SIGKILL);
|
||||
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();
|
||||
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
|
||||
* these signals we must install a dummy signal handler in
|
||||
* order for the kernel to pass them in to us. POSIX says
|
||||
* that the _application_ must explicitly install a dummy
|
||||
@ -110,66 +92,158 @@ _sigwait(const sigset_t *set, int *sig)
|
||||
* mask because a subsequent sigaction could enable an
|
||||
* ignored signal.
|
||||
*/
|
||||
sigemptyset(&tempset);
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&waitset, i) &&
|
||||
SIGEMPTYSET(tempset);
|
||||
for (i = 1; i <= _SIG_MAXSIG; i++) {
|
||||
if (SIGISMEMBER(waitset, i) &&
|
||||
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
|
||||
_thread_dfl_count[i]++;
|
||||
sigaddset(&tempset, i);
|
||||
if (_thread_dfl_count[i] == 1) {
|
||||
_thread_dfl_count[i - 1]++;
|
||||
SIGADDSET(tempset, i);
|
||||
if (_thread_dfl_count[i - 1] == 1) {
|
||||
if (__sys_sigaction(i, &act, NULL) != 0)
|
||||
ret = -1;
|
||||
/* ret = -1 */;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Done accessing _thread_dfl_count for now. */
|
||||
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
|
||||
_kse_critical_leave(crit);
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* Save the wait signal mask. The wait signal
|
||||
* mask is independent of the threads signal mask
|
||||
* and requires separate storage.
|
||||
*/
|
||||
curthread->data.sigwait = &waitset;
|
||||
|
||||
if (ret == 0) {
|
||||
/* Done accessing _thread_dfl_count for now. */
|
||||
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);
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
curthread->timeout = 0;
|
||||
_thr_set_timeout(timeout);
|
||||
/* 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_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
|
||||
* 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.
|
||||
*/
|
||||
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Relock the array of SIG_DFL wait counts.
|
||||
*/
|
||||
crit = _kse_critical_enter();
|
||||
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
|
||||
|
||||
/* Restore the sigactions: */
|
||||
act.sa_handler = SIG_DFL;
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&tempset, i)) {
|
||||
_thread_dfl_count[i]--;
|
||||
for (i = 1; i <= _SIG_MAXSIG; i++) {
|
||||
if (SIGISMEMBER(tempset, i)) {
|
||||
_thread_dfl_count[i - 1]--;
|
||||
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)
|
||||
ret = -1;
|
||||
/* ret = -1 */ ;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Done accessing _thread_dfl_count. */
|
||||
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
|
||||
_kse_critical_leave(crit);
|
||||
_thr_leave_cancellation_point(curthread);
|
||||
|
||||
/* Return the completion status: */
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,8 @@ global:
|
||||
_sigprocmask;
|
||||
_sigsuspend;
|
||||
_sigwait;
|
||||
_sigtimedwait;
|
||||
_sigwaitinfo;
|
||||
_sleep;
|
||||
_spinlock;
|
||||
_spinlock_debug;
|
||||
@ -271,6 +273,8 @@ global:
|
||||
sigprocmask;
|
||||
sigsuspend;
|
||||
sigwait;
|
||||
sigwaitinfo;
|
||||
sigtimedwait;
|
||||
sleep;
|
||||
system;
|
||||
tcdrain;
|
||||
|
@ -54,5 +54,8 @@ __strong_reference(memcpy, _thr_memcpy);
|
||||
__strong_reference(strcpy, _thr_strcpy);
|
||||
__strong_reference(strlen, _thr_strlen);
|
||||
__strong_reference(bzero, _thr_bzero);
|
||||
__strong_reference(bcopy, _thr_bcopy);
|
||||
|
||||
__strong_reference(__sys_write, _thr__sys_write);
|
||||
__strong_reference(__sys_sigtimedwait, _thr__sys_sigtimedwait);
|
||||
|
||||
|
@ -77,7 +77,7 @@ _thread_dump_info(void)
|
||||
int fd, 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);
|
||||
/* Open the dump file for append and create it if necessary: */
|
||||
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");
|
||||
__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: */
|
||||
switch (pthread->state) {
|
||||
case PS_SIGWAIT:
|
||||
snprintf(s, sizeof(s), "sigmask (hi)");
|
||||
__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--) {
|
||||
snprintf(s, sizeof(s), "%08x\n",
|
||||
pthread->sigmask.__bits[i]);
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "namespace.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
@ -304,7 +305,7 @@ _libpthread_init(struct pthread *curthread)
|
||||
_thr_initial->kse->k_curthread = _thr_initial;
|
||||
_thr_initial->kse->k_flags |= KF_INITIALIZED;
|
||||
_kse_initial->k_curthread = _thr_initial;
|
||||
|
||||
|
||||
_thr_rtld_init();
|
||||
}
|
||||
|
||||
@ -365,14 +366,13 @@ init_main_thread(struct pthread *thread)
|
||||
thread->name = strdup("initial thread");
|
||||
|
||||
/* Initialize the thread for signals: */
|
||||
sigemptyset(&thread->sigmask);
|
||||
SIGEMPTYSET(thread->sigmask);
|
||||
|
||||
/*
|
||||
* Set up the thread mailbox. The threads saved context
|
||||
* is also in the mailbox.
|
||||
*/
|
||||
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_sp = thread->attr.stackaddr_attr;
|
||||
|
||||
@ -407,10 +407,8 @@ static void
|
||||
init_private(void)
|
||||
{
|
||||
struct clockinfo clockinfo;
|
||||
struct sigaction act;
|
||||
size_t len;
|
||||
int mib[2];
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Avoid reinitializing some things if they don't need to be,
|
||||
@ -448,36 +446,6 @@ init_private(void)
|
||||
|
||||
_thr_page_size = getpagesize();
|
||||
_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. */
|
||||
} else {
|
||||
/*
|
||||
@ -495,8 +463,6 @@ init_private(void)
|
||||
TAILQ_INIT(&_thread_list);
|
||||
TAILQ_INIT(&_thread_gc_list);
|
||||
|
||||
/* Enter a loop to get the existing signal status: */
|
||||
|
||||
/* Initialize the SIG_DFL dummy handler count. */
|
||||
bzero(_thread_dfl_count, sizeof(_thread_dfl_count));
|
||||
|
||||
@ -520,8 +486,7 @@ init_private(void)
|
||||
_thr_spinlock_init();
|
||||
|
||||
/* Clear pending signals and get the process signal mask. */
|
||||
sigemptyset(&_thr_proc_sigpending);
|
||||
__sys_sigprocmask(SIG_SETMASK, NULL, &_thr_proc_sigmask);
|
||||
SIGEMPTYSET(_thr_proc_sigpending);
|
||||
|
||||
/*
|
||||
* _thread_list_lock and _kse_count are initialized
|
||||
|
@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/queue.h>
|
||||
#include <machine/atomic.h>
|
||||
#include <machine/sigframe.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
@ -125,7 +126,6 @@ static void dump_queues(struct kse *curkse);
|
||||
#endif
|
||||
static void kse_check_completed(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_reinit(struct kse *kse);
|
||||
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 thr_cleanup(struct kse *kse, struct pthread *curthread);
|
||||
static void thr_link(struct pthread *thread);
|
||||
static void thr_resume_wrapper(int unused_1, siginfo_t *unused_2,
|
||||
ucontext_t *ucp);
|
||||
static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
|
||||
static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
|
||||
struct pthread_sigframe *psf);
|
||||
static int thr_timedout(struct pthread *thread, struct timespec *curtime);
|
||||
static void thr_unlink(struct pthread *thread);
|
||||
|
||||
|
||||
/*
|
||||
* This is called after a fork().
|
||||
* No locks need to be taken here since we are guaranteed to be
|
||||
* 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
|
||||
_kse_single_thread(struct pthread *curthread)
|
||||
{
|
||||
#ifdef NOTYET
|
||||
struct kse *kse;
|
||||
struct kse_group *kseg;
|
||||
struct pthread *thread;
|
||||
kse_critical_t crit;
|
||||
int i;
|
||||
|
||||
|
||||
/*
|
||||
* Disable upcalls and clear the threaded flag.
|
||||
* 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();
|
||||
__isthreaded = 0;
|
||||
active_threads = 1;
|
||||
_thr_signal_deinit();
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
curthread->joiner = NULL; /* no joining threads yet */
|
||||
curthread->refcount = 0;
|
||||
sigemptyset(&curthread->sigpend); /* clear pending signals */
|
||||
SIGEMPTYSET(curthread->sigpend); /* clear pending signals */
|
||||
if (curthread->specific != NULL) {
|
||||
free(curthread->specific);
|
||||
curthread->specific = NULL;
|
||||
@ -307,6 +320,12 @@ _kse_single_thread(struct pthread *curthread)
|
||||
curthread->kseg = NULL;
|
||||
_kse_initial = NULL;
|
||||
_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
|
||||
* and enable upcalls in it.
|
||||
*/
|
||||
_thr_signal_init();
|
||||
_kse_initial->k_flags |= KF_STARTED;
|
||||
if (kse_create(&_kse_initial->k_mbx, 0) != 0) {
|
||||
_kse_initial->k_flags &= ~KF_STARTED;
|
||||
__isthreaded = 0;
|
||||
/* may abort() */
|
||||
DBG_MSG("kse_create failed\n");
|
||||
PANIC("kse_create() failed\n");
|
||||
return (-1);
|
||||
}
|
||||
KSE_SET_MBOX(_kse_initial, _thr_initial);
|
||||
_thr_start_sig_daemon();
|
||||
_thr_setmaxconcurrency();
|
||||
}
|
||||
return (0);
|
||||
@ -536,6 +557,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
|
||||
int ret;
|
||||
volatile int uts_once;
|
||||
volatile int resume_once = 0;
|
||||
ucontext_t uc;
|
||||
|
||||
/* We're in the scheduler, 5 by 5: */
|
||||
curkse = _get_curkse();
|
||||
@ -552,7 +574,7 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
|
||||
* a thread can be interrupted by other signals while
|
||||
* it is running down pending signals.
|
||||
*/
|
||||
sigemptyset(&psf.psf_sigset);
|
||||
psf.psf_valid = 0;
|
||||
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
|
||||
* cleaned up and it can't be done while operating on
|
||||
* it.
|
||||
* o The current thread has signals pending, should
|
||||
* let scheduler install signal trampoline for us.
|
||||
* o There are no runnable threads.
|
||||
* o The next thread to run won't unlock the scheduler
|
||||
* 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) ||
|
||||
(((td = KSE_RUNQ_FIRST(curkse)) == NULL) &&
|
||||
(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);
|
||||
}
|
||||
else {
|
||||
uts_once = 0;
|
||||
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) {
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if ((resume_once == 0) && (!THR_IN_CRITICAL(curthread))) {
|
||||
resume_once = 1;
|
||||
thr_resume_check(curthread, &curthread->tmbx.tm_context, &psf);
|
||||
if ((psf.psf_valid || curthread->check_pending)) {
|
||||
resume_once = 0;
|
||||
THR_GETCONTEXT(&uc);
|
||||
if (resume_once == 0) {
|
||||
resume_once = 1;
|
||||
curthread->check_pending = 0;
|
||||
thr_resume_check(curthread, &uc, &psf);
|
||||
}
|
||||
}
|
||||
|
||||
THR_ACTIVATE_LAST_LOCK(curthread);
|
||||
}
|
||||
|
||||
@ -747,9 +786,6 @@ kse_sched_single(struct kse *curkse)
|
||||
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. */
|
||||
@ -810,12 +846,12 @@ kse_sched_multi(struct kse *curkse)
|
||||
KSE_CLEAR_WAIT(curkse);
|
||||
}
|
||||
|
||||
/* Lock the scheduling lock. */
|
||||
curthread = curkse->k_curthread;
|
||||
if ((curthread == NULL) || (curthread->need_switchout == 0)) {
|
||||
/* This is an upcall; take the scheduler lock. */
|
||||
/*If this is an upcall; take the scheduler lock. */
|
||||
if (curkse->k_switch == 0)
|
||||
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
|
||||
}
|
||||
curkse->k_switch = 0;
|
||||
|
||||
curthread = curkse->k_curthread;
|
||||
|
||||
if (KSE_IS_IDLE(curkse)) {
|
||||
KSE_CLEAR_IDLE(curkse);
|
||||
@ -879,11 +915,6 @@ kse_sched_multi(struct kse *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
|
||||
dump_queues(curkse);
|
||||
#endif
|
||||
@ -899,9 +930,6 @@ kse_sched_multi(struct kse *curkse)
|
||||
kse_wait(curkse, td_wait);
|
||||
kse_check_completed(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: */
|
||||
@ -966,15 +994,19 @@ kse_sched_multi(struct kse *curkse)
|
||||
* signal frame to the thread's context.
|
||||
*/
|
||||
#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 & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))))
|
||||
((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))) &&
|
||||
!THR_IN_CRITICAL(curthread))
|
||||
signalcontext(&curthread->tmbx.tm_context, 0,
|
||||
(__sighandler_t *)thr_resume_wrapper);
|
||||
#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,
|
||||
(__sighandler_t *)thr_resume_wrapper);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Continue the thread at its current frame:
|
||||
@ -999,61 +1031,31 @@ kse_sched_multi(struct kse *curkse)
|
||||
}
|
||||
|
||||
static void
|
||||
kse_check_signals(struct kse *curkse)
|
||||
{
|
||||
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)
|
||||
thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
|
||||
{
|
||||
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);
|
||||
_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
|
||||
thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
|
||||
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
|
||||
if (((curthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
|
||||
@ -1124,7 +1126,7 @@ thr_cleanup(struct kse *curkse, struct pthread *thread)
|
||||
THR_GCLIST_ADD(thread);
|
||||
/* Use thread_list_lock */
|
||||
active_threads--;
|
||||
if (active_threads == 0) {
|
||||
if (active_threads == 1) {
|
||||
KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
|
||||
exit(0);
|
||||
}
|
||||
@ -1203,8 +1205,15 @@ _thr_gc(struct pthread *curthread)
|
||||
KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
|
||||
_kse_critical_leave(crit);
|
||||
}
|
||||
DBG_MSG("Freeing thread %p\n", td);
|
||||
_thr_free(curthread, td);
|
||||
/*
|
||||
* 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);
|
||||
_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 */
|
||||
}
|
||||
@ -1216,7 +1225,6 @@ _thr_gc(struct pthread *curthread)
|
||||
int
|
||||
_thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
|
||||
{
|
||||
struct kse *curkse;
|
||||
kse_critical_t crit;
|
||||
int ret;
|
||||
|
||||
@ -1250,15 +1258,11 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
|
||||
/*
|
||||
* This thread needs a new KSE and KSEG.
|
||||
*/
|
||||
crit = _kse_critical_enter();
|
||||
curkse = _get_curkse();
|
||||
_ksd_setprivate(&newthread->kse->k_ksd);
|
||||
newthread->kse->k_flags |= KF_INITIALIZED|KF_STARTED;
|
||||
newthread->kse->k_flags &= ~KF_INITIALIZED;
|
||||
newthread->kse->k_flags |= KF_STARTED;
|
||||
ret = kse_create(&newthread->kse->k_mbx, 1);
|
||||
if (ret != 0)
|
||||
ret = errno;
|
||||
_ksd_setprivate(&curkse->k_ksd);
|
||||
_kse_critical_leave(crit);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
@ -1266,6 +1270,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
|
||||
* assigned threads. If the new thread is runnable, also
|
||||
* add it to the KSE's run queue.
|
||||
*/
|
||||
crit = _kse_critical_enter();
|
||||
KSE_SCHED_LOCK(curthread->kse, newthread->kseg);
|
||||
KSEG_THRQ_ADD(newthread->kseg, newthread);
|
||||
if (newthread->state == PS_RUNNING)
|
||||
@ -1288,6 +1293,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
|
||||
kse_wakeup_one(newthread);
|
||||
}
|
||||
KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg);
|
||||
_kse_critical_leave(crit);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret != 0)
|
||||
@ -1328,6 +1334,7 @@ kse_check_completed(struct kse *kse)
|
||||
{
|
||||
struct pthread *thread;
|
||||
struct kse_thr_mailbox *completed;
|
||||
int sig;
|
||||
|
||||
if ((completed = 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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1446,6 +1460,8 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
|
||||
{
|
||||
int level;
|
||||
int i;
|
||||
int restart;
|
||||
siginfo_t siginfo;
|
||||
|
||||
/*
|
||||
* Place the currently running thread into the
|
||||
@ -1459,15 +1475,25 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
|
||||
thread->need_switchout = 0;
|
||||
/* This thread must have blocked in the kernel. */
|
||||
/* 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) &&
|
||||
(thread->attr.sched_policy != SCHED_FIFO))
|
||||
thread->slice_usec += (thread->tmbx.tm_uticks
|
||||
+ 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 {
|
||||
switch (thread->state) {
|
||||
@ -1507,10 +1533,12 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
|
||||
THR_SET_STATE(thread, PS_RUNNING);
|
||||
break;
|
||||
|
||||
case PS_SIGWAIT:
|
||||
KSE_WAITQ_INSERT(kse, thread);
|
||||
break;
|
||||
case PS_JOIN:
|
||||
case PS_MUTEX_WAIT:
|
||||
case PS_SIGSUSPEND:
|
||||
case PS_SIGWAIT:
|
||||
case PS_SUSPENDED:
|
||||
case PS_DEADLOCK:
|
||||
default:
|
||||
@ -1564,11 +1592,18 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
|
||||
if (thread->check_pending != 0) {
|
||||
/* Install pending signals into the frame. */
|
||||
thread->check_pending = 0;
|
||||
for (i = 0; i < _SIG_MAXSIG; i++) {
|
||||
if (sigismember(&thread->sigpend, i) &&
|
||||
!sigismember(&thread->tmbx.tm_context.uc_sigmask, i))
|
||||
KSE_LOCK_ACQUIRE(kse, &_thread_signal_lock);
|
||||
for (i = 1; i <= _SIG_MAXSIG; i++) {
|
||||
if (SIGISMEMBER(thread->sigmask, i))
|
||||
continue;
|
||||
if (SIGISMEMBER(thread->sigpend, 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]);
|
||||
}
|
||||
free(kse);
|
||||
if (curthread != NULL) {
|
||||
KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
|
||||
_kse_critical_leave(crit);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
kse->k_flags = 0;
|
||||
@ -2044,7 +2083,7 @@ kse_reinit(struct kse *kse)
|
||||
kse->k_kseg = 0;
|
||||
kse->k_schedq = 0;
|
||||
kse->k_locklevel = 0;
|
||||
sigemptyset(&kse->k_sigmask);
|
||||
SIGEMPTYSET(kse->k_sigmask);
|
||||
bzero(&kse->k_sigq, sizeof(kse->k_sigq));
|
||||
kse->k_check_sigq = 0;
|
||||
kse->k_flags = 0;
|
||||
@ -2053,6 +2092,7 @@ kse_reinit(struct kse *kse)
|
||||
kse->k_error = 0;
|
||||
kse->k_cpu = 0;
|
||||
kse->k_done = 0;
|
||||
kse->k_switch = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -2171,10 +2211,12 @@ thr_link(struct pthread *thread)
|
||||
{
|
||||
kse_critical_t crit;
|
||||
struct kse *curkse;
|
||||
struct pthread *curthread;
|
||||
|
||||
crit = _kse_critical_enter();
|
||||
curkse = _get_curkse();
|
||||
|
||||
curthread = _get_curthread();
|
||||
thread->sigmask = curthread->sigmask;
|
||||
KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
|
||||
/*
|
||||
* Initialize the unique id (which GDB uses to track
|
||||
|
@ -45,7 +45,7 @@ _pthread_kill(pthread_t pthread, int sig)
|
||||
int ret;
|
||||
|
||||
/* Check for invalid signal numbers: */
|
||||
if (sig < 0 || sig >= NSIG)
|
||||
if (sig < 0 || sig > _SIG_MAXSIG)
|
||||
/* Invalid signal: */
|
||||
ret = EINVAL;
|
||||
/*
|
||||
|
@ -171,7 +171,7 @@ typedef struct kse_thr_mailbox *kse_critical_t;
|
||||
|
||||
struct kse_group;
|
||||
|
||||
#define MAX_KSE_LOCKLEVEL 3
|
||||
#define MAX_KSE_LOCKLEVEL 5
|
||||
struct kse {
|
||||
struct kse_mailbox k_mbx; /* kernel kse mailbox */
|
||||
/* -- location and order specific items for gdb -- */
|
||||
@ -190,7 +190,7 @@ struct kse {
|
||||
struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL];
|
||||
int k_locklevel;
|
||||
sigset_t k_sigmask;
|
||||
struct sigstatus k_sigq[NSIG];
|
||||
struct sigstatus k_sigq[_SIG_MAXSIG];
|
||||
stack_t k_stack;
|
||||
int k_check_sigq;
|
||||
int k_flags;
|
||||
@ -201,6 +201,7 @@ struct kse {
|
||||
int k_error; /* syscall errno in critical */
|
||||
int k_cpu; /* CPU ID when bound */
|
||||
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 {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
const sigset_t *sigwait; /* Waiting on a signal in sigwait */
|
||||
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.
|
||||
*/
|
||||
struct pthread_sigframe {
|
||||
int psf_valid;
|
||||
int psf_flags;
|
||||
int psf_interrupted;
|
||||
int psf_signo;
|
||||
@ -586,7 +588,7 @@ struct pthread_specific_elem {
|
||||
};
|
||||
|
||||
|
||||
#define MAX_THR_LOCKLEVEL 3
|
||||
#define MAX_THR_LOCKLEVEL 5
|
||||
/*
|
||||
* Thread structure.
|
||||
*/
|
||||
@ -640,7 +642,7 @@ struct pthread {
|
||||
* Used for tracking delivery of signal handlers.
|
||||
*/
|
||||
struct pthread_sigframe *curframe;
|
||||
siginfo_t siginfo[NSIG];
|
||||
siginfo_t siginfo[_SIG_MAXSIG];
|
||||
|
||||
/*
|
||||
* 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
|
||||
* signal mask is stored in the thread's context (in mailbox).
|
||||
*/
|
||||
sigset_t oldsigmask;
|
||||
sigset_t sigmask;
|
||||
sigset_t sigpend;
|
||||
int sigmask_seqno;
|
||||
int check_pending;
|
||||
int have_signals;
|
||||
int refcount;
|
||||
|
||||
/* Thread state: */
|
||||
@ -997,14 +998,14 @@ SCLASS struct pthread_cond_attr _pthread_condattr_default
|
||||
SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC);
|
||||
|
||||
/* 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
|
||||
* assure that there is always a dummy signal handler installed while there
|
||||
* 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
|
||||
@ -1014,8 +1015,7 @@ SCLASS struct lock _thread_signal_lock;
|
||||
|
||||
/* Pending signals and mask for this process: */
|
||||
SCLASS sigset_t _thr_proc_sigpending;
|
||||
SCLASS sigset_t _thr_proc_sigmask SCLASS_PRESET({{0, 0, 0, 0}});
|
||||
SCLASS siginfo_t _thr_proc_siginfo[NSIG];
|
||||
SCLASS siginfo_t _thr_proc_siginfo[_SIG_MAXSIG];
|
||||
|
||||
SCLASS pid_t _thr_pid SCLASS_PRESET(0);
|
||||
|
||||
@ -1030,7 +1030,7 @@ SCLASS struct lock _keytable_lock;
|
||||
SCLASS struct lock _thread_list_lock;
|
||||
SCLASS int _thr_guard_default;
|
||||
SCLASS int _thr_page_size;
|
||||
|
||||
SCLASS pthread_t _thr_sig_daemon;
|
||||
SCLASS int _thr_debug_flags SCLASS_PRESET(0);
|
||||
|
||||
/* Undefine the storage class and preset specifiers: */
|
||||
@ -1116,7 +1116,6 @@ void _thr_panic_exit(char *, int, char *);
|
||||
void _thread_cleanupspecific(void);
|
||||
void _thread_dump_info(void);
|
||||
void _thread_printf(int, const char *, ...);
|
||||
void _thr_sched_frame(struct pthread_sigframe *);
|
||||
void _thr_sched_switch(struct pthread *);
|
||||
void _thr_sched_switch_unlocked(struct pthread *);
|
||||
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 *,
|
||||
struct pthread_sigframe *);
|
||||
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_spinlock_init(void);
|
||||
void _thr_enter_cancellation_point(struct pthread *);
|
||||
void _thr_leave_cancellation_point(struct pthread *);
|
||||
int _thr_setconcurrency(int new_level);
|
||||
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
|
||||
@ -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_write(int, const void *, size_t);
|
||||
void __sys_exit(int);
|
||||
int __sys_sigwait(const sigset_t *, int *);
|
||||
int __sys_sigtimedwait(sigset_t *, siginfo_t *, struct timespec *);
|
||||
#endif
|
||||
|
||||
/* #include <poll.h> */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,16 +43,21 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sigaction gact;
|
||||
struct pthread *curthread;
|
||||
kse_critical_t crit;
|
||||
|
||||
/* Check if the signal number is out of range: */
|
||||
if (sig < 1 || sig > NSIG) {
|
||||
if (sig < 1 || sig > _SIG_MAXSIG) {
|
||||
/* Return an invalid argument: */
|
||||
errno = EINVAL;
|
||||
ret = -1;
|
||||
} else {
|
||||
if (_thr_initial == NULL)
|
||||
_libpthread_init(NULL);
|
||||
if (!_kse_isthreaded())
|
||||
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
|
||||
* to be returned:
|
||||
@ -99,6 +104,8 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
|
||||
if (__sys_sigaction(sig, &gact, NULL) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
|
||||
_kse_critical_leave(crit);
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
@ -48,33 +48,35 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
struct pthread *curthread = _get_curthread();
|
||||
int ret;
|
||||
|
||||
if (! _kse_isthreaded())
|
||||
_kse_setthreaded(1);
|
||||
|
||||
THR_SCHED_LOCK(curthread, curthread);
|
||||
ret = 0;
|
||||
if (oset != NULL)
|
||||
/* 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: */
|
||||
if (set != NULL) {
|
||||
THR_SCHED_LOCK(curthread, curthread);
|
||||
|
||||
/* Process according to what to do: */
|
||||
switch (how) {
|
||||
/* Block signals: */
|
||||
case SIG_BLOCK:
|
||||
/* Add signals to the existing mask: */
|
||||
SIGSETOR(curthread->tmbx.tm_context.uc_sigmask, *set);
|
||||
SIGSETOR(curthread->sigmask, *set);
|
||||
break;
|
||||
|
||||
/* Unblock signals: */
|
||||
case SIG_UNBLOCK:
|
||||
/* Clear signals from the existing mask: */
|
||||
SIGSETNAND(curthread->tmbx.tm_context.uc_sigmask, *set);
|
||||
SIGSETNAND(curthread->sigmask, *set);
|
||||
break;
|
||||
|
||||
/* Set the signal process mask: */
|
||||
case SIG_SETMASK:
|
||||
/* Set the new mask: */
|
||||
curthread->tmbx.tm_context.uc_sigmask = *set;
|
||||
curthread->sigmask = *set;
|
||||
break;
|
||||
|
||||
/* Trap invalid actions: */
|
||||
@ -84,13 +86,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
curthread->sigmask =
|
||||
curthread->tmbx.tm_context.uc_sigmask;
|
||||
curthread->sigmask_seqno++;
|
||||
}
|
||||
|
||||
SIG_CANTMASK(curthread->sigmask);
|
||||
THR_SCHED_UNLOCK(curthread, curthread);
|
||||
|
||||
/*
|
||||
@ -98,6 +94,7 @@ _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
*/
|
||||
if (ret == 0)
|
||||
_thr_sig_check_pending(curthread);
|
||||
}
|
||||
} else
|
||||
THR_SCHED_UNLOCK(curthread, curthread);
|
||||
return (ret);
|
||||
}
|
||||
|
@ -54,8 +54,13 @@ _sigpending(sigset_t *set)
|
||||
ret = EINVAL;
|
||||
}
|
||||
else {
|
||||
*set = curthread->sigpend;
|
||||
if (!_kse_isthreaded())
|
||||
return __sys_sigpending(set);
|
||||
|
||||
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);
|
||||
SIGSETOR(*set, _thr_proc_sigpending);
|
||||
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
|
||||
|
@ -46,8 +46,9 @@ _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_sigmask(how, set, oset);
|
||||
if ((ret == 0) && (_kse_isthreaded() == 0))
|
||||
if (_kse_isthreaded() == 0)
|
||||
ret = __sys_sigprocmask(how, set, oset);
|
||||
else
|
||||
ret = pthread_sigmask(how, set, oset);
|
||||
return (ret);
|
||||
}
|
||||
|
@ -44,14 +44,19 @@ _sigsuspend(const sigset_t *set)
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
int ret = -1;
|
||||
sigset_t osigmask;
|
||||
|
||||
if (!_kse_isthreaded())
|
||||
return __sys_sigsuspend(set);
|
||||
|
||||
/* Check if a new signal set was provided by the caller: */
|
||||
if (set != NULL) {
|
||||
THR_LOCK_SWITCH(curthread);
|
||||
|
||||
/* Save current sigmask */
|
||||
memcpy(&osigmask, &curthread->sigmask, sizeof(osigmask));
|
||||
/* Change the caller's mask: */
|
||||
memcpy(&curthread->tmbx.tm_context.uc_sigmask,
|
||||
set, sizeof(sigset_t));
|
||||
memcpy(&curthread->sigmask, set, sizeof(sigset_t));
|
||||
|
||||
THR_SET_STATE(curthread, PS_SIGSUSPEND);
|
||||
|
||||
@ -61,9 +66,15 @@ _sigsuspend(const sigset_t *set)
|
||||
/* Always return an interrupted error: */
|
||||
errno = EINTR;
|
||||
|
||||
THR_SCHED_LOCK(curthread, curthread);
|
||||
/* Restore the signal mask: */
|
||||
memcpy(&curthread->tmbx.tm_context.uc_sigmask,
|
||||
&curthread->sigmask, sizeof(sigset_t));
|
||||
memcpy(&curthread->sigmask, &osigmask, 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 {
|
||||
/* Return an invalid argument error: */
|
||||
errno = EINVAL;
|
||||
|
@ -39,10 +39,13 @@
|
||||
#include <pthread.h>
|
||||
#include "thr_private.h"
|
||||
|
||||
__weak_reference(_sigwait, sigwait);
|
||||
__weak_reference(__sigwait, sigwait);
|
||||
__weak_reference(__sigtimedwait, sigtimedwait);
|
||||
__weak_reference(__sigwaitinfo, sigwaitinfo);
|
||||
|
||||
int
|
||||
_sigwait(const sigset_t *set, int *sig)
|
||||
static int
|
||||
lib_sigtimedwait(const sigset_t *set, siginfo_t *info,
|
||||
const struct timespec * timeout)
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
int ret = 0;
|
||||
@ -50,8 +53,14 @@ _sigwait(const sigset_t *set, int *sig)
|
||||
sigset_t tempset, waitset;
|
||||
struct sigaction act;
|
||||
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.
|
||||
@ -59,7 +68,7 @@ _sigwait(const sigset_t *set, int *sig)
|
||||
act.sa_handler = (void (*) ()) _thr_sig_handler;
|
||||
act.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
/* 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:
|
||||
@ -67,41 +76,14 @@ _sigwait(const sigset_t *set, int *sig)
|
||||
waitset = *set;
|
||||
|
||||
/* These signals can't be waited on. */
|
||||
sigdelset(&waitset, SIGKILL);
|
||||
sigdelset(&waitset, SIGSTOP);
|
||||
SIGDELSET(waitset, SIGKILL);
|
||||
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();
|
||||
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
|
||||
* these signals we must install a dummy signal handler in
|
||||
* order for the kernel to pass them in to us. POSIX says
|
||||
* that the _application_ must explicitly install a dummy
|
||||
@ -110,66 +92,158 @@ _sigwait(const sigset_t *set, int *sig)
|
||||
* mask because a subsequent sigaction could enable an
|
||||
* ignored signal.
|
||||
*/
|
||||
sigemptyset(&tempset);
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&waitset, i) &&
|
||||
SIGEMPTYSET(tempset);
|
||||
for (i = 1; i <= _SIG_MAXSIG; i++) {
|
||||
if (SIGISMEMBER(waitset, i) &&
|
||||
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
|
||||
_thread_dfl_count[i]++;
|
||||
sigaddset(&tempset, i);
|
||||
if (_thread_dfl_count[i] == 1) {
|
||||
_thread_dfl_count[i - 1]++;
|
||||
SIGADDSET(tempset, i);
|
||||
if (_thread_dfl_count[i - 1] == 1) {
|
||||
if (__sys_sigaction(i, &act, NULL) != 0)
|
||||
ret = -1;
|
||||
/* ret = -1 */;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Done accessing _thread_dfl_count for now. */
|
||||
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
|
||||
_kse_critical_leave(crit);
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* Save the wait signal mask. The wait signal
|
||||
* mask is independent of the threads signal mask
|
||||
* and requires separate storage.
|
||||
*/
|
||||
curthread->data.sigwait = &waitset;
|
||||
|
||||
if (ret == 0) {
|
||||
/* Done accessing _thread_dfl_count for now. */
|
||||
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);
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
curthread->timeout = 0;
|
||||
_thr_set_timeout(timeout);
|
||||
/* 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_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
|
||||
* 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.
|
||||
*/
|
||||
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Relock the array of SIG_DFL wait counts.
|
||||
*/
|
||||
crit = _kse_critical_enter();
|
||||
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
|
||||
|
||||
/* Restore the sigactions: */
|
||||
act.sa_handler = SIG_DFL;
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&tempset, i)) {
|
||||
_thread_dfl_count[i]--;
|
||||
for (i = 1; i <= _SIG_MAXSIG; i++) {
|
||||
if (SIGISMEMBER(tempset, i)) {
|
||||
_thread_dfl_count[i - 1]--;
|
||||
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)
|
||||
ret = -1;
|
||||
/* ret = -1 */ ;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Done accessing _thread_dfl_count. */
|
||||
KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
|
||||
_kse_critical_leave(crit);
|
||||
_thr_leave_cancellation_point(curthread);
|
||||
|
||||
/* Return the completion status: */
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user