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 edb09b0c7f
commit 7b25bda563
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(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);

View File

@ -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]);

View File

@ -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

View File

@ -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

View File

@ -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;
/*

View File

@ -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

View File

@ -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: */

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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]);

View File

@ -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

View File

@ -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

View File

@ -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;
/*

View File

@ -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

View File

@ -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: */

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}