thr_sig.c revision 117366
113546Sjulian/* 235509Sjb * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 313546Sjulian * All rights reserved. 413546Sjulian * 513546Sjulian * Redistribution and use in source and binary forms, with or without 613546Sjulian * modification, are permitted provided that the following conditions 713546Sjulian * are met: 813546Sjulian * 1. Redistributions of source code must retain the above copyright 913546Sjulian * notice, this list of conditions and the following disclaimer. 1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1113546Sjulian * notice, this list of conditions and the following disclaimer in the 1213546Sjulian * documentation and/or other materials provided with the distribution. 1313546Sjulian * 3. All advertising materials mentioning features or use of this software 1413546Sjulian * must display the following acknowledgement: 1513546Sjulian * This product includes software developed by John Birrell. 1613546Sjulian * 4. Neither the name of the author nor the names of any co-contributors 1713546Sjulian * may be used to endorse or promote products derived from this software 1813546Sjulian * without specific prior written permission. 1913546Sjulian * 2013546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 2113546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2213546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2349439Sdeischen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2413546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2513546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2613546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2713546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2813546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2913546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3013546Sjulian * SUCH DAMAGE. 3113546Sjulian * 3250476Speter * $FreeBSD: head/lib/libkse/thread/thr_sig.c 117366 2003-07-09 22:30:55Z davidxu $ 3313546Sjulian */ 3451794Smarcel#include <sys/param.h> 3551794Smarcel#include <sys/types.h> 3651794Smarcel#include <sys/signalvar.h> 3713546Sjulian#include <signal.h> 38113658Sdeischen#include <errno.h> 3917706Sjulian#include <fcntl.h> 4017706Sjulian#include <unistd.h> 41113658Sdeischen#include <string.h> 4213546Sjulian#include <pthread.h> 43103388Smini#include "thr_private.h" 44113658Sdeischen#include "pthread_md.h" 4513546Sjulian 4654138Sdeischen/* Prototypes: */ 47113658Sdeischenstatic void build_siginfo(siginfo_t *info, int signo); 48113658Sdeischenstatic void thr_sig_check_state(struct pthread *pthread, int sig); 49113658Sdeischenstatic struct pthread *thr_sig_find(struct kse *curkse, int sig, 50113658Sdeischen siginfo_t *info); 51113658Sdeischenstatic void handle_special_signals(struct kse *curkse, int sig); 52116977Sdavidxustatic void thr_sigframe_add(struct pthread *thread); 53113658Sdeischenstatic void thr_sigframe_restore(struct pthread *thread, 54113658Sdeischen struct pthread_sigframe *psf); 55113658Sdeischenstatic void thr_sigframe_save(struct pthread *thread, 56113658Sdeischen struct pthread_sigframe *psf); 57111035Smini 58111035Smini/* #define DEBUG_SIGNAL */ 5967097Sdeischen#ifdef DEBUG_SIGNAL 6067097Sdeischen#define DBG_MSG stdout_debug 6167097Sdeischen#else 6267097Sdeischen#define DBG_MSG(x...) 6367097Sdeischen#endif 6456277Sjasone 65111035Smini/* 66113658Sdeischen * Signal setup and delivery. 67113658Sdeischen * 68113658Sdeischen * 1) Delivering signals to threads in the same KSE. 69113658Sdeischen * These signals are sent by upcall events and are set in the 70113658Sdeischen * km_sigscaught field of the KSE mailbox. Since these signals 71113658Sdeischen * are received while operating on the KSE stack, they can be 72113658Sdeischen * delivered either by using signalcontext() to add a stack frame 73113658Sdeischen * to the target thread's stack, or by adding them in the thread's 74113658Sdeischen * pending set and having the thread run them down after it 75113658Sdeischen * 2) Delivering signals to threads in other KSEs/KSEGs. 76113658Sdeischen * 3) Delivering signals to threads in critical regions. 77113658Sdeischen * 4) Delivering signals to threads after they change their signal masks. 78113658Sdeischen * 79113658Sdeischen * Methods of delivering signals. 80113658Sdeischen * 81113658Sdeischen * 1) Add a signal frame to the thread's saved context. 82113658Sdeischen * 2) Add the signal to the thread structure, mark the thread as 83113658Sdeischen * having signals to handle, and let the thread run them down 84113658Sdeischen * after it resumes from the KSE scheduler. 85113658Sdeischen * 86113658Sdeischen * Problem with 1). You can't do this to a running thread or a 87113658Sdeischen * thread in a critical region. 88113658Sdeischen * 89113658Sdeischen * Problem with 2). You can't do this to a thread that doesn't 90113658Sdeischen * yield in some way (explicitly enters the scheduler). A thread 91113658Sdeischen * blocked in the kernel or a CPU hungry thread will not see the 92113658Sdeischen * signal without entering the scheduler. 93113658Sdeischen * 94113658Sdeischen * The solution is to use both 1) and 2) to deliver signals: 95113658Sdeischen * 96113658Sdeischen * o Thread in critical region - use 2). When the thread 97113658Sdeischen * leaves the critical region it will check to see if it 98113658Sdeischen * has pending signals and run them down. 99113658Sdeischen * 100113658Sdeischen * o Thread enters scheduler explicitly - use 2). The thread 101113658Sdeischen * can check for pending signals after it returns from the 102113658Sdeischen * the scheduler. 103113658Sdeischen * 104113658Sdeischen * o Thread is running and not current thread - use 2). When the 105113658Sdeischen * thread hits a condition specified by one of the other bullets, 106113658Sdeischen * the signal will be delivered. 107113658Sdeischen * 108113658Sdeischen * o Thread is running and is current thread (e.g., the thread 109113658Sdeischen * has just changed its signal mask and now sees that it has 110113658Sdeischen * pending signals) - just run down the pending signals. 111113658Sdeischen * 112113658Sdeischen * o Thread is swapped out due to quantum expiration - use 1) 113113658Sdeischen * 114113658Sdeischen * o Thread is blocked in kernel - kse_thr_wakeup() and then 115113658Sdeischen * use 1) 116111035Smini */ 117113658Sdeischen 118113658Sdeischen/* 119113658Sdeischen * Rules for selecting threads for signals received: 120113658Sdeischen * 121113658Sdeischen * 1) If the signal is a sychronous signal, it is delivered to 122113658Sdeischen * the generating (current thread). If the thread has the 123113658Sdeischen * signal masked, it is added to the threads pending signal 124113658Sdeischen * set until the thread unmasks it. 125113658Sdeischen * 126113658Sdeischen * 2) A thread in sigwait() where the signal is in the thread's 127113658Sdeischen * waitset. 128113658Sdeischen * 129113658Sdeischen * 3) A thread in sigsuspend() where the signal is not in the 130113658Sdeischen * thread's suspended signal mask. 131113658Sdeischen * 132113658Sdeischen * 4) Any thread (first found/easiest to deliver) that has the 133113658Sdeischen * signal unmasked. 134113658Sdeischen */ 135113658Sdeischen 136116977Sdavidxustatic void * 137116977Sdavidxusig_daemon(void *arg /* Unused */) 138116977Sdavidxu{ 139116977Sdavidxu int i; 140116977Sdavidxu kse_critical_t crit; 141116977Sdavidxu struct timespec ts; 142116977Sdavidxu sigset_t set; 143116977Sdavidxu struct kse *curkse; 144116977Sdavidxu struct pthread *curthread = _get_curthread(); 145116977Sdavidxu 146117301Sdavidxu DBG_MSG("signal daemon started\n"); 147116977Sdavidxu 148116977Sdavidxu curthread->name = strdup("signal thread"); 149116977Sdavidxu crit = _kse_critical_enter(); 150116977Sdavidxu curkse = _get_curkse(); 151116977Sdavidxu SIGFILLSET(set); 152116977Sdavidxu __sys_sigprocmask(SIG_SETMASK, &set, NULL); 153116977Sdavidxu __sys_sigpending(&set); 154116977Sdavidxu ts.tv_sec = 0; 155116977Sdavidxu ts.tv_nsec = 0; 156116977Sdavidxu while (1) { 157116977Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 158116977Sdavidxu _thr_proc_sigpending = set; 159116977Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 160116977Sdavidxu for (i = 1; i <= _SIG_MAXSIG; i++) { 161116977Sdavidxu if (SIGISMEMBER(set, i) != 0) 162116977Sdavidxu _thr_sig_dispatch(curkse, i, 163116977Sdavidxu NULL /* no siginfo */); 164116977Sdavidxu } 165116977Sdavidxu ts.tv_sec = 30; 166116977Sdavidxu ts.tv_nsec = 0; 167116977Sdavidxu curkse->k_mbx.km_flags = 168116977Sdavidxu KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT; 169116977Sdavidxu kse_release(&ts); 170116977Sdavidxu curkse->k_mbx.km_flags = 0; 171116977Sdavidxu set = curkse->k_mbx.km_sigscaught; 172116977Sdavidxu } 173116977Sdavidxu return (0); 174116977Sdavidxu} 175116977Sdavidxu 176116977Sdavidxu/* Utility function to create signal daemon thread */ 177116977Sdavidxuint 178116977Sdavidxu_thr_start_sig_daemon(void) 179116977Sdavidxu{ 180116977Sdavidxu pthread_attr_t attr; 181116977Sdavidxu sigset_t sigset, oldset; 182116977Sdavidxu 183116977Sdavidxu SIGFILLSET(sigset); 184116977Sdavidxu pthread_sigmask(SIG_SETMASK, &sigset, &oldset); 185116977Sdavidxu pthread_attr_init(&attr); 186116977Sdavidxu pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 187116977Sdavidxu /* sigmask will be inherited */ 188116977Sdavidxu if (pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL)) 189116977Sdavidxu PANIC("can not create signal daemon thread!\n"); 190116977Sdavidxu pthread_attr_destroy(&attr); 191116977Sdavidxu pthread_sigmask(SIG_SETMASK, &oldset, NULL); 192116977Sdavidxu return (0); 193116977Sdavidxu} 194116977Sdavidxu 195113658Sdeischen/* 196113658Sdeischen * This signal handler only delivers asynchronous signals. 197113658Sdeischen * This must be called with upcalls disabled and without 198113658Sdeischen * holding any locks. 199113658Sdeischen */ 20013546Sjulianvoid 201113658Sdeischen_thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info) 20235509Sjb{ 203113658Sdeischen struct pthread *thread; 20435509Sjb 205113658Sdeischen DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig); 20635509Sjb 207113658Sdeischen /* Some signals need special handling: */ 208113658Sdeischen handle_special_signals(curkse, sig); 209115278Sdeischen while ((thread = thr_sig_find(curkse, sig, info)) != NULL) { 210113658Sdeischen /* 211113658Sdeischen * Setup the target thread to receive the signal: 212113658Sdeischen */ 213113658Sdeischen DBG_MSG("Got signal %d, selecting thread %p\n", sig, thread); 214113658Sdeischen KSE_SCHED_LOCK(curkse, thread->kseg); 215115278Sdeischen if ((thread->state == PS_DEAD) || 216115278Sdeischen (thread->state == PS_DEADLOCK) || 217115278Sdeischen THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) { 218115278Sdeischen KSE_SCHED_UNLOCK(curkse, thread->kseg); 219115278Sdeischen _thr_ref_delete(NULL, thread); 220117353Sdavidxu } else if ((thread->state == PS_SIGWAIT && 221117353Sdavidxu SIGISMEMBER(thread->oldsigmask, sig)) || 222117353Sdavidxu (thread->state != PS_SIGWAIT && 223117353Sdavidxu SIGISMEMBER(thread->sigmask, sig))) { 224116061Sdeischen KSE_SCHED_UNLOCK(curkse, thread->kseg); 225116061Sdeischen _thr_ref_delete(NULL, thread); 226116977Sdavidxu } else { 227115278Sdeischen _thr_sig_add(thread, sig, info); 228115278Sdeischen KSE_SCHED_UNLOCK(curkse, thread->kseg); 229115278Sdeischen _thr_ref_delete(NULL, thread); 230115278Sdeischen break; 231115278Sdeischen } 232113658Sdeischen } 233116977Sdavidxu DBG_MSG("<<< _thr_sig_dispatch\n"); 234113658Sdeischen} 235113658Sdeischen 236113658Sdeischenvoid 237113658Sdeischen_thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) 238113658Sdeischen{ 239115381Sdeischen __siginfohandler_t *sigfunc; 240113658Sdeischen struct kse *curkse; 241113658Sdeischen 242113658Sdeischen curkse = _get_curkse(); 243113658Sdeischen if ((curkse == NULL) || ((curkse->k_flags & KF_STARTED) == 0)) { 244113658Sdeischen /* Upcalls are not yet started; just call the handler. */ 245113658Sdeischen sigfunc = _thread_sigact[sig - 1].sa_sigaction; 246113658Sdeischen if (((__sighandler_t *)sigfunc != SIG_DFL) && 247115381Sdeischen ((__sighandler_t *)sigfunc != SIG_IGN) && 248115381Sdeischen (sigfunc != (__siginfohandler_t *)_thr_sig_handler)) { 249113658Sdeischen if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) 250113658Sdeischen != 0) || (info == NULL)) 251113658Sdeischen (*(sigfunc))(sig, info, ucp); 252113658Sdeischen else 253116773Smarcel (*(sigfunc))(sig, 254116773Smarcel (siginfo_t*)(intptr_t)info->si_code, ucp); 255113658Sdeischen } 256113658Sdeischen } 257113658Sdeischen else { 258113658Sdeischen /* Nothing. */ 259113658Sdeischen DBG_MSG("Got signal %d\n", sig); 260116977Sdavidxu /* XXX Bound thread will fall into this... */ 261113658Sdeischen } 262113658Sdeischen} 263113658Sdeischen 264116977Sdavidxu/* Must be called with signal lock and schedule lock held in order */ 265113658Sdeischenstatic void 266113658Sdeischenthr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info, 267113658Sdeischen ucontext_t *ucp) 268113658Sdeischen{ 269113658Sdeischen void (*sigfunc)(int, siginfo_t *, void *); 270116977Sdavidxu sigset_t sigmask; 271116977Sdavidxu int sa_flags; 272116977Sdavidxu struct sigaction act; 273116977Sdavidxu struct kse *curkse; 274113658Sdeischen 275116977Sdavidxu /* 276116977Sdavidxu * Invoke the signal handler without going through the scheduler: 277113658Sdeischen */ 278113658Sdeischen DBG_MSG("Got signal %d, calling handler for current thread %p\n", 279113658Sdeischen sig, curthread); 280113658Sdeischen 281116977Sdavidxu if (!_kse_in_critical()) 282116977Sdavidxu PANIC("thr_sig_invoke_handler without in critical\n"); 283116977Sdavidxu curkse = _get_curkse(); 28448046Sjb /* 285113658Sdeischen * Check that a custom handler is installed and if 286113658Sdeischen * the signal is not blocked: 287113658Sdeischen */ 288113658Sdeischen sigfunc = _thread_sigact[sig - 1].sa_sigaction; 289116977Sdavidxu sa_flags = _thread_sigact[sig - 1].sa_flags & SA_SIGINFO; 290116977Sdavidxu sigmask = curthread->sigmask; 291116977Sdavidxu SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask); 292116977Sdavidxu if (!(sa_flags & (SA_NODEFER | SA_RESETHAND))) 293116977Sdavidxu SIGADDSET(curthread->sigmask, sig); 294116977Sdavidxu if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) { 295116977Sdavidxu if (_thread_dfl_count[sig - 1] == 0) { 296116977Sdavidxu act.sa_handler = SIG_DFL; 297116977Sdavidxu act.sa_flags = SA_RESTART; 298116977Sdavidxu SIGEMPTYSET(act.sa_mask); 299116977Sdavidxu __sys_sigaction(sig, &act, NULL); 300116977Sdavidxu __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]); 301116977Sdavidxu } 302116977Sdavidxu } 303116977Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 304116977Sdavidxu KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); 305116977Sdavidxu _kse_critical_leave(&curthread->tmbx); 306116977Sdavidxu ucp->uc_sigmask = sigmask; 307116977Sdavidxu 308113658Sdeischen if (((__sighandler_t *)sigfunc != SIG_DFL) && 309113658Sdeischen ((__sighandler_t *)sigfunc != SIG_IGN)) { 310116977Sdavidxu if ((sa_flags & SA_SIGINFO) != 0 || info == NULL) 311113658Sdeischen (*(sigfunc))(sig, info, ucp); 312113658Sdeischen else 313116773Smarcel (*(sigfunc))(sig, (siginfo_t*)(intptr_t)info->si_code, 314116773Smarcel ucp); 315116977Sdavidxu } else { 316116977Sdavidxu /* XXX 317116977Sdavidxu * TODO: exit process if signal would kill it. 318116977Sdavidxu */ 319116977Sdavidxu#ifdef NOTYET 320116977Sdavidxu if (sigprop(sig) & SA_KILL) 321116977Sdavidxu kse_sigexit(sig); 322116977Sdavidxu#endif 32367097Sdeischen } 324116977Sdavidxu _kse_critical_enter(); 325116977Sdavidxu /* Don't trust after critical leave/enter */ 326116977Sdavidxu curkse = _get_curkse(); 327116977Sdavidxu KSE_SCHED_LOCK(curkse, curkse->k_kseg); 328116977Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 329113658Sdeischen /* 330113658Sdeischen * Restore the thread's signal mask. 331113658Sdeischen */ 332116977Sdavidxu curthread->sigmask = ucp->uc_sigmask; 333116977Sdavidxu 334116977Sdavidxu DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread); 33548046Sjb} 33648046Sjb 337116977Sdavidxuint 338116977Sdavidxu_thr_getprocsig(int sig, siginfo_t *siginfo) 339116977Sdavidxu{ 340116977Sdavidxu kse_critical_t crit; 341116977Sdavidxu struct kse *curkse; 342116977Sdavidxu int ret; 343116977Sdavidxu 344116977Sdavidxu DBG_MSG(">>> _thr_getprocsig\n"); 345116977Sdavidxu 346116977Sdavidxu crit = _kse_critical_enter(); 347116977Sdavidxu curkse = _get_curkse(); 348116977Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 349116977Sdavidxu ret = _thr_getprocsig_unlocked(sig, siginfo); 350116977Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 351116977Sdavidxu _kse_critical_leave(crit); 352116977Sdavidxu 353116977Sdavidxu DBG_MSG("<<< _thr_getprocsig\n"); 354116977Sdavidxu return (ret); 355116977Sdavidxu} 356116977Sdavidxu 357116977Sdavidxuint 358116977Sdavidxu_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo) 359116977Sdavidxu{ 360116977Sdavidxu sigset_t sigset; 361116977Sdavidxu struct timespec ts; 362116977Sdavidxu 363116977Sdavidxu /* try to retrieve signal from kernel */ 364116977Sdavidxu SIGEMPTYSET(sigset); 365116977Sdavidxu SIGADDSET(sigset, sig); 366116977Sdavidxu ts.tv_sec = 0; 367116977Sdavidxu ts.tv_nsec = 0; 368116977Sdavidxu if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0) { 369116977Sdavidxu SIGDELSET(_thr_proc_sigpending, sig); 370116977Sdavidxu return (sig); 371116977Sdavidxu } 372116977Sdavidxu return (0); 373116977Sdavidxu} 374116977Sdavidxu 37567097Sdeischen/* 376113658Sdeischen * Find a thread that can handle the signal. This must be called 377113658Sdeischen * with upcalls disabled. 37867097Sdeischen */ 379113658Sdeischenstruct pthread * 380113658Sdeischenthr_sig_find(struct kse *curkse, int sig, siginfo_t *info) 38148046Sjb{ 382114180Sdeischen struct pthread *pthread; 38390431Sdeischen struct pthread *suspended_thread, *signaled_thread; 384116977Sdavidxu siginfo_t si; 38548046Sjb 38667097Sdeischen DBG_MSG("Looking for thread to handle signal %d\n", sig); 387113658Sdeischen 38848046Sjb /* Check if the signal requires a dump of thread information: */ 38968516Sdeischen if (sig == SIGINFO) { 39048046Sjb /* Dump thread information to file: */ 39148046Sjb _thread_dump_info(); 39268516Sdeischen } 393111035Smini /* 394111035Smini * Enter a loop to look for threads that have the signal 395111035Smini * unmasked. POSIX specifies that a thread in a sigwait 396111035Smini * will get the signal over any other threads. Second 397111035Smini * preference will be threads in in a sigsuspend. Third 398111035Smini * preference will be the current thread. If none of the 399111035Smini * above, then the signal is delivered to the first thread 400111035Smini * that is found. Note that if a custom handler is not 401111035Smini * installed, the signal only affects threads in sigwait. 402111035Smini */ 403111035Smini suspended_thread = NULL; 404113658Sdeischen signaled_thread = NULL; 405111035Smini 406113658Sdeischen KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); 407114180Sdeischen TAILQ_FOREACH(pthread, &_thread_list, tle) { 408116977Sdavidxu if (pthread == _thr_sig_daemon) 409116977Sdavidxu continue; 410116977Sdavidxu#ifdef NOTYET 411116977Sdavidxu /* Signal delivering to bound thread is done by kernel */ 412116977Sdavidxu if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 413116977Sdavidxu continue; 414116977Sdavidxu#endif 415116977Sdavidxu 416114254Sdeischen /* Take the scheduling lock. */ 417114254Sdeischen KSE_SCHED_LOCK(curkse, pthread->kseg); 418116977Sdavidxu if ((pthread->state == PS_DEAD) || 419116977Sdavidxu (pthread->state == PS_DEADLOCK) || 420116977Sdavidxu THR_IS_EXITING(pthread) || 421117353Sdavidxu THR_IS_SUSPENDED(pthread)) { 422116977Sdavidxu ; /* Skip this thread. */ 423117353Sdavidxu } else if (pthread->state == PS_SIGWAIT && 424117353Sdavidxu !SIGISMEMBER(pthread->sigmask, sig)) { 42548046Sjb /* 426116977Sdavidxu * retrieve signal from kernel, if it is job control 427116977Sdavidxu * signal, and sigaction is SIG_DFL, then we will 428116977Sdavidxu * be stopped in kernel, we hold lock here, but that 429116977Sdavidxu * does not matter, because that's job control, and 430116977Sdavidxu * whole process should be stopped. 43148046Sjb */ 432116977Sdavidxu if (_thr_getprocsig(sig, &si)) { 433116977Sdavidxu DBG_MSG("Waking thread %p in sigwait" 434116977Sdavidxu " with signal %d\n", pthread, sig); 435116977Sdavidxu /* where to put siginfo ? */ 436116977Sdavidxu *(pthread->data.sigwaitinfo) = si; 437116977Sdavidxu pthread->sigmask = pthread->oldsigmask; 438116977Sdavidxu _thr_setrunnable_unlocked(pthread); 439116977Sdavidxu } 440113658Sdeischen KSE_SCHED_UNLOCK(curkse, pthread->kseg); 441111035Smini /* 442111035Smini * POSIX doesn't doesn't specify which thread 443111035Smini * will get the signal if there are multiple 444111035Smini * waiters, so we give it to the first thread 445111035Smini * we find. 446111035Smini * 447111035Smini * Do not attempt to deliver this signal 448111035Smini * to other threads and do not add the signal 449111035Smini * to the process pending set. 450111035Smini */ 451113658Sdeischen KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 452111035Smini return (NULL); 453117353Sdavidxu } else if (!SIGISMEMBER(pthread->sigmask, sig) || 454117353Sdavidxu (!SIGISMEMBER(pthread->oldsigmask, sig) && 455117353Sdavidxu pthread->state == PS_SIGWAIT)) { 456111035Smini if (pthread->state == PS_SIGSUSPEND) { 457115278Sdeischen if (suspended_thread == NULL) { 458111035Smini suspended_thread = pthread; 459115278Sdeischen suspended_thread->refcount++; 460115278Sdeischen } 461115278Sdeischen } else if (signaled_thread == NULL) { 462111035Smini signaled_thread = pthread; 463115278Sdeischen signaled_thread->refcount++; 464116977Sdavidxu } 465111035Smini } 466114254Sdeischen KSE_SCHED_UNLOCK(curkse, pthread->kseg); 467111035Smini } 468113658Sdeischen KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 46939805Sjb 470116977Sdavidxu if (suspended_thread != NULL) { 471116977Sdavidxu pthread = suspended_thread; 472116977Sdavidxu if (signaled_thread) 473116977Sdavidxu _thr_ref_delete(NULL, signaled_thread); 474116977Sdavidxu } else if (signaled_thread) { 475116977Sdavidxu pthread = signaled_thread; 476113658Sdeischen } else { 477116977Sdavidxu pthread = NULL; 478111035Smini } 479116977Sdavidxu return (pthread); 48035509Sjb} 48135509Sjb 482113658Sdeischenstatic void 483113658Sdeischenbuild_siginfo(siginfo_t *info, int signo) 484113658Sdeischen{ 485113658Sdeischen bzero(info, sizeof(*info)); 486113658Sdeischen info->si_signo = signo; 487113658Sdeischen info->si_pid = _thr_pid; 488113658Sdeischen} 489113658Sdeischen 490113658Sdeischen/* 491113658Sdeischen * This is called by a thread when it has pending signals to deliver. 492113658Sdeischen * It should only be called from the context of the thread. 493113658Sdeischen */ 49467097Sdeischenvoid 495113658Sdeischen_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp, 496113658Sdeischen struct pthread_sigframe *psf) 49756277Sjasone{ 498117353Sdavidxu int interrupted = curthread->interrupted; 499117353Sdavidxu int timeout = curthread->timeout; 500116977Sdavidxu siginfo_t siginfo; 501113658Sdeischen int i; 502116977Sdavidxu kse_critical_t crit; 503116977Sdavidxu struct kse *curkse; 50467097Sdeischen 505116977Sdavidxu DBG_MSG(">>> thr_sig_rundown %p\n", curthread); 506113658Sdeischen /* Check the threads previous state: */ 507116977Sdavidxu if ((psf != NULL) && (psf->psf_valid != 0)) { 508113658Sdeischen /* 509113658Sdeischen * Do a little cleanup handling for those threads in 510113658Sdeischen * queues before calling the signal handler. Signals 511113658Sdeischen * for these threads are temporarily blocked until 512113658Sdeischen * after cleanup handling. 513113658Sdeischen */ 514116977Sdavidxu switch (psf->psf_state) { 515113658Sdeischen case PS_COND_WAIT: 516113658Sdeischen _cond_wait_backout(curthread); 517116977Sdavidxu psf->psf_state = PS_RUNNING; 518113658Sdeischen break; 519113658Sdeischen 520113658Sdeischen case PS_MUTEX_WAIT: 521113658Sdeischen _mutex_lock_backout(curthread); 522116977Sdavidxu psf->psf_state = PS_RUNNING; 523113658Sdeischen break; 524113658Sdeischen 525116977Sdavidxu case PS_RUNNING: 526116977Sdavidxu break; 527116977Sdavidxu 528113658Sdeischen default: 529116977Sdavidxu psf->psf_state = PS_RUNNING; 530113658Sdeischen break; 531113658Sdeischen } 532116977Sdavidxu /* XXX see comment in thr_sched_switch_unlocked */ 533116977Sdavidxu curthread->critical_count--; 534113658Sdeischen } 535116977Sdavidxu 53656277Sjasone /* 537113658Sdeischen * Lower the priority before calling the handler in case 538113658Sdeischen * it never returns (longjmps back): 53956277Sjasone */ 540116977Sdavidxu crit = _kse_critical_enter(); 541116977Sdavidxu curkse = _get_curkse(); 542116977Sdavidxu KSE_SCHED_LOCK(curkse, curkse->k_kseg); 543116977Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 544113658Sdeischen curthread->active_priority &= ~THR_SIGNAL_PRIORITY; 545113658Sdeischen 546116977Sdavidxu while (1) { 547116977Sdavidxu for (i = 1; i <= _SIG_MAXSIG; i++) { 548116977Sdavidxu if (SIGISMEMBER(curthread->sigmask, i)) 549116977Sdavidxu continue; 550116977Sdavidxu if (SIGISMEMBER(curthread->sigpend, i)) { 551116977Sdavidxu SIGDELSET(curthread->sigpend, i); 552117066Sdavidxu siginfo = curthread->siginfo[i-1]; 553116977Sdavidxu break; 554116977Sdavidxu } 555116977Sdavidxu if (SIGISMEMBER(_thr_proc_sigpending, i)) { 556116977Sdavidxu if (_thr_getprocsig_unlocked(i, &siginfo)) 557116977Sdavidxu break; 558116977Sdavidxu } 55967097Sdeischen } 560116977Sdavidxu if (i <= _SIG_MAXSIG) 561116977Sdavidxu thr_sig_invoke_handler(curthread, i, &siginfo, ucp); 562116977Sdavidxu else 563116977Sdavidxu break; 56456277Sjasone } 565113658Sdeischen 566116977Sdavidxu if (psf != NULL && psf->psf_valid != 0) 567116977Sdavidxu thr_sigframe_restore(curthread, psf); 568116977Sdavidxu curkse = _get_curkse(); 569116977Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 570116977Sdavidxu KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); 571116977Sdavidxu _kse_critical_leave(&curthread->tmbx); 572116977Sdavidxu 573117353Sdavidxu curthread->interrupted = interrupted; 574117353Sdavidxu curthread->timeout = timeout; 575117353Sdavidxu 576116977Sdavidxu DBG_MSG("<<< thr_sig_rundown %p\n", curthread); 57767097Sdeischen} 57867097Sdeischen 57967097Sdeischen/* 580113658Sdeischen * This checks pending signals for the current thread. It should be 581113658Sdeischen * called whenever a thread changes its signal mask. Note that this 582113658Sdeischen * is called from a thread (using its stack). 583113658Sdeischen * 584113658Sdeischen * XXX - We might want to just check to see if there are pending 585113658Sdeischen * signals for the thread here, but enter the UTS scheduler 586113658Sdeischen * to actually install the signal handler(s). 58767097Sdeischen */ 58867097Sdeischenvoid 589113658Sdeischen_thr_sig_check_pending(struct pthread *curthread) 59067097Sdeischen{ 591116977Sdavidxu ucontext_t uc; 592116977Sdavidxu volatile int once; 59367097Sdeischen 594116977Sdavidxu if (THR_IN_CRITICAL(curthread)) 595116977Sdavidxu return; 596113658Sdeischen 597116977Sdavidxu once = 0; 598116977Sdavidxu THR_GETCONTEXT(&uc); 599116977Sdavidxu if (once == 0) { 600116977Sdavidxu once = 1; 601113658Sdeischen curthread->check_pending = 0; 602116977Sdavidxu _thr_sig_rundown(curthread, &uc, NULL); 60356277Sjasone } 60456277Sjasone} 60556277Sjasone 606111035Smini/* 607113658Sdeischen * This must be called with upcalls disabled. 608111035Smini */ 60956277Sjasonestatic void 610113658Sdeischenhandle_special_signals(struct kse *curkse, int sig) 61156277Sjasone{ 61267097Sdeischen switch (sig) { 61367097Sdeischen /* 61467097Sdeischen * POSIX says that pending SIGCONT signals are 61567097Sdeischen * discarded when one of these signals occurs. 61667097Sdeischen */ 61767097Sdeischen case SIGTSTP: 61867097Sdeischen case SIGTTIN: 61967097Sdeischen case SIGTTOU: 620113658Sdeischen KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 621116977Sdavidxu SIGDELSET(_thr_proc_sigpending, SIGCONT); 622113658Sdeischen KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 62367097Sdeischen break; 624116977Sdavidxu case SIGCONT: 625116977Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 626116977Sdavidxu SIGDELSET(_thr_proc_sigpending, SIGTSTP); 627116977Sdavidxu SIGDELSET(_thr_proc_sigpending, SIGTTIN); 628116977Sdavidxu SIGDELSET(_thr_proc_sigpending, SIGTTOU); 629116977Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 63067097Sdeischen default: 63167097Sdeischen break; 63256277Sjasone } 63356277Sjasone} 63456277Sjasone 63567097Sdeischen/* 63667097Sdeischen * Perform thread specific actions in response to a signal. 63767097Sdeischen * This function is only called if there is a handler installed 63867097Sdeischen * for the signal, and if the target thread has the signal 63967097Sdeischen * unmasked. 640113658Sdeischen * 641113658Sdeischen * This must be called with the thread's scheduling lock held. 64267097Sdeischen */ 643115080Sdeischenvoid 644115080Sdeischen_thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) 64535509Sjb{ 646113658Sdeischen int restart; 64767097Sdeischen int suppress_handler = 0; 648116977Sdavidxu int fromproc = 0; 649116977Sdavidxu struct pthread *curthread = _get_curthread(); 650116977Sdavidxu struct kse *curkse; 651116977Sdavidxu siginfo_t siginfo; 65267097Sdeischen 653116977Sdavidxu DBG_MSG(">>> _thr_sig_add\n"); 654116977Sdavidxu 655116977Sdavidxu curkse = _get_curkse(); 656116977Sdavidxu restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART; 657116977Sdavidxu fromproc = (curthread == _thr_sig_daemon); 658116977Sdavidxu 659116977Sdavidxu if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK || 660116977Sdavidxu pthread->state == PS_STATE_MAX) 661116977Sdavidxu return; /* return false */ 662116977Sdavidxu 663116977Sdavidxu#ifdef NOTYET 664116977Sdavidxu if ((pthread->attrs.flags & PTHREAD_SCOPE_SYSTEM) != 0) { 665116977Sdavidxu if (!fromproc) 666116977Sdavidxu kse_thr_interrupt(&pthread->tmbx, 0, sig); 667116977Sdavidxu return; 668115080Sdeischen } 669116977Sdavidxu#endif 670116977Sdavidxu 671116977Sdavidxu if (pthread->curframe == NULL || 672117353Sdavidxu (pthread->state != PS_SIGWAIT && 673117353Sdavidxu SIGISMEMBER(pthread->sigmask, sig)) || 674116977Sdavidxu THR_IN_CRITICAL(pthread)) { 675116977Sdavidxu /* thread is running or signal was being masked */ 676116977Sdavidxu if (!fromproc) { 677116977Sdavidxu SIGADDSET(pthread->sigpend, sig); 678116977Sdavidxu if (info == NULL) 679117066Sdavidxu build_siginfo(&pthread->siginfo[sig-1], sig); 680117066Sdavidxu else if (info != &pthread->siginfo[sig-1]) 681117066Sdavidxu memcpy(&pthread->siginfo[sig-1], info, 682116977Sdavidxu sizeof(*info)); 683116977Sdavidxu } else { 684117066Sdavidxu if (!_thr_getprocsig(sig, &pthread->siginfo[sig-1])) 685116977Sdavidxu return; 686116977Sdavidxu SIGADDSET(pthread->sigpend, sig); 687116977Sdavidxu } 688116977Sdavidxu if (!SIGISMEMBER(pthread->sigmask, sig)) { 689116977Sdavidxu pthread->check_pending = 1; 690116977Sdavidxu if (pthread->blocked != 0 && !THR_IN_CRITICAL(pthread)) 691116977Sdavidxu kse_thr_interrupt(&pthread->tmbx, 692116977Sdavidxu restart ? -2 : -1); 693116977Sdavidxu } 694116977Sdavidxu } 695115080Sdeischen else { 696116977Sdavidxu /* if process signal not exists, just return */ 697116977Sdavidxu if (fromproc) { 698116977Sdavidxu if (!_thr_getprocsig(sig, &siginfo)) 699116977Sdavidxu return; 700116977Sdavidxu info = &siginfo; 701116977Sdavidxu } 70267097Sdeischen /* 703115080Sdeischen * Process according to thread state: 70467097Sdeischen */ 705115080Sdeischen switch (pthread->state) { 706115080Sdeischen case PS_DEAD: 707115080Sdeischen case PS_DEADLOCK: 708116977Sdavidxu case PS_STATE_MAX: 709116977Sdavidxu return; /* XXX return false */ 710115080Sdeischen case PS_LOCKWAIT: 711115080Sdeischen case PS_SUSPENDED: 71267097Sdeischen /* 713115080Sdeischen * You can't call a signal handler for threads in these 714115080Sdeischen * states. 71567097Sdeischen */ 716113658Sdeischen suppress_handler = 1; 717115080Sdeischen break; 718115080Sdeischen case PS_RUNNING: 719116977Sdavidxu if ((pthread->flags & THR_FLAGS_IN_RUNQ)) { 720115080Sdeischen THR_RUNQ_REMOVE(pthread); 721116977Sdavidxu pthread->active_priority |= THR_SIGNAL_PRIORITY; 722116977Sdavidxu THR_RUNQ_INSERT_TAIL(pthread); 723116977Sdavidxu } else { 724116977Sdavidxu /* Possible not in RUNQ and has curframe ? */ 725116977Sdavidxu pthread->active_priority |= THR_SIGNAL_PRIORITY; 726116977Sdavidxu } 727116977Sdavidxu suppress_handler = 1; 728115080Sdeischen break; 72939805Sjb /* 730115080Sdeischen * States which cannot be interrupted but still require the 731115080Sdeischen * signal handler to run: 73239805Sjb */ 733115080Sdeischen case PS_COND_WAIT: 734115080Sdeischen case PS_MUTEX_WAIT: 735115080Sdeischen break; 73639805Sjb 737115080Sdeischen case PS_SLEEP_WAIT: 738115080Sdeischen /* 739115080Sdeischen * Unmasked signals always cause sleep to terminate 740115080Sdeischen * early regardless of SA_RESTART: 741115080Sdeischen */ 742115080Sdeischen pthread->interrupted = 1; 743115080Sdeischen break; 744113658Sdeischen 745115080Sdeischen case PS_JOIN: 746116977Sdavidxu break; 747116977Sdavidxu 748115080Sdeischen case PS_SIGSUSPEND: 749116977Sdavidxu pthread->interrupted = 1; 750115080Sdeischen break; 751113658Sdeischen 752115080Sdeischen case PS_SIGWAIT: 753116977Sdavidxu if (info == NULL) 754117066Sdavidxu build_siginfo(&pthread->siginfo[sig-1], sig); 755117066Sdavidxu else if (info != &pthread->siginfo[sig-1]) 756117066Sdavidxu memcpy(&pthread->siginfo[sig-1], info, 757116977Sdavidxu sizeof(*info)); 758113658Sdeischen /* 759115080Sdeischen * The signal handler is not called for threads in 760115080Sdeischen * SIGWAIT. 761113658Sdeischen */ 762115080Sdeischen suppress_handler = 1; 763116977Sdavidxu /* Wake up the thread if the signal is not blocked. */ 764116977Sdavidxu if (!SIGISMEMBER(pthread->sigmask, sig)) { 765115080Sdeischen /* Return the signal number: */ 766117066Sdavidxu *(pthread->data.sigwaitinfo) = pthread->siginfo[sig-1]; 767116977Sdavidxu pthread->sigmask = pthread->oldsigmask; 768115080Sdeischen /* Make the thread runnable: */ 769115080Sdeischen _thr_setrunnable_unlocked(pthread); 770116977Sdavidxu } else { 771115080Sdeischen /* Increment the pending signal count. */ 772116977Sdavidxu SIGADDSET(pthread->sigpend, sig); 773117366Sdavidxu if (!SIGISMEMBER(pthread->oldsigmask, sig)) { 774117366Sdavidxu pthread->check_pending = 1; 775117366Sdavidxu pthread->interrupted = 1; 776117366Sdavidxu pthread->sigmask = pthread->oldsigmask; 777117366Sdavidxu _thr_setrunnable_unlocked(pthread); 778117366Sdavidxu } 779116977Sdavidxu } 780116977Sdavidxu 781116977Sdavidxu return; 782115080Sdeischen } 783115080Sdeischen 784116977Sdavidxu SIGADDSET(pthread->sigpend, sig); 785116977Sdavidxu if (info == NULL) 786117066Sdavidxu build_siginfo(&pthread->siginfo[sig-1], sig); 787117066Sdavidxu else if (info != &pthread->siginfo[sig-1]) 788117066Sdavidxu memcpy(&pthread->siginfo[sig-1], info, sizeof(*info)); 789116977Sdavidxu 790115080Sdeischen if (suppress_handler == 0) { 791113658Sdeischen /* 792113658Sdeischen * Setup a signal frame and save the current threads 793113658Sdeischen * state: 794113658Sdeischen */ 795116977Sdavidxu thr_sigframe_add(pthread); 796116977Sdavidxu if (pthread->flags & THR_FLAGS_IN_RUNQ) 797116977Sdavidxu THR_RUNQ_REMOVE(pthread); 798115080Sdeischen pthread->active_priority |= THR_SIGNAL_PRIORITY; 799116977Sdavidxu _thr_setrunnable_unlocked(pthread); 800116977Sdavidxu } else { 801116977Sdavidxu pthread->check_pending = 1; 802115080Sdeischen } 80367097Sdeischen } 804116977Sdavidxu 805116977Sdavidxu DBG_MSG("<<< _thr_sig_add\n"); 80635509Sjb} 80713546Sjulian 80867566Sdeischenstatic void 809113658Sdeischenthr_sig_check_state(struct pthread *pthread, int sig) 81067566Sdeischen{ 81167566Sdeischen /* 81267566Sdeischen * Process according to thread state: 81367566Sdeischen */ 81467566Sdeischen switch (pthread->state) { 81567566Sdeischen /* 81667566Sdeischen * States which do not change when a signal is trapped: 81767566Sdeischen */ 818113658Sdeischen case PS_RUNNING: 819113658Sdeischen case PS_LOCKWAIT: 820113658Sdeischen case PS_MUTEX_WAIT: 821113658Sdeischen case PS_COND_WAIT: 822113658Sdeischen case PS_JOIN: 823113658Sdeischen case PS_SUSPENDED: 82467566Sdeischen case PS_DEAD: 82567566Sdeischen case PS_DEADLOCK: 82667566Sdeischen case PS_STATE_MAX: 82767566Sdeischen break; 82867566Sdeischen 82967566Sdeischen case PS_SIGWAIT: 830117066Sdavidxu build_siginfo(&pthread->siginfo[sig-1], sig); 83167566Sdeischen /* Wake up the thread if the signal is blocked. */ 832116977Sdavidxu if (!SIGISMEMBER(pthread->sigmask, sig)) { 83367566Sdeischen /* Return the signal number: */ 834117066Sdavidxu *(pthread->data.sigwaitinfo) = pthread->siginfo[sig-1]; 835116977Sdavidxu pthread->sigmask = pthread->oldsigmask; 836113658Sdeischen /* Change the state of the thread to run: */ 837113658Sdeischen _thr_setrunnable_unlocked(pthread); 838116977Sdavidxu } else { 83967566Sdeischen /* Increment the pending signal count. */ 840116977Sdavidxu SIGADDSET(pthread->sigpend, sig); 841117366Sdavidxu if (!SIGISMEMBER(pthread->oldsigmask, sig)) { 842117366Sdavidxu pthread->check_pending = 1; 843117366Sdavidxu pthread->interrupted = 1; 844117366Sdavidxu pthread->sigmask = pthread->oldsigmask; 845117366Sdavidxu _thr_setrunnable_unlocked(pthread); 846117366Sdavidxu } 847116977Sdavidxu } 84867566Sdeischen break; 84967566Sdeischen 85067566Sdeischen case PS_SIGSUSPEND: 85167566Sdeischen case PS_SLEEP_WAIT: 85267566Sdeischen /* 85367566Sdeischen * Remove the thread from the wait queue and make it 85467566Sdeischen * runnable: 85567566Sdeischen */ 856113658Sdeischen _thr_setrunnable_unlocked(pthread); 85767566Sdeischen 85867566Sdeischen /* Flag the operation as interrupted: */ 85967566Sdeischen pthread->interrupted = 1; 86067566Sdeischen break; 86167566Sdeischen } 86267566Sdeischen} 86367566Sdeischen 86467097Sdeischen/* 86567097Sdeischen * Send a signal to a specific thread (ala pthread_kill): 86667097Sdeischen */ 86754707Sdeischenvoid 868113658Sdeischen_thr_sig_send(struct pthread *pthread, int sig) 86954707Sdeischen{ 870113658Sdeischen struct pthread *curthread = _get_curthread(); 87171581Sdeischen 872116977Sdavidxu#ifdef NOTYET 873116977Sdavidxu if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) { 874116977Sdavidxu kse_thr_interrupt(&pthread->tmbx, sig); 875116977Sdavidxu return; 876116977Sdavidxu } 877116977Sdavidxu#endif 878113658Sdeischen /* Lock the scheduling queue of the target thread. */ 879113658Sdeischen THR_SCHED_LOCK(curthread, pthread); 880113658Sdeischen 88167566Sdeischen /* Check for signals whose actions are SIG_DFL: */ 88267566Sdeischen if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) { 88367566Sdeischen /* 88467566Sdeischen * Check to see if a temporary signal handler is 88567566Sdeischen * installed for sigwaiters: 88667566Sdeischen */ 887116977Sdavidxu if (_thread_dfl_count[sig - 1] == 0) { 88867566Sdeischen /* 88967566Sdeischen * Deliver the signal to the process if a handler 89067566Sdeischen * is not installed: 89167566Sdeischen */ 892113658Sdeischen THR_SCHED_UNLOCK(curthread, pthread); 89367566Sdeischen kill(getpid(), sig); 894113658Sdeischen THR_SCHED_LOCK(curthread, pthread); 895113658Sdeischen } 89667566Sdeischen /* 89767566Sdeischen * Assuming we're still running after the above kill(), 89867566Sdeischen * make any necessary state changes to the thread: 89967566Sdeischen */ 900113658Sdeischen thr_sig_check_state(pthread, sig); 901113658Sdeischen THR_SCHED_UNLOCK(curthread, pthread); 90267566Sdeischen } 90354707Sdeischen /* 90454707Sdeischen * Check that the signal is not being ignored: 90554707Sdeischen */ 90667566Sdeischen else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { 907116977Sdavidxu _thr_sig_add(pthread, sig, NULL); 908116977Sdavidxu THR_SCHED_UNLOCK(curthread, pthread); 909116977Sdavidxu /* XXX 910116977Sdavidxu * If thread sent signal to itself, check signals now. 911116977Sdavidxu * It is not really needed, _kse_critical_leave should 912116977Sdavidxu * have already checked signals. 913116977Sdavidxu */ 914116977Sdavidxu if (pthread == curthread && curthread->check_pending) 915116977Sdavidxu _thr_sig_check_pending(curthread); 916116977Sdavidxu } else { 917116977Sdavidxu THR_SCHED_UNLOCK(curthread, pthread); 91854707Sdeischen } 91954707Sdeischen} 92054707Sdeischen 921113658Sdeischenstatic void 922116977Sdavidxuthr_sigframe_add(struct pthread *thread) 92335509Sjb{ 924113658Sdeischen if (thread->curframe == NULL) 925113658Sdeischen PANIC("Thread doesn't have signal frame "); 92613546Sjulian 927116977Sdavidxu if (thread->curframe->psf_valid == 0) { 928116977Sdavidxu thread->curframe->psf_valid = 1; 92967097Sdeischen /* 930113658Sdeischen * Multiple signals can be added to the same signal 931113658Sdeischen * frame. Only save the thread's state the first time. 93267097Sdeischen */ 933113658Sdeischen thr_sigframe_save(thread, thread->curframe); 93467097Sdeischen } 93567097Sdeischen} 93654707Sdeischen 937116977Sdavidxustatic void 938113658Sdeischenthr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf) 93967097Sdeischen{ 940116977Sdavidxu if (psf->psf_valid == 0) 941116977Sdavidxu PANIC("invalid pthread_sigframe\n"); 942113658Sdeischen thread->flags = psf->psf_flags; 943113658Sdeischen thread->interrupted = psf->psf_interrupted; 944113658Sdeischen thread->signo = psf->psf_signo; 945113658Sdeischen thread->state = psf->psf_state; 946113658Sdeischen thread->data = psf->psf_wait_data; 947113658Sdeischen thread->wakeup_time = psf->psf_wakeup_time; 94867097Sdeischen} 94967097Sdeischen 95067097Sdeischenstatic void 951113658Sdeischenthr_sigframe_save(struct pthread *thread, struct pthread_sigframe *psf) 95267097Sdeischen{ 953113658Sdeischen /* This has to initialize all members of the sigframe. */ 954115413Sdavidxu psf->psf_flags = 955116061Sdeischen thread->flags & (THR_FLAGS_PRIVATE | THR_FLAGS_IN_TDLIST); 956113658Sdeischen psf->psf_interrupted = thread->interrupted; 957113658Sdeischen psf->psf_signo = thread->signo; 958113658Sdeischen psf->psf_state = thread->state; 959113658Sdeischen psf->psf_wait_data = thread->data; 960113658Sdeischen psf->psf_wakeup_time = thread->wakeup_time; 96167097Sdeischen} 962116977Sdavidxu 963116977Sdavidxuvoid 964116977Sdavidxu_thr_signal_init(void) 965116977Sdavidxu{ 966116977Sdavidxu sigset_t sigset; 967116977Sdavidxu struct sigaction act; 968116977Sdavidxu int i; 969116977Sdavidxu 970116977Sdavidxu SIGFILLSET(sigset); 971116977Sdavidxu __sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask); 972116977Sdavidxu /* Enter a loop to get the existing signal status: */ 973116977Sdavidxu for (i = 1; i <= _SIG_MAXSIG; i++) { 974116977Sdavidxu /* Check for signals which cannot be trapped: */ 975116977Sdavidxu if (i == SIGKILL || i == SIGSTOP) { 976116977Sdavidxu } 977116977Sdavidxu 978116977Sdavidxu /* Get the signal handler details: */ 979116977Sdavidxu else if (__sys_sigaction(i, NULL, 980116977Sdavidxu &_thread_sigact[i - 1]) != 0) { 981116977Sdavidxu /* 982116977Sdavidxu * Abort this process if signal 983116977Sdavidxu * initialisation fails: 984116977Sdavidxu */ 985116977Sdavidxu PANIC("Cannot read signal handler info"); 986116977Sdavidxu } 987116977Sdavidxu } 988116977Sdavidxu /* 989116977Sdavidxu * Install the signal handler for SIGINFO. It isn't 990116977Sdavidxu * really needed, but it is nice to have for debugging 991116977Sdavidxu * purposes. 992116977Sdavidxu */ 993116977Sdavidxu _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART; 994116977Sdavidxu SIGEMPTYSET(act.sa_mask); 995116977Sdavidxu act.sa_flags = SA_SIGINFO | SA_RESTART; 996116977Sdavidxu act.sa_sigaction = (__siginfohandler_t *)&_thr_sig_handler; 997116977Sdavidxu if (__sys_sigaction(SIGINFO, &act, NULL) != 0) { 998116977Sdavidxu /* 999116977Sdavidxu * Abort this process if signal initialisation fails: 1000116977Sdavidxu */ 1001116977Sdavidxu PANIC("Cannot initialize signal handler"); 1002116977Sdavidxu } 1003116977Sdavidxu} 1004116977Sdavidxu 1005116977Sdavidxuvoid 1006116977Sdavidxu_thr_signal_deinit(void) 1007116977Sdavidxu{ 1008117345Sdavidxu struct pthread *curthread = _get_curthread(); 1009117345Sdavidxu sigset_t tmpmask; 1010116977Sdavidxu int i; 1011116977Sdavidxu 1012116977Sdavidxu SIGFILLSET(tmpmask); 1013116977Sdavidxu SIG_CANTMASK(tmpmask); 1014117345Sdavidxu __sys_sigprocmask(SIG_SETMASK, &tmpmask, NULL); 1015116977Sdavidxu /* Enter a loop to get the existing signal status: */ 1016116977Sdavidxu for (i = 1; i <= _SIG_MAXSIG; i++) { 1017116977Sdavidxu /* Check for signals which cannot be trapped: */ 1018116977Sdavidxu if (i == SIGKILL || i == SIGSTOP) { 1019116977Sdavidxu } 1020116977Sdavidxu 1021116977Sdavidxu /* Set the signal handler details: */ 1022116977Sdavidxu else if (__sys_sigaction(i, &_thread_sigact[i - 1], NULL) != 0) { 1023116977Sdavidxu /* 1024116977Sdavidxu * Abort this process if signal 1025116977Sdavidxu * initialisation fails: 1026116977Sdavidxu */ 1027116977Sdavidxu PANIC("Cannot set signal handler info"); 1028116977Sdavidxu } 1029116977Sdavidxu } 1030117345Sdavidxu __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 1031116977Sdavidxu} 1032116977Sdavidxu 1033