Date: Sat, 20 Nov 2004 03:34:38 GMT From: David Xu <davidxu@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 65501 for review Message-ID: <200411200334.iAK3YciD004023@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=65501 Change 65501 by davidxu@davidxu_alona on 2004/11/20 03:34:36 simplify signal code. Affected files ... .. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_sig.c#2 edit Differences ... ==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_sig.c#2 (text+ko) ==== @@ -1,5 +1,6 @@ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,56 +44,12 @@ #include "thr_private.h" /* Prototypes: */ -static void build_siginfo(siginfo_t *info, int signo); -#ifndef SYSTEM_SCOPE_ONLY -static struct pthread *thr_sig_find(struct kse *curkse, int sig, - siginfo_t *info); -static void handle_special_signals(struct kse *curkse, int sig); -#endif -static void thr_sigframe_add(struct pthread *thread); -static void thr_sigframe_restore(struct pthread *thread, - struct pthread_sigframe *psf); -static void thr_sigframe_save(struct pthread *thread, - struct pthread_sigframe *psf); +static inline void build_siginfo(siginfo_t *info, int signo); +static inline void thr_sigframe_restore(struct pthread *thread, + struct pthread_sigframe *psf); +static inline void thr_sigframe_save(struct pthread *thread, + struct pthread_sigframe *psf); -#define SA_KILL 0x01 /* terminates process by default */ -#define SA_STOP 0x02 -#define SA_CONT 0x04 - -static int sigproptbl[NSIG] = { - SA_KILL, /* SIGHUP */ - SA_KILL, /* SIGINT */ - SA_KILL, /* SIGQUIT */ - SA_KILL, /* SIGILL */ - SA_KILL, /* SIGTRAP */ - SA_KILL, /* SIGABRT */ - SA_KILL, /* SIGEMT */ - SA_KILL, /* SIGFPE */ - SA_KILL, /* SIGKILL */ - SA_KILL, /* SIGBUS */ - SA_KILL, /* SIGSEGV */ - SA_KILL, /* SIGSYS */ - SA_KILL, /* SIGPIPE */ - SA_KILL, /* SIGALRM */ - SA_KILL, /* SIGTERM */ - 0, /* SIGURG */ - SA_STOP, /* SIGSTOP */ - SA_STOP, /* SIGTSTP */ - SA_CONT, /* SIGCONT */ - 0, /* SIGCHLD */ - SA_STOP, /* SIGTTIN */ - SA_STOP, /* SIGTTOU */ - 0, /* SIGIO */ - SA_KILL, /* SIGXCPU */ - SA_KILL, /* SIGXFSZ */ - SA_KILL, /* SIGVTALRM */ - SA_KILL, /* SIGPROF */ - 0, /* SIGWINCH */ - 0, /* SIGINFO */ - SA_KILL, /* SIGUSR1 */ - SA_KILL /* SIGUSR2 */ -}; - /* #define DEBUG_SIGNAL */ #ifdef DEBUG_SIGNAL #define DBG_MSG stdout_debug @@ -100,263 +57,69 @@ #define DBG_MSG(x...) #endif -/* - * Signal setup and delivery. - * - * 1) Delivering signals to threads in the same KSE. - * These signals are sent by upcall events and are set in the - * km_sigscaught field of the KSE mailbox. Since these signals - * are received while operating on the KSE stack, they can be - * delivered either by using signalcontext() to add a stack frame - * to the target thread's stack, or by adding them in the thread's - * pending set and having the thread run them down after it - * 2) Delivering signals to threads in other KSEs/KSEGs. - * 3) Delivering signals to threads in critical regions. - * 4) Delivering signals to threads after they change their signal masks. - * - * Methods of delivering signals. - * - * 1) Add a signal frame to the thread's saved context. - * 2) Add the signal to the thread structure, mark the thread as - * having signals to handle, and let the thread run them down - * after it resumes from the KSE scheduler. - * - * Problem with 1). You can't do this to a running thread or a - * thread in a critical region. - * - * Problem with 2). You can't do this to a thread that doesn't - * yield in some way (explicitly enters the scheduler). A thread - * blocked in the kernel or a CPU hungry thread will not see the - * signal without entering the scheduler. - * - * The solution is to use both 1) and 2) to deliver signals: - * - * o Thread in critical region - use 2). When the thread - * leaves the critical region it will check to see if it - * has pending signals and run them down. - * - * o Thread enters scheduler explicitly - use 2). The thread - * can check for pending signals after it returns from the - * the scheduler. - * - * o Thread is running and not current thread - use 2). When the - * thread hits a condition specified by one of the other bullets, - * the signal will be delivered. - * - * o Thread is running and is current thread (e.g., the thread - * has just changed its signal mask and now sees that it has - * pending signals) - just run down the pending signals. - * - * o Thread is swapped out due to quantum expiration - use 1) - * - * o Thread is blocked in kernel - kse_thr_wakeup() and then - * use 1) - */ - -/* - * Rules for selecting threads for signals received: - * - * 1) If the signal is a sychronous signal, it is delivered to - * the generating (current thread). If the thread has the - * signal masked, it is added to the threads pending signal - * set until the thread unmasks it. - * - * 2) A thread in sigwait() where the signal is in the thread's - * waitset. - * - * 3) A thread in sigsuspend() where the signal is not in the - * thread's suspended signal mask. - * - * 4) Any thread (first found/easiest to deliver) that has the - * signal unmasked. - */ - -#ifndef SYSTEM_SCOPE_ONLY - -static void * -sig_daemon(void *arg /* Unused */) -{ - int i; - kse_critical_t crit; - struct timespec ts; - sigset_t set; - struct kse *curkse; - struct pthread *curthread = _get_curthread(); - - DBG_MSG("signal daemon started(%p)\n", curthread); - - curthread->name = strdup("signal thread"); - crit = _kse_critical_enter(); - curkse = _get_curkse(); - - /* - * Daemon thread is a bound thread and we must be created with - * all signals masked - */ -#if 0 - SIGFILLSET(set); - __sys_sigprocmask(SIG_SETMASK, &set, NULL); -#endif - __sys_sigpending(&set); - ts.tv_sec = 0; - ts.tv_nsec = 0; - while (1) { - KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); - _thr_proc_sigpending = set; - KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); - for (i = 1; i <= _SIG_MAXSIG; i++) { - if (SIGISMEMBER(set, i) != 0) - _thr_sig_dispatch(curkse, i, - NULL /* no siginfo */); - } - ts.tv_sec = 30; - ts.tv_nsec = 0; - curkse->k_kcb->kcb_kmbx.km_flags = - KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT; - kse_release(&ts); - curkse->k_kcb->kcb_kmbx.km_flags = 0; - set = curkse->k_kcb->kcb_kmbx.km_sigscaught; - } - return (0); -} - - -/* Utility function to create signal daemon thread */ -int -_thr_start_sig_daemon(void) -{ - pthread_attr_t attr; - sigset_t sigset, oldset; - - SIGFILLSET(sigset); - pthread_sigmask(SIG_SETMASK, &sigset, &oldset); - pthread_attr_init(&attr); - pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); - attr->flags |= THR_SIGNAL_THREAD; - /* sigmask will be inherited */ - if (pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL)) - PANIC("can not create signal daemon thread!\n"); - pthread_attr_destroy(&attr); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); - return (0); -} - -/* - * This signal handler only delivers asynchronous signals. - * This must be called with upcalls disabled and without - * holding any locks. - */ -void -_thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info) -{ - struct kse_mailbox *kmbx; - struct pthread *thread; - - DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig); - - /* Some signals need special handling: */ - handle_special_signals(curkse, sig); - - /* Check if the signal requires a dump of thread information: */ - if (sig == SIGINFO) { - /* Dump thread information to file: */ - _thread_dump_info(); - } - - while ((thread = thr_sig_find(curkse, sig, info)) != NULL) { - /* - * Setup the target thread to receive the signal: - */ - DBG_MSG("Got signal %d, selecting thread %p\n", sig, thread); - KSE_SCHED_LOCK(curkse, thread->kseg); - if ((thread->state == PS_DEAD) || - (thread->state == PS_DEADLOCK) || - THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) { - KSE_SCHED_UNLOCK(curkse, thread->kseg); - _thr_ref_delete(NULL, thread); - } else if (SIGISMEMBER(thread->sigmask, sig)) { - KSE_SCHED_UNLOCK(curkse, thread->kseg); - _thr_ref_delete(NULL, thread); - } else { - kmbx = _thr_sig_add(thread, sig, info); - KSE_SCHED_UNLOCK(curkse, thread->kseg); - _thr_ref_delete(NULL, thread); - if (kmbx != NULL) - kse_wakeup(kmbx); - break; - } - } - DBG_MSG("<<< _thr_sig_dispatch\n"); -} - -#endif /* ! SYSTEM_SCOPE_ONLY */ - -static __inline int -sigprop(int sig) -{ - - if (sig > 0 && sig < NSIG) - return (sigproptbl[_SIG_IDX(sig)]); - return (0); -} - typedef void (*ohandler)(int sig, int code, struct sigcontext *scp, char *addr, __sighandler_t *catcher); void _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) { + struct pthread_sigframe psf; __siginfohandler_t *sigfunc; struct pthread *curthread; - struct kse *curkse; struct sigaction act; - int sa_flags, err_save, intr_save, timeout_save; + int sa_flags, err_save; + + err_save = errno; DBG_MSG(">>> _thr_sig_handler(%d)\n", sig); curthread = _get_curthread(); if (curthread == NULL) PANIC("No current thread.\n"); - if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)) - PANIC("Thread is not system scope.\n"); - if (curthread->flags & THR_FLAGS_EXITING) + if (curthread->flags & THR_FLAGS_EXITING) { + errno = err_save; return; - curkse = _get_curkse(); + } + /* * If thread is in critical region or if thread is on * the way of state transition, then latch signal into buffer. */ - if (_kse_in_critical() || THR_IN_CRITICAL(curthread) || - (curthread->state != PS_RUNNING && curthread->curframe == NULL)) { + if (THR_IN_CRITICAL(curthread) || curthread->state != PS_RUNNING || + curthread->lock_switch != 0 || curthread->idle != 0) { DBG_MSG(">>> _thr_sig_handler(%d) in critical\n", sig); curthread->siginfo[sig-1] = *info; curthread->check_pending = 1; - curkse->k_sigseqno++; + curthread->sigseqno++; SIGADDSET(curthread->sigpend, sig); /* - * If the kse is on the way to idle itself, but + * If the thread is on the way to idle itself, but * we have signal ready, we should prevent it * to sleep, kernel will latch the wakeup request, - * so kse_release will return from kernel immediately. + * so thr_suspend will return from kernel immediately. */ - if (KSE_IS_IDLE(curkse)) - kse_wakeup(&curkse->k_kcb->kcb_kmbx); + if (curthread->idle) + thr_wake(curthread->tid); + errno = err_save; return; } - /* It is now safe to invoke signal handler */ - err_save = errno; - timeout_save = curthread->timeout; - intr_save = curthread->interrupted; /* Check if the signal requires a dump of thread information: */ if (sig == SIGINFO) { /* Dump thread information to file: */ _thread_dump_info(); } - _kse_critical_enter(); - /* Get a fresh copy of signal mask */ - __sys_sigprocmask(SIG_BLOCK, NULL, &curthread->sigmask); - KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); + + /* Check the threads previous state: */ + curthread->critical_count++; + if (curthread->sigbackout != NULL) + curthread->sigbackout((void *)curthread); + curthread->critical_count--; + thr_sigframe_save(curthread, &psf); + + THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared."); + + THR_LOCK_ACQUIRE(curthread, &_thread_signal_lock); sigfunc = _thread_sigact[sig - 1].sa_sigaction; sa_flags = _thread_sigact[sig - 1].sa_flags; if (sa_flags & SA_RESETHAND) { @@ -366,8 +129,7 @@ __sys_sigaction(sig, &act, NULL); __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]); } - KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); - _kse_critical_leave(&curthread->tcb->tcb_tmbx); + THR_LOCK_RELEASE(curthread, &_thread_signal_lock); /* Now invoke real handler */ if (((__sighandler_t *)sigfunc != SIG_DFL) && @@ -380,379 +142,18 @@ sig, info->si_code, (struct sigcontext *)ucp, info->si_addr, (__sighandler_t *)sigfunc); } - } else { - if ((__sighandler_t *)sigfunc == SIG_DFL) { - if (sigprop(sig) & SA_KILL) { - if (_kse_isthreaded()) - kse_thr_interrupt(NULL, - KSE_INTR_SIGEXIT, sig); - else - kill(getpid(), sig); - } -#ifdef NOTYET - else if (sigprop(sig) & SA_STOP) - kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, sig); -#endif - } + } else if ((__sighandler_t *)sigfunc == SIG_DFL) { + thr_kill(curthread->tid, sig); } - errno = err_save; - curthread->timeout = timeout_save; - curthread->interrupted = intr_save; - _kse_critical_enter(); - curthread->sigmask = ucp->uc_sigmask; - SIG_CANTMASK(curthread->sigmask); - _kse_critical_leave(&curthread->tcb->tcb_tmbx); - DBG_MSG("<<< _thr_sig_handler(%d)\n", sig); -} -struct sighandle_info { - __siginfohandler_t *sigfunc; - int sa_flags; - int sig; - siginfo_t *info; - ucontext_t *ucp; -}; + thr_sigframe_restore(curthread, &psf); -static void handle_signal(struct pthread *curthread, - struct sighandle_info *shi); -static void handle_signal_altstack(struct pthread *curthread, - struct sighandle_info *shi); + DBG_MSG("<<< _thr_sig_handler(%d)\n", sig); -/* Must be called with signal lock and schedule lock held in order */ -static void -thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info, - ucontext_t *ucp) -{ - __siginfohandler_t *sigfunc; - sigset_t sigmask; - int sa_flags; - int onstack; - struct sigaction act; - struct kse *curkse; - struct sighandle_info shi; - - /* - * Invoke the signal handler without going through the scheduler: - */ - DBG_MSG("Got signal %d, calling handler for current thread %p\n", - sig, curthread); - - if (!_kse_in_critical()) - PANIC("thr_sig_invoke_handler without in critical\n"); - curkse = _get_curkse(); - /* - * Check that a custom handler is installed and if - * the signal is not blocked: - */ - sigfunc = _thread_sigact[sig - 1].sa_sigaction; - sa_flags = _thread_sigact[sig - 1].sa_flags; - sigmask = curthread->sigmask; - SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask); - if (!(sa_flags & (SA_NODEFER | SA_RESETHAND))) - SIGADDSET(curthread->sigmask, sig); - if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) { - act.sa_handler = SIG_DFL; - act.sa_flags = SA_RESTART; - SIGEMPTYSET(act.sa_mask); - __sys_sigaction(sig, &act, NULL); - __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]); - } - KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); - KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); - /* - * We are processing buffered signals, synchronize working - * signal mask into kernel. - */ - if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) - __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); - onstack = _thr_sigonstack(&sigfunc); - ucp->uc_stack = curthread->sigstk; - ucp->uc_stack.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE) - ? SS_DISABLE : ((onstack) ? SS_ONSTACK : 0); - if (curthread->oldsigmask) { - ucp->uc_sigmask = *(curthread->oldsigmask); - curthread->oldsigmask = NULL; - } else - ucp->uc_sigmask = sigmask; - shi.sigfunc = sigfunc; - shi.sig = sig; - shi.sa_flags = sa_flags; - shi.info = info; - shi.ucp = ucp; - if ((curthread->sigstk.ss_flags & SS_DISABLE) == 0) { - /* Deliver signal on alternative stack */ - if (sa_flags & SA_ONSTACK && !onstack) - handle_signal_altstack(curthread, &shi); - else - handle_signal(curthread, &shi); - } else { - handle_signal(curthread, &shi); - } - - _kse_critical_enter(); - /* Don't trust after critical leave/enter */ - curkse = _get_curkse(); - - /* - * Restore the thread's signal mask. - */ - curthread->sigmask = ucp->uc_sigmask; - SIG_CANTMASK(curthread->sigmask); - if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) - __sys_sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL); - KSE_SCHED_LOCK(curkse, curkse->k_kseg); - KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); - - DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread); + errno = err_save; } -static void -handle_signal(struct pthread *curthread, struct sighandle_info *shi) -{ - _kse_critical_leave(&curthread->tcb->tcb_tmbx); - - /* Check if the signal requires a dump of thread information: */ - if (shi->sig == SIGINFO) { - /* Dump thread information to file: */ - _thread_dump_info(); - } - - if (((__sighandler_t *)shi->sigfunc != SIG_DFL) && - ((__sighandler_t *)shi->sigfunc != SIG_IGN)) { - if ((shi->sa_flags & SA_SIGINFO) != 0 || shi->info == NULL) - (*(shi->sigfunc))(shi->sig, shi->info, shi->ucp); - else { - ((ohandler)(*shi->sigfunc))( - shi->sig, shi->info->si_code, - (struct sigcontext *)shi->ucp, - shi->info->si_addr, - (__sighandler_t *)shi->sigfunc); - } - } else { - if ((__sighandler_t *)shi->sigfunc == SIG_DFL) { - if (sigprop(shi->sig) & SA_KILL) { - if (_kse_isthreaded()) - kse_thr_interrupt(NULL, - KSE_INTR_SIGEXIT, shi->sig); - else - kill(getpid(), shi->sig); - } -#ifdef NOTYET - else if (sigprop(shi->sig) & SA_STOP) - kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, - shi->sig); -#endif - } - } -} - -static void -handle_signal_wrapper(struct pthread *curthread, ucontext_t *ret_uc, - struct sighandle_info *shi) -{ - shi->ucp->uc_stack.ss_flags = SS_ONSTACK; - handle_signal(curthread, shi); - if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) - setcontext(ret_uc); - else { - /* Work around for ia64, THR_SETCONTEXT does not work */ - _kse_critical_enter(); - curthread->tcb->tcb_tmbx.tm_context = *ret_uc; - _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1); - /* THR_SETCONTEXT */ - } -} - -/* - * Jump to stack set by sigaltstack before invoking signal handler - */ -static void -handle_signal_altstack(struct pthread *curthread, struct sighandle_info *shi) -{ - volatile int once; - ucontext_t uc1, *uc2; - - THR_ASSERT(_kse_in_critical(), "Not in critical"); - - once = 0; - THR_GETCONTEXT(&uc1); - if (once == 0) { - once = 1; - /* XXX - * We are still in critical region, it is safe to operate thread - * context - */ - uc2 = &curthread->tcb->tcb_tmbx.tm_context; - uc2->uc_stack = curthread->sigstk; - makecontext(uc2, (void (*)(void))handle_signal_wrapper, - 3, curthread, &uc1, shi); - if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) - setcontext(uc2); - else { - _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1); - /* THR_SETCONTEXT(uc2); */ - } - } -} - -int -_thr_getprocsig(int sig, siginfo_t *siginfo) -{ - kse_critical_t crit; - struct kse *curkse; - int ret; - - DBG_MSG(">>> _thr_getprocsig\n"); - - crit = _kse_critical_enter(); - curkse = _get_curkse(); - KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); - ret = _thr_getprocsig_unlocked(sig, siginfo); - KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); - _kse_critical_leave(crit); - - DBG_MSG("<<< _thr_getprocsig\n"); - return (ret); -} - -int -_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo) -{ - sigset_t sigset; - struct timespec ts; - - /* try to retrieve signal from kernel */ - SIGEMPTYSET(sigset); - SIGADDSET(sigset, sig); - ts.tv_sec = 0; - ts.tv_nsec = 0; - SIGDELSET(_thr_proc_sigpending, sig); - if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0) - return (sig); - return (0); -} - -#ifndef SYSTEM_SCOPE_ONLY -/* - * Find a thread that can handle the signal. This must be called - * with upcalls disabled. - */ -struct pthread * -thr_sig_find(struct kse *curkse, int sig, siginfo_t *info) -{ - struct kse_mailbox *kmbx = NULL; - struct pthread *pthread; - struct pthread *suspended_thread, *signaled_thread; - __siginfohandler_t *sigfunc; - siginfo_t si; - - DBG_MSG("Looking for thread to handle signal %d\n", sig); - - /* - * Enter a loop to look for threads that have the signal - * unmasked. POSIX specifies that a thread in a sigwait - * will get the signal over any other threads. Second - * preference will be threads in in a sigsuspend. Third - * preference will be the current thread. If none of the - * above, then the signal is delivered to the first thread - * that is found. Note that if a custom handler is not - * installed, the signal only affects threads in sigwait. - */ - suspended_thread = NULL; - signaled_thread = NULL; - - KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); - TAILQ_FOREACH(pthread, &_thread_list, tle) { - if (pthread == _thr_sig_daemon) - continue; - /* Signal delivering to bound thread is done by kernel */ - if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) - continue; - /* Take the scheduling lock. */ - KSE_SCHED_LOCK(curkse, pthread->kseg); - if ((pthread->state == PS_DEAD) || - (pthread->state == PS_DEADLOCK) || - THR_IS_EXITING(pthread) || - THR_IS_SUSPENDED(pthread)) { - ; /* Skip this thread. */ - } else if (pthread->state == PS_SIGWAIT && - SIGISMEMBER(*(pthread->data.sigwait->waitset), sig)) { - /* - * retrieve signal from kernel, if it is job control - * signal, and sigaction is SIG_DFL, then we will - * be stopped in kernel, we hold lock here, but that - * does not matter, because that's job control, and - * whole process should be stopped. - */ - if (_thr_getprocsig(sig, &si)) { - DBG_MSG("Waking thread %p in sigwait" - " with signal %d\n", pthread, sig); - /* where to put siginfo ? */ - *(pthread->data.sigwait->siginfo) = si; - kmbx = _thr_setrunnable_unlocked(pthread); - } - KSE_SCHED_UNLOCK(curkse, pthread->kseg); - /* - * POSIX doesn't doesn't specify which thread - * will get the signal if there are multiple - * waiters, so we give it to the first thread - * we find. - * - * Do not attempt to deliver this signal - * to other threads and do not add the signal - * to the process pending set. - */ - KSE_LOCK_RELEASE(curkse, &_thread_list_lock); - if (kmbx != NULL) - kse_wakeup(kmbx); - if (suspended_thread != NULL) - _thr_ref_delete(NULL, suspended_thread); - if (signaled_thread != NULL) - _thr_ref_delete(NULL, signaled_thread); - return (NULL); - } else if (!SIGISMEMBER(pthread->sigmask, sig)) { - /* - * If debugger is running, we don't quick exit, - * and give it a chance to check the signal. - */ - if (_libkse_debug == 0) { - sigfunc = _thread_sigact[sig - 1].sa_sigaction; - if ((__sighandler_t *)sigfunc == SIG_DFL) { - if (sigprop(sig) & SA_KILL) { - kse_thr_interrupt(NULL, - KSE_INTR_SIGEXIT, sig); - /* Never reach */ - } - } - } - if (pthread->state == PS_SIGSUSPEND) { - if (suspended_thread == NULL) { - suspended_thread = pthread; - suspended_thread->refcount++; - } - } else if (signaled_thread == NULL) { - signaled_thread = pthread; - signaled_thread->refcount++; - } - } - KSE_SCHED_UNLOCK(curkse, pthread->kseg); - } - KSE_LOCK_RELEASE(curkse, &_thread_list_lock); - - if (suspended_thread != NULL) { - pthread = suspended_thread; - if (signaled_thread) - _thr_ref_delete(NULL, signaled_thread); - } else if (signaled_thread) { - pthread = signaled_thread; - } else { - pthread = NULL; - } - return (pthread); -} -#endif /* ! SYSTEM_SCOPE_ONLY */ - -static void +static inline void build_siginfo(siginfo_t *info, int signo) { bzero(info, sizeof(*info)); @@ -765,120 +166,32 @@ * It should only be called from the context of the thread. */ void -_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp, - struct pthread_sigframe *psf) +_thr_sig_rundown(struct pthread *curthread) { - int interrupted = curthread->interrupted; - int timeout = curthread->timeout; - siginfo_t siginfo; - int i; - kse_critical_t crit; - struct kse *curkse; + int i, err_save; sigset_t sigmask; + err_save = errno; + DBG_MSG(">>> thr_sig_rundown (%p)\n", curthread); - /* Check the threads previous state: */ - if ((psf != NULL) && (psf->psf_valid != 0)) { - /* - * Do a little cleanup handling for those threads in - * queues before calling the signal handler. Signals - * for these threads are temporarily blocked until - * after cleanup handling. - */ - switch (psf->psf_state) { - case PS_COND_WAIT: - _cond_wait_backout(curthread); - psf->psf_state = PS_RUNNING; - break; - - case PS_MUTEX_WAIT: - _mutex_lock_backout(curthread); - psf->psf_state = PS_RUNNING; - break; - - case PS_RUNNING: - break; - - default: - psf->psf_state = PS_RUNNING; - break; - } - /* XXX see comment in thr_sched_switch_unlocked */ - curthread->critical_count--; - } - /* - * Lower the priority before calling the handler in case - * it never returns (longjmps back): - */ - crit = _kse_critical_enter(); - curkse = _get_curkse(); - KSE_SCHED_LOCK(curkse, curkse->k_kseg); - KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); - curthread->active_priority &= ~THR_SIGNAL_PRIORITY; SIGFILLSET(sigmask); - while (1) { - /* - * For bound thread, we mask all signals and get a fresh - * copy of signal mask from kernel - */ - if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) { - __sys_sigprocmask(SIG_SETMASK, &sigmask, - &curthread->sigmask); - } - for (i = 1; i <= _SIG_MAXSIG; i++) { - if (SIGISMEMBER(curthread->sigmask, i)) - continue; - if (SIGISMEMBER(curthread->sigpend, i)) { - SIGDELSET(curthread->sigpend, i); - siginfo = curthread->siginfo[i-1]; - break; - } - if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) - && SIGISMEMBER(_thr_proc_sigpending, i)) { - if (_thr_getprocsig_unlocked(i, &siginfo)) - break; - } - } - if (i <= _SIG_MAXSIG) - thr_sig_invoke_handler(curthread, i, &siginfo, ucp); - else { - if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) { - __sys_sigprocmask(SIG_SETMASK, - &curthread->sigmask, NULL); - } - break; - } - } - - if (psf != NULL && psf->psf_valid != 0) - thr_sigframe_restore(curthread, psf); - curkse = _get_curkse(); - KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); - KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); - _kse_critical_leave(&curthread->tcb->tcb_tmbx); - /* repost masked signal to kernel, it hardly happens in real world */ - if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) && - !SIGISEMPTY(curthread->sigpend)) { /* dirty read */ + /* repost signal to kernel */ + if (!SIGISEMPTY(curthread->sigpend)) { __sys_sigprocmask(SIG_SETMASK, &sigmask, &curthread->sigmask); for (i = 1; i <= _SIG_MAXSIG; ++i) { if (SIGISMEMBER(curthread->sigpend, i)) { SIGDELSET(curthread->sigpend, i); - if (!_kse_isthreaded()) + if (!_thr_isthreaded()) kill(getpid(), i); else - kse_thr_interrupt( - &curthread->tcb->tcb_tmbx, - KSE_INTR_SENDSIG, - i); + thr_kill(curthread->tid, i); } } __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); } - curthread->interrupted = interrupted; - curthread->timeout = timeout; - DBG_MSG("<<< thr_sig_rundown (%p)\n", curthread); + errno = err_save; } /* @@ -893,56 +206,26 @@ void _thr_sig_check_pending(struct pthread *curthread) { - ucontext_t uc; - volatile int once; int errsave; - if (THR_IN_CRITICAL(curthread)) + /* + * If the thread is in critical region, delay processing signals. + * If the thread state is not PS_RUNNING, it might be switching + * into UTS and but a THR_LOCK_RELEASE saw check_pending, and it + * goes here, in the case we delay processing signals, lets UTS + * process complicated things, normally UTS will call _thr_sig_add + * to resume the thread, so we needn't repeat doing it here. + */ + if (THR_IN_CRITICAL(curthread) || curthread->lock_switch) return; errsave = errno; - once = 0; - THR_GETCONTEXT(&uc); - if (once == 0) { - once = 1; - curthread->check_pending = 0; - _thr_sig_rundown(curthread, &uc, NULL); - } + curthread->check_pending = 0; + _thr_sig_rundown(curthread); errno = errsave; } -#ifndef SYSTEM_SCOPE_ONLY /* - * This must be called with upcalls disabled. - */ -static void -handle_special_signals(struct kse *curkse, int sig) -{ - switch (sig) { - /* - * POSIX says that pending SIGCONT signals are - * discarded when one of these signals occurs. - */ - case SIGTSTP: - case SIGTTIN: - case SIGTTOU: - KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); - SIGDELSET(_thr_proc_sigpending, SIGCONT); - KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); - break; - case SIGCONT: - KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); - SIGDELSET(_thr_proc_sigpending, SIGTSTP); - SIGDELSET(_thr_proc_sigpending, SIGTTIN); - SIGDELSET(_thr_proc_sigpending, SIGTTOU); - KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); - default: - break; - } -} -#endif /* ! SYSTEM_SCOPE_ONLY */ - -/* * Perform thread specific actions in response to a signal. * This function is only called if there is a handler installed * for the signal, and if the target thread has the signal @@ -950,80 +233,38 @@ * * This must be called with the thread's scheduling lock held. */ -struct kse_mailbox * +long _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) { - siginfo_t siginfo; - struct kse *curkse; - struct kse_mailbox *kmbx = NULL; struct pthread *curthread = _get_curthread(); - int restart; + long tid = -1; int suppress_handler = 0; - int fromproc = 0; __sighandler_t *sigfunc; DBG_MSG(">>> _thr_sig_add %p (%d)\n", pthread, sig); - curkse = _get_curkse(); - restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART; sigfunc = _thread_sigact[sig - 1].sa_handler; - fromproc = (curthread == _thr_sig_daemon); if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK || pthread->state == PS_STATE_MAX) - return (NULL); /* return false */ + return (-1); /* return false */ - if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) && - (curthread != pthread)) { + if (curthread != pthread) { PANIC("Please use _thr_send_sig for bound thread"); >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200411200334.iAK3YciD004023>