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. 13165967Simp * 3. Neither the name of the author nor the names of any co-contributors 1413546Sjulian * may be used to endorse or promote products derived from this software 1513546Sjulian * without specific prior written permission. 1613546Sjulian * 1713546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 1813546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1913546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2049439Sdeischen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2113546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2213546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2313546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2413546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2513546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2613546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2713546Sjulian * SUCH DAMAGE. 2813546Sjulian * 2950476Speter * $FreeBSD$ 3013546Sjulian */ 31174112Sdeischen 32174112Sdeischen#include "namespace.h" 3351794Smarcel#include <sys/param.h> 3451794Smarcel#include <sys/types.h> 3551794Smarcel#include <sys/signalvar.h> 3613546Sjulian#include <signal.h> 37113658Sdeischen#include <errno.h> 3817706Sjulian#include <fcntl.h> 3917706Sjulian#include <unistd.h> 40113658Sdeischen#include <string.h> 4113546Sjulian#include <pthread.h> 42174112Sdeischen#include "un-namespace.h" 43103388Smini#include "thr_private.h" 4413546Sjulian 4554138Sdeischen/* Prototypes: */ 46139023Sdeischenstatic inline void build_siginfo(siginfo_t *info, int signo); 47117706Sdavidxu#ifndef SYSTEM_SCOPE_ONLY 48113658Sdeischenstatic struct pthread *thr_sig_find(struct kse *curkse, int sig, 49113658Sdeischen siginfo_t *info); 50117706Sdavidxu#endif 51139023Sdeischenstatic inline void thr_sigframe_restore(struct pthread *thread, 52139023Sdeischen struct pthread_sigframe *psf); 53139023Sdeischenstatic inline void thr_sigframe_save(struct pthread *thread, 54139023Sdeischen struct pthread_sigframe *psf); 55111035Smini 56117706Sdavidxu#define SA_KILL 0x01 /* terminates process by default */ 57117706Sdavidxu#define SA_STOP 0x02 58117706Sdavidxu#define SA_CONT 0x04 59117706Sdavidxu 60117706Sdavidxustatic int sigproptbl[NSIG] = { 61117706Sdavidxu SA_KILL, /* SIGHUP */ 62117706Sdavidxu SA_KILL, /* SIGINT */ 63117706Sdavidxu SA_KILL, /* SIGQUIT */ 64117706Sdavidxu SA_KILL, /* SIGILL */ 65117706Sdavidxu SA_KILL, /* SIGTRAP */ 66117706Sdavidxu SA_KILL, /* SIGABRT */ 67117706Sdavidxu SA_KILL, /* SIGEMT */ 68117706Sdavidxu SA_KILL, /* SIGFPE */ 69117706Sdavidxu SA_KILL, /* SIGKILL */ 70117706Sdavidxu SA_KILL, /* SIGBUS */ 71117706Sdavidxu SA_KILL, /* SIGSEGV */ 72117706Sdavidxu SA_KILL, /* SIGSYS */ 73117706Sdavidxu SA_KILL, /* SIGPIPE */ 74117706Sdavidxu SA_KILL, /* SIGALRM */ 75117706Sdavidxu SA_KILL, /* SIGTERM */ 76117706Sdavidxu 0, /* SIGURG */ 77117706Sdavidxu SA_STOP, /* SIGSTOP */ 78117706Sdavidxu SA_STOP, /* SIGTSTP */ 79117706Sdavidxu SA_CONT, /* SIGCONT */ 80117706Sdavidxu 0, /* SIGCHLD */ 81117706Sdavidxu SA_STOP, /* SIGTTIN */ 82117706Sdavidxu SA_STOP, /* SIGTTOU */ 83117706Sdavidxu 0, /* SIGIO */ 84117706Sdavidxu SA_KILL, /* SIGXCPU */ 85117706Sdavidxu SA_KILL, /* SIGXFSZ */ 86117706Sdavidxu SA_KILL, /* SIGVTALRM */ 87117706Sdavidxu SA_KILL, /* SIGPROF */ 88117706Sdavidxu 0, /* SIGWINCH */ 89117706Sdavidxu 0, /* SIGINFO */ 90117706Sdavidxu SA_KILL, /* SIGUSR1 */ 91117706Sdavidxu SA_KILL /* SIGUSR2 */ 92117706Sdavidxu}; 93117706Sdavidxu 94111035Smini/* #define DEBUG_SIGNAL */ 9567097Sdeischen#ifdef DEBUG_SIGNAL 9667097Sdeischen#define DBG_MSG stdout_debug 9767097Sdeischen#else 9867097Sdeischen#define DBG_MSG(x...) 9967097Sdeischen#endif 10056277Sjasone 101111035Smini/* 102113658Sdeischen * Signal setup and delivery. 103113658Sdeischen * 104113658Sdeischen * 1) Delivering signals to threads in the same KSE. 105113658Sdeischen * These signals are sent by upcall events and are set in the 106113658Sdeischen * km_sigscaught field of the KSE mailbox. Since these signals 107113658Sdeischen * are received while operating on the KSE stack, they can be 108113658Sdeischen * delivered either by using signalcontext() to add a stack frame 109113658Sdeischen * to the target thread's stack, or by adding them in the thread's 110113658Sdeischen * pending set and having the thread run them down after it 111113658Sdeischen * 2) Delivering signals to threads in other KSEs/KSEGs. 112113658Sdeischen * 3) Delivering signals to threads in critical regions. 113113658Sdeischen * 4) Delivering signals to threads after they change their signal masks. 114113658Sdeischen * 115113658Sdeischen * Methods of delivering signals. 116113658Sdeischen * 117113658Sdeischen * 1) Add a signal frame to the thread's saved context. 118113658Sdeischen * 2) Add the signal to the thread structure, mark the thread as 119113658Sdeischen * having signals to handle, and let the thread run them down 120113658Sdeischen * after it resumes from the KSE scheduler. 121113658Sdeischen * 122113658Sdeischen * Problem with 1). You can't do this to a running thread or a 123113658Sdeischen * thread in a critical region. 124113658Sdeischen * 125113658Sdeischen * Problem with 2). You can't do this to a thread that doesn't 126113658Sdeischen * yield in some way (explicitly enters the scheduler). A thread 127113658Sdeischen * blocked in the kernel or a CPU hungry thread will not see the 128113658Sdeischen * signal without entering the scheduler. 129113658Sdeischen * 130113658Sdeischen * The solution is to use both 1) and 2) to deliver signals: 131113658Sdeischen * 132113658Sdeischen * o Thread in critical region - use 2). When the thread 133113658Sdeischen * leaves the critical region it will check to see if it 134113658Sdeischen * has pending signals and run them down. 135113658Sdeischen * 136113658Sdeischen * o Thread enters scheduler explicitly - use 2). The thread 137113658Sdeischen * can check for pending signals after it returns from the 138113658Sdeischen * the scheduler. 139113658Sdeischen * 140113658Sdeischen * o Thread is running and not current thread - use 2). When the 141113658Sdeischen * thread hits a condition specified by one of the other bullets, 142113658Sdeischen * the signal will be delivered. 143113658Sdeischen * 144113658Sdeischen * o Thread is running and is current thread (e.g., the thread 145113658Sdeischen * has just changed its signal mask and now sees that it has 146113658Sdeischen * pending signals) - just run down the pending signals. 147113658Sdeischen * 148113658Sdeischen * o Thread is swapped out due to quantum expiration - use 1) 149113658Sdeischen * 150113658Sdeischen * o Thread is blocked in kernel - kse_thr_wakeup() and then 151113658Sdeischen * use 1) 152111035Smini */ 153113658Sdeischen 154113658Sdeischen/* 155113658Sdeischen * Rules for selecting threads for signals received: 156113658Sdeischen * 157113658Sdeischen * 1) If the signal is a sychronous signal, it is delivered to 158113658Sdeischen * the generating (current thread). If the thread has the 159113658Sdeischen * signal masked, it is added to the threads pending signal 160113658Sdeischen * set until the thread unmasks it. 161113658Sdeischen * 162113658Sdeischen * 2) A thread in sigwait() where the signal is in the thread's 163113658Sdeischen * waitset. 164113658Sdeischen * 165113658Sdeischen * 3) A thread in sigsuspend() where the signal is not in the 166113658Sdeischen * thread's suspended signal mask. 167113658Sdeischen * 168113658Sdeischen * 4) Any thread (first found/easiest to deliver) that has the 169113658Sdeischen * signal unmasked. 170113658Sdeischen */ 171113658Sdeischen 172117706Sdavidxu#ifndef SYSTEM_SCOPE_ONLY 173117706Sdavidxu 174116977Sdavidxustatic void * 175174112Sdeischensig_daemon(void *arg __unused) 176116977Sdavidxu{ 177116977Sdavidxu int i; 178116977Sdavidxu kse_critical_t crit; 179116977Sdavidxu struct timespec ts; 180116977Sdavidxu sigset_t set; 181116977Sdavidxu struct kse *curkse; 182116977Sdavidxu struct pthread *curthread = _get_curthread(); 183116977Sdavidxu 184117706Sdavidxu DBG_MSG("signal daemon started(%p)\n", curthread); 185116977Sdavidxu 186116977Sdavidxu curthread->name = strdup("signal thread"); 187116977Sdavidxu crit = _kse_critical_enter(); 188116977Sdavidxu curkse = _get_curkse(); 189117706Sdavidxu 190117706Sdavidxu /* 191117706Sdavidxu * Daemon thread is a bound thread and we must be created with 192117706Sdavidxu * all signals masked 193117706Sdavidxu */ 194117706Sdavidxu#if 0 195116977Sdavidxu SIGFILLSET(set); 196116977Sdavidxu __sys_sigprocmask(SIG_SETMASK, &set, NULL); 197117706Sdavidxu#endif 198116977Sdavidxu __sys_sigpending(&set); 199116977Sdavidxu ts.tv_sec = 0; 200116977Sdavidxu ts.tv_nsec = 0; 201116977Sdavidxu while (1) { 202116977Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 203116977Sdavidxu _thr_proc_sigpending = set; 204116977Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 205116977Sdavidxu for (i = 1; i <= _SIG_MAXSIG; i++) { 206116977Sdavidxu if (SIGISMEMBER(set, i) != 0) 207116977Sdavidxu _thr_sig_dispatch(curkse, i, 208116977Sdavidxu NULL /* no siginfo */); 209116977Sdavidxu } 210116977Sdavidxu ts.tv_sec = 30; 211116977Sdavidxu ts.tv_nsec = 0; 212118510Sdeischen curkse->k_kcb->kcb_kmbx.km_flags = 213116977Sdavidxu KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT; 214116977Sdavidxu kse_release(&ts); 215118510Sdeischen curkse->k_kcb->kcb_kmbx.km_flags = 0; 216118510Sdeischen set = curkse->k_kcb->kcb_kmbx.km_sigscaught; 217116977Sdavidxu } 218116977Sdavidxu return (0); 219116977Sdavidxu} 220116977Sdavidxu 221117706Sdavidxu 222116977Sdavidxu/* Utility function to create signal daemon thread */ 223116977Sdavidxuint 224116977Sdavidxu_thr_start_sig_daemon(void) 225116977Sdavidxu{ 226116977Sdavidxu pthread_attr_t attr; 227116977Sdavidxu sigset_t sigset, oldset; 228117706Sdavidxu 229116977Sdavidxu SIGFILLSET(sigset); 230174112Sdeischen _pthread_sigmask(SIG_SETMASK, &sigset, &oldset); 231174112Sdeischen _pthread_attr_init(&attr); 232174112Sdeischen _pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 233132122Sdavidxu attr->flags |= THR_SIGNAL_THREAD; 234116977Sdavidxu /* sigmask will be inherited */ 235174112Sdeischen if (_pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL)) 236116977Sdavidxu PANIC("can not create signal daemon thread!\n"); 237174112Sdeischen _pthread_attr_destroy(&attr); 238174112Sdeischen _pthread_sigmask(SIG_SETMASK, &oldset, NULL); 239116977Sdavidxu return (0); 240116977Sdavidxu} 241116977Sdavidxu 242113658Sdeischen/* 243113658Sdeischen * This signal handler only delivers asynchronous signals. 244113658Sdeischen * This must be called with upcalls disabled and without 245113658Sdeischen * holding any locks. 246113658Sdeischen */ 24713546Sjulianvoid 248113658Sdeischen_thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info) 24935509Sjb{ 250117907Sdeischen struct kse_mailbox *kmbx; 251113658Sdeischen struct pthread *thread; 25235509Sjb 253113658Sdeischen DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig); 25435509Sjb 255117706Sdavidxu /* Check if the signal requires a dump of thread information: */ 256156330Sdeischen if (_thr_dump_enabled() && (sig == SIGINFO)) { 257117706Sdavidxu /* Dump thread information to file: */ 258117706Sdavidxu _thread_dump_info(); 259117706Sdavidxu } 260117706Sdavidxu 261115278Sdeischen while ((thread = thr_sig_find(curkse, sig, info)) != NULL) { 262113658Sdeischen /* 263113658Sdeischen * Setup the target thread to receive the signal: 264113658Sdeischen */ 265113658Sdeischen DBG_MSG("Got signal %d, selecting thread %p\n", sig, thread); 266113658Sdeischen KSE_SCHED_LOCK(curkse, thread->kseg); 267115278Sdeischen if ((thread->state == PS_DEAD) || 268115278Sdeischen (thread->state == PS_DEADLOCK) || 269115278Sdeischen THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) { 270115278Sdeischen KSE_SCHED_UNLOCK(curkse, thread->kseg); 271115278Sdeischen _thr_ref_delete(NULL, thread); 272118075Sdavidxu } else if (SIGISMEMBER(thread->sigmask, sig)) { 273116061Sdeischen KSE_SCHED_UNLOCK(curkse, thread->kseg); 274116061Sdeischen _thr_ref_delete(NULL, thread); 275116977Sdavidxu } else { 276117907Sdeischen kmbx = _thr_sig_add(thread, sig, info); 277115278Sdeischen KSE_SCHED_UNLOCK(curkse, thread->kseg); 278115278Sdeischen _thr_ref_delete(NULL, thread); 279117907Sdeischen if (kmbx != NULL) 280117907Sdeischen kse_wakeup(kmbx); 281115278Sdeischen break; 282115278Sdeischen } 283113658Sdeischen } 284116977Sdavidxu DBG_MSG("<<< _thr_sig_dispatch\n"); 285113658Sdeischen} 286113658Sdeischen 287117706Sdavidxu#endif /* ! SYSTEM_SCOPE_ONLY */ 288117706Sdavidxu 289117706Sdavidxustatic __inline int 290117706Sdavidxusigprop(int sig) 291117706Sdavidxu{ 292117706Sdavidxu 293117706Sdavidxu if (sig > 0 && sig < NSIG) 294117706Sdavidxu return (sigproptbl[_SIG_IDX(sig)]); 295117706Sdavidxu return (0); 296117706Sdavidxu} 297117706Sdavidxu 298120073Sdavidxutypedef void (*ohandler)(int sig, int code, 299120073Sdavidxu struct sigcontext *scp, char *addr, __sighandler_t *catcher); 300120073Sdavidxu 301113658Sdeischenvoid 302174112Sdeischen_thr_sig_handler(int sig, siginfo_t *info, void *ucp_arg) 303113658Sdeischen{ 304139023Sdeischen struct pthread_sigframe psf; 305115381Sdeischen __siginfohandler_t *sigfunc; 306117706Sdavidxu struct pthread *curthread; 307113658Sdeischen struct kse *curkse; 308174112Sdeischen ucontext_t *ucp; 309117706Sdavidxu struct sigaction act; 310139023Sdeischen int sa_flags, err_save; 311113658Sdeischen 312139023Sdeischen err_save = errno; 313174112Sdeischen ucp = (ucontext_t *)ucp_arg; 314139023Sdeischen 315117706Sdavidxu DBG_MSG(">>> _thr_sig_handler(%d)\n", sig); 316117706Sdavidxu 317117706Sdavidxu curthread = _get_curthread(); 318117706Sdavidxu if (curthread == NULL) 319117706Sdavidxu PANIC("No current thread.\n"); 320117706Sdavidxu if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)) 321117706Sdavidxu PANIC("Thread is not system scope.\n"); 322139023Sdeischen if (curthread->flags & THR_FLAGS_EXITING) { 323139023Sdeischen errno = err_save; 324117706Sdavidxu return; 325139023Sdeischen } 326139023Sdeischen 327117706Sdavidxu curkse = _get_curkse(); 328117706Sdavidxu /* 329117706Sdavidxu * If thread is in critical region or if thread is on 330117706Sdavidxu * the way of state transition, then latch signal into buffer. 331117706Sdavidxu */ 332117706Sdavidxu if (_kse_in_critical() || THR_IN_CRITICAL(curthread) || 333139023Sdeischen curthread->state != PS_RUNNING) { 334117706Sdavidxu DBG_MSG(">>> _thr_sig_handler(%d) in critical\n", sig); 335117706Sdavidxu curthread->siginfo[sig-1] = *info; 336117706Sdavidxu curthread->check_pending = 1; 337117706Sdavidxu curkse->k_sigseqno++; 338117706Sdavidxu SIGADDSET(curthread->sigpend, sig); 339117706Sdavidxu /* 340117706Sdavidxu * If the kse is on the way to idle itself, but 341117706Sdavidxu * we have signal ready, we should prevent it 342117706Sdavidxu * to sleep, kernel will latch the wakeup request, 343117706Sdavidxu * so kse_release will return from kernel immediately. 344117706Sdavidxu */ 345117706Sdavidxu if (KSE_IS_IDLE(curkse)) 346118510Sdeischen kse_wakeup(&curkse->k_kcb->kcb_kmbx); 347139023Sdeischen errno = err_save; 348117706Sdavidxu return; 349113658Sdeischen } 350117706Sdavidxu 351132122Sdavidxu /* Check if the signal requires a dump of thread information: */ 352156330Sdeischen if (_thr_dump_enabled() && (sig == SIGINFO)) { 353132122Sdavidxu /* Dump thread information to file: */ 354132122Sdavidxu _thread_dump_info(); 355132122Sdavidxu } 356139023Sdeischen 357139023Sdeischen /* Check the threads previous state: */ 358139023Sdeischen curthread->critical_count++; 359139023Sdeischen if (curthread->sigbackout != NULL) 360139023Sdeischen curthread->sigbackout((void *)curthread); 361139023Sdeischen curthread->critical_count--; 362139023Sdeischen thr_sigframe_save(curthread, &psf); 363139023Sdeischen THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared."); 364139023Sdeischen 365120079Sdavidxu _kse_critical_enter(); 366120079Sdavidxu /* Get a fresh copy of signal mask */ 367120338Sdavidxu __sys_sigprocmask(SIG_BLOCK, NULL, &curthread->sigmask); 368117706Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 369117706Sdavidxu sigfunc = _thread_sigact[sig - 1].sa_sigaction; 370123933Sdavidxu sa_flags = _thread_sigact[sig - 1].sa_flags; 371117706Sdavidxu if (sa_flags & SA_RESETHAND) { 372117706Sdavidxu act.sa_handler = SIG_DFL; 373117706Sdavidxu act.sa_flags = SA_RESTART; 374117706Sdavidxu SIGEMPTYSET(act.sa_mask); 375117706Sdavidxu __sys_sigaction(sig, &act, NULL); 376117706Sdavidxu __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]); 377117706Sdavidxu } 378117706Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 379118510Sdeischen _kse_critical_leave(&curthread->tcb->tcb_tmbx); 380117706Sdavidxu 381117706Sdavidxu /* Now invoke real handler */ 382117706Sdavidxu if (((__sighandler_t *)sigfunc != SIG_DFL) && 383117706Sdavidxu ((__sighandler_t *)sigfunc != SIG_IGN) && 384117706Sdavidxu (sigfunc != (__siginfohandler_t *)_thr_sig_handler)) { 385117706Sdavidxu if ((sa_flags & SA_SIGINFO) != 0 || info == NULL) 386117706Sdavidxu (*(sigfunc))(sig, info, ucp); 387120073Sdavidxu else { 388120073Sdavidxu ((ohandler)(*sigfunc))( 389120073Sdavidxu sig, info->si_code, (struct sigcontext *)ucp, 390120073Sdavidxu info->si_addr, (__sighandler_t *)sigfunc); 391120073Sdavidxu } 392117706Sdavidxu } else { 393117706Sdavidxu if ((__sighandler_t *)sigfunc == SIG_DFL) { 394119063Sdavidxu if (sigprop(sig) & SA_KILL) { 395119063Sdavidxu if (_kse_isthreaded()) 396119063Sdavidxu kse_thr_interrupt(NULL, 397119063Sdavidxu KSE_INTR_SIGEXIT, sig); 398119063Sdavidxu else 399119063Sdavidxu kill(getpid(), sig); 400119063Sdavidxu } 401117706Sdavidxu#ifdef NOTYET 402117706Sdavidxu else if (sigprop(sig) & SA_STOP) 403117706Sdavidxu kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, sig); 404117706Sdavidxu#endif 405117706Sdavidxu } 406117706Sdavidxu } 407117706Sdavidxu _kse_critical_enter(); 408117706Sdavidxu curthread->sigmask = ucp->uc_sigmask; 409120079Sdavidxu SIG_CANTMASK(curthread->sigmask); 410118510Sdeischen _kse_critical_leave(&curthread->tcb->tcb_tmbx); 411139023Sdeischen 412139023Sdeischen thr_sigframe_restore(curthread, &psf); 413139023Sdeischen 414117706Sdavidxu DBG_MSG("<<< _thr_sig_handler(%d)\n", sig); 415139023Sdeischen 416139023Sdeischen errno = err_save; 417113658Sdeischen} 418113658Sdeischen 419123974Sdavidxustruct sighandle_info { 420123974Sdavidxu __siginfohandler_t *sigfunc; 421123974Sdavidxu int sa_flags; 422123974Sdavidxu int sig; 423123974Sdavidxu siginfo_t *info; 424123974Sdavidxu ucontext_t *ucp; 425123974Sdavidxu}; 426123974Sdavidxu 427123974Sdavidxustatic void handle_signal(struct pthread *curthread, 428123974Sdavidxu struct sighandle_info *shi); 429123974Sdavidxustatic void handle_signal_altstack(struct pthread *curthread, 430123974Sdavidxu struct sighandle_info *shi); 431123974Sdavidxu 432116977Sdavidxu/* Must be called with signal lock and schedule lock held in order */ 433113658Sdeischenstatic void 434113658Sdeischenthr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info, 435113658Sdeischen ucontext_t *ucp) 436113658Sdeischen{ 437123974Sdavidxu __siginfohandler_t *sigfunc; 438116977Sdavidxu sigset_t sigmask; 439116977Sdavidxu int sa_flags; 440123974Sdavidxu int onstack; 441116977Sdavidxu struct sigaction act; 442116977Sdavidxu struct kse *curkse; 443123974Sdavidxu struct sighandle_info shi; 444113658Sdeischen 445116977Sdavidxu /* 446116977Sdavidxu * Invoke the signal handler without going through the scheduler: 447113658Sdeischen */ 448113658Sdeischen DBG_MSG("Got signal %d, calling handler for current thread %p\n", 449113658Sdeischen sig, curthread); 450113658Sdeischen 451116977Sdavidxu if (!_kse_in_critical()) 452116977Sdavidxu PANIC("thr_sig_invoke_handler without in critical\n"); 453139023Sdeischen curkse = curthread->kse; 45448046Sjb /* 455113658Sdeischen * Check that a custom handler is installed and if 456113658Sdeischen * the signal is not blocked: 457113658Sdeischen */ 458113658Sdeischen sigfunc = _thread_sigact[sig - 1].sa_sigaction; 459123933Sdavidxu sa_flags = _thread_sigact[sig - 1].sa_flags; 460116977Sdavidxu sigmask = curthread->sigmask; 461116977Sdavidxu SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask); 462116977Sdavidxu if (!(sa_flags & (SA_NODEFER | SA_RESETHAND))) 463116977Sdavidxu SIGADDSET(curthread->sigmask, sig); 464116977Sdavidxu if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) { 465117706Sdavidxu act.sa_handler = SIG_DFL; 466117706Sdavidxu act.sa_flags = SA_RESTART; 467117706Sdavidxu SIGEMPTYSET(act.sa_mask); 468117706Sdavidxu __sys_sigaction(sig, &act, NULL); 469117706Sdavidxu __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]); 470116977Sdavidxu } 471116977Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 472116977Sdavidxu KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); 473117706Sdavidxu /* 474117706Sdavidxu * We are processing buffered signals, synchronize working 475117706Sdavidxu * signal mask into kernel. 476117706Sdavidxu */ 477117706Sdavidxu if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 478117706Sdavidxu __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 479123974Sdavidxu onstack = _thr_sigonstack(&sigfunc); 480123974Sdavidxu ucp->uc_stack = curthread->sigstk; 481123974Sdavidxu ucp->uc_stack.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE) 482123974Sdavidxu ? SS_DISABLE : ((onstack) ? SS_ONSTACK : 0); 483130374Sdavidxu if (curthread->oldsigmask) { 484130374Sdavidxu ucp->uc_sigmask = *(curthread->oldsigmask); 485130374Sdavidxu curthread->oldsigmask = NULL; 486130374Sdavidxu } else 487130374Sdavidxu ucp->uc_sigmask = sigmask; 488123974Sdavidxu shi.sigfunc = sigfunc; 489123974Sdavidxu shi.sig = sig; 490124055Sdavidxu shi.sa_flags = sa_flags; 491123974Sdavidxu shi.info = info; 492123974Sdavidxu shi.ucp = ucp; 493124095Sdavidxu if ((curthread->sigstk.ss_flags & SS_DISABLE) == 0) { 494123974Sdavidxu /* Deliver signal on alternative stack */ 495123974Sdavidxu if (sa_flags & SA_ONSTACK && !onstack) 496123974Sdavidxu handle_signal_altstack(curthread, &shi); 497123974Sdavidxu else 498123974Sdavidxu handle_signal(curthread, &shi); 499116977Sdavidxu } else { 500123974Sdavidxu handle_signal(curthread, &shi); 50167097Sdeischen } 502117706Sdavidxu 503116977Sdavidxu _kse_critical_enter(); 504116977Sdavidxu /* Don't trust after critical leave/enter */ 505139023Sdeischen curkse = curthread->kse; 506117706Sdavidxu 507113658Sdeischen /* 508113658Sdeischen * Restore the thread's signal mask. 509113658Sdeischen */ 510116977Sdavidxu curthread->sigmask = ucp->uc_sigmask; 511120079Sdavidxu SIG_CANTMASK(curthread->sigmask); 512117706Sdavidxu if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 513117706Sdavidxu __sys_sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL); 514117706Sdavidxu KSE_SCHED_LOCK(curkse, curkse->k_kseg); 515117706Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 516117706Sdavidxu 517116977Sdavidxu DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread); 51848046Sjb} 51948046Sjb 520123974Sdavidxustatic void 521123974Sdavidxuhandle_signal(struct pthread *curthread, struct sighandle_info *shi) 522123974Sdavidxu{ 523123974Sdavidxu _kse_critical_leave(&curthread->tcb->tcb_tmbx); 524123974Sdavidxu 525132122Sdavidxu /* Check if the signal requires a dump of thread information: */ 526156330Sdeischen if (_thr_dump_enabled() && (shi->sig == SIGINFO)) { 527132122Sdavidxu /* Dump thread information to file: */ 528132122Sdavidxu _thread_dump_info(); 529132122Sdavidxu } 530132122Sdavidxu 531123974Sdavidxu if (((__sighandler_t *)shi->sigfunc != SIG_DFL) && 532123974Sdavidxu ((__sighandler_t *)shi->sigfunc != SIG_IGN)) { 533123974Sdavidxu if ((shi->sa_flags & SA_SIGINFO) != 0 || shi->info == NULL) 534123974Sdavidxu (*(shi->sigfunc))(shi->sig, shi->info, shi->ucp); 535123974Sdavidxu else { 536123974Sdavidxu ((ohandler)(*shi->sigfunc))( 537123974Sdavidxu shi->sig, shi->info->si_code, 538123974Sdavidxu (struct sigcontext *)shi->ucp, 539123974Sdavidxu shi->info->si_addr, 540123974Sdavidxu (__sighandler_t *)shi->sigfunc); 541123974Sdavidxu } 542123974Sdavidxu } else { 543123974Sdavidxu if ((__sighandler_t *)shi->sigfunc == SIG_DFL) { 544123974Sdavidxu if (sigprop(shi->sig) & SA_KILL) { 545123974Sdavidxu if (_kse_isthreaded()) 546123974Sdavidxu kse_thr_interrupt(NULL, 547123974Sdavidxu KSE_INTR_SIGEXIT, shi->sig); 548123974Sdavidxu else 549123974Sdavidxu kill(getpid(), shi->sig); 550123974Sdavidxu } 551123974Sdavidxu#ifdef NOTYET 552123974Sdavidxu else if (sigprop(shi->sig) & SA_STOP) 553123974Sdavidxu kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, 554123974Sdavidxu shi->sig); 555123974Sdavidxu#endif 556123974Sdavidxu } 557123974Sdavidxu } 558123974Sdavidxu} 559123974Sdavidxu 560123974Sdavidxustatic void 561123974Sdavidxuhandle_signal_wrapper(struct pthread *curthread, ucontext_t *ret_uc, 562123974Sdavidxu struct sighandle_info *shi) 563123974Sdavidxu{ 564123974Sdavidxu shi->ucp->uc_stack.ss_flags = SS_ONSTACK; 565123974Sdavidxu handle_signal(curthread, shi); 566123974Sdavidxu if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 567123974Sdavidxu setcontext(ret_uc); 568123974Sdavidxu else { 569123974Sdavidxu /* Work around for ia64, THR_SETCONTEXT does not work */ 570123974Sdavidxu _kse_critical_enter(); 571123974Sdavidxu curthread->tcb->tcb_tmbx.tm_context = *ret_uc; 572123974Sdavidxu _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1); 573123974Sdavidxu /* THR_SETCONTEXT */ 574123974Sdavidxu } 575123974Sdavidxu} 576123974Sdavidxu 577123974Sdavidxu/* 578123974Sdavidxu * Jump to stack set by sigaltstack before invoking signal handler 579123974Sdavidxu */ 580123974Sdavidxustatic void 581123974Sdavidxuhandle_signal_altstack(struct pthread *curthread, struct sighandle_info *shi) 582123974Sdavidxu{ 583123974Sdavidxu volatile int once; 584123974Sdavidxu ucontext_t uc1, *uc2; 585123974Sdavidxu 586123974Sdavidxu THR_ASSERT(_kse_in_critical(), "Not in critical"); 587123974Sdavidxu 588123974Sdavidxu once = 0; 589123974Sdavidxu THR_GETCONTEXT(&uc1); 590123974Sdavidxu if (once == 0) { 591123974Sdavidxu once = 1; 592123974Sdavidxu /* XXX 593123974Sdavidxu * We are still in critical region, it is safe to operate thread 594123974Sdavidxu * context 595123974Sdavidxu */ 596123974Sdavidxu uc2 = &curthread->tcb->tcb_tmbx.tm_context; 597123974Sdavidxu uc2->uc_stack = curthread->sigstk; 598123974Sdavidxu makecontext(uc2, (void (*)(void))handle_signal_wrapper, 599123974Sdavidxu 3, curthread, &uc1, shi); 600123974Sdavidxu if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 601123974Sdavidxu setcontext(uc2); 602123974Sdavidxu else { 603123974Sdavidxu _thread_switch(curthread->kse->k_kcb, curthread->tcb, 1); 604123974Sdavidxu /* THR_SETCONTEXT(uc2); */ 605123974Sdavidxu } 606123974Sdavidxu } 607123974Sdavidxu} 608123974Sdavidxu 609116977Sdavidxuint 610116977Sdavidxu_thr_getprocsig(int sig, siginfo_t *siginfo) 611116977Sdavidxu{ 612116977Sdavidxu kse_critical_t crit; 613116977Sdavidxu struct kse *curkse; 614116977Sdavidxu int ret; 615116977Sdavidxu 616116977Sdavidxu DBG_MSG(">>> _thr_getprocsig\n"); 617116977Sdavidxu 618116977Sdavidxu crit = _kse_critical_enter(); 619116977Sdavidxu curkse = _get_curkse(); 620116977Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 621116977Sdavidxu ret = _thr_getprocsig_unlocked(sig, siginfo); 622116977Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 623116977Sdavidxu _kse_critical_leave(crit); 624116977Sdavidxu 625116977Sdavidxu DBG_MSG("<<< _thr_getprocsig\n"); 626116977Sdavidxu return (ret); 627116977Sdavidxu} 628116977Sdavidxu 629116977Sdavidxuint 630116977Sdavidxu_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo) 631116977Sdavidxu{ 632116977Sdavidxu sigset_t sigset; 633116977Sdavidxu struct timespec ts; 634116977Sdavidxu 635116977Sdavidxu /* try to retrieve signal from kernel */ 636116977Sdavidxu SIGEMPTYSET(sigset); 637116977Sdavidxu SIGADDSET(sigset, sig); 638116977Sdavidxu ts.tv_sec = 0; 639116977Sdavidxu ts.tv_nsec = 0; 640117706Sdavidxu SIGDELSET(_thr_proc_sigpending, sig); 641117706Sdavidxu if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0) 642116977Sdavidxu return (sig); 643116977Sdavidxu return (0); 644116977Sdavidxu} 645116977Sdavidxu 646117706Sdavidxu#ifndef SYSTEM_SCOPE_ONLY 64767097Sdeischen/* 648113658Sdeischen * Find a thread that can handle the signal. This must be called 649113658Sdeischen * with upcalls disabled. 65067097Sdeischen */ 651113658Sdeischenstruct pthread * 652174112Sdeischenthr_sig_find(struct kse *curkse, int sig, siginfo_t *info __unused) 65348046Sjb{ 654117907Sdeischen struct kse_mailbox *kmbx = NULL; 655114180Sdeischen struct pthread *pthread; 65690431Sdeischen struct pthread *suspended_thread, *signaled_thread; 657117706Sdavidxu __siginfohandler_t *sigfunc; 658116977Sdavidxu siginfo_t si; 65948046Sjb 66067097Sdeischen DBG_MSG("Looking for thread to handle signal %d\n", sig); 661113658Sdeischen 662111035Smini /* 663111035Smini * Enter a loop to look for threads that have the signal 664111035Smini * unmasked. POSIX specifies that a thread in a sigwait 665111035Smini * will get the signal over any other threads. Second 666177626Sbrueffer * preference will be threads in a sigsuspend. Third 667111035Smini * preference will be the current thread. If none of the 668111035Smini * above, then the signal is delivered to the first thread 669111035Smini * that is found. Note that if a custom handler is not 670111035Smini * installed, the signal only affects threads in sigwait. 671111035Smini */ 672111035Smini suspended_thread = NULL; 673113658Sdeischen signaled_thread = NULL; 674111035Smini 675113658Sdeischen KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); 676114180Sdeischen TAILQ_FOREACH(pthread, &_thread_list, tle) { 677116977Sdavidxu if (pthread == _thr_sig_daemon) 678116977Sdavidxu continue; 679116977Sdavidxu /* Signal delivering to bound thread is done by kernel */ 680116977Sdavidxu if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 681116977Sdavidxu continue; 682114254Sdeischen /* Take the scheduling lock. */ 683114254Sdeischen KSE_SCHED_LOCK(curkse, pthread->kseg); 684116977Sdavidxu if ((pthread->state == PS_DEAD) || 685116977Sdavidxu (pthread->state == PS_DEADLOCK) || 686116977Sdavidxu THR_IS_EXITING(pthread) || 687117353Sdavidxu THR_IS_SUSPENDED(pthread)) { 688116977Sdavidxu ; /* Skip this thread. */ 689117353Sdavidxu } else if (pthread->state == PS_SIGWAIT && 690118075Sdavidxu SIGISMEMBER(*(pthread->data.sigwait->waitset), sig)) { 69148046Sjb /* 692116977Sdavidxu * retrieve signal from kernel, if it is job control 693116977Sdavidxu * signal, and sigaction is SIG_DFL, then we will 694116977Sdavidxu * be stopped in kernel, we hold lock here, but that 695116977Sdavidxu * does not matter, because that's job control, and 696116977Sdavidxu * whole process should be stopped. 69748046Sjb */ 698116977Sdavidxu if (_thr_getprocsig(sig, &si)) { 699116977Sdavidxu DBG_MSG("Waking thread %p in sigwait" 700116977Sdavidxu " with signal %d\n", pthread, sig); 701116977Sdavidxu /* where to put siginfo ? */ 702118075Sdavidxu *(pthread->data.sigwait->siginfo) = si; 703117907Sdeischen kmbx = _thr_setrunnable_unlocked(pthread); 704116977Sdavidxu } 705113658Sdeischen KSE_SCHED_UNLOCK(curkse, pthread->kseg); 706111035Smini /* 707111035Smini * POSIX doesn't doesn't specify which thread 708111035Smini * will get the signal if there are multiple 709111035Smini * waiters, so we give it to the first thread 710111035Smini * we find. 711111035Smini * 712111035Smini * Do not attempt to deliver this signal 713111035Smini * to other threads and do not add the signal 714111035Smini * to the process pending set. 715111035Smini */ 716113658Sdeischen KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 717117907Sdeischen if (kmbx != NULL) 718117907Sdeischen kse_wakeup(kmbx); 719136735Sdavidxu if (suspended_thread != NULL) 720136735Sdavidxu _thr_ref_delete(NULL, suspended_thread); 721136735Sdavidxu if (signaled_thread != NULL) 722136735Sdavidxu _thr_ref_delete(NULL, signaled_thread); 723111035Smini return (NULL); 724118075Sdavidxu } else if (!SIGISMEMBER(pthread->sigmask, sig)) { 725132122Sdavidxu /* 726132122Sdavidxu * If debugger is running, we don't quick exit, 727132122Sdavidxu * and give it a chance to check the signal. 728132122Sdavidxu */ 729132122Sdavidxu if (_libkse_debug == 0) { 730132122Sdavidxu sigfunc = _thread_sigact[sig - 1].sa_sigaction; 731132122Sdavidxu if ((__sighandler_t *)sigfunc == SIG_DFL) { 732132122Sdavidxu if (sigprop(sig) & SA_KILL) { 733132122Sdavidxu kse_thr_interrupt(NULL, 734132122Sdavidxu KSE_INTR_SIGEXIT, sig); 735132122Sdavidxu /* Never reach */ 736132122Sdavidxu } 737117706Sdavidxu } 738117706Sdavidxu } 739111035Smini if (pthread->state == PS_SIGSUSPEND) { 740115278Sdeischen if (suspended_thread == NULL) { 741111035Smini suspended_thread = pthread; 742115278Sdeischen suspended_thread->refcount++; 743115278Sdeischen } 744115278Sdeischen } else if (signaled_thread == NULL) { 745111035Smini signaled_thread = pthread; 746115278Sdeischen signaled_thread->refcount++; 747116977Sdavidxu } 748111035Smini } 749114254Sdeischen KSE_SCHED_UNLOCK(curkse, pthread->kseg); 750111035Smini } 751113658Sdeischen KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 75239805Sjb 753116977Sdavidxu if (suspended_thread != NULL) { 754116977Sdavidxu pthread = suspended_thread; 755116977Sdavidxu if (signaled_thread) 756116977Sdavidxu _thr_ref_delete(NULL, signaled_thread); 757116977Sdavidxu } else if (signaled_thread) { 758116977Sdavidxu pthread = signaled_thread; 759113658Sdeischen } else { 760116977Sdavidxu pthread = NULL; 761111035Smini } 762116977Sdavidxu return (pthread); 76335509Sjb} 764117706Sdavidxu#endif /* ! SYSTEM_SCOPE_ONLY */ 76535509Sjb 766139023Sdeischenstatic inline void 767113658Sdeischenbuild_siginfo(siginfo_t *info, int signo) 768113658Sdeischen{ 769113658Sdeischen bzero(info, sizeof(*info)); 770113658Sdeischen info->si_signo = signo; 771113658Sdeischen info->si_pid = _thr_pid; 772113658Sdeischen} 773113658Sdeischen 774113658Sdeischen/* 775113658Sdeischen * This is called by a thread when it has pending signals to deliver. 776113658Sdeischen * It should only be called from the context of the thread. 777113658Sdeischen */ 77867097Sdeischenvoid 779139023Sdeischen_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp) 78056277Sjasone{ 781139023Sdeischen struct pthread_sigframe psf; 782116977Sdavidxu siginfo_t siginfo; 783139023Sdeischen int i, err_save; 784116977Sdavidxu kse_critical_t crit; 785116977Sdavidxu struct kse *curkse; 786117706Sdavidxu sigset_t sigmask; 78767097Sdeischen 788139023Sdeischen err_save = errno; 789139023Sdeischen 790117706Sdavidxu DBG_MSG(">>> thr_sig_rundown (%p)\n", curthread); 791139023Sdeischen 792113658Sdeischen /* Check the threads previous state: */ 793139023Sdeischen curthread->critical_count++; 794139023Sdeischen if (curthread->sigbackout != NULL) 795139023Sdeischen curthread->sigbackout((void *)curthread); 796139023Sdeischen curthread->critical_count--; 797116977Sdavidxu 798139023Sdeischen THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared."); 799139023Sdeischen THR_ASSERT((curthread->state == PS_RUNNING), "state is not PS_RUNNING"); 800116977Sdavidxu 801139023Sdeischen thr_sigframe_save(curthread, &psf); 80256277Sjasone /* 803113658Sdeischen * Lower the priority before calling the handler in case 804113658Sdeischen * it never returns (longjmps back): 80556277Sjasone */ 806116977Sdavidxu crit = _kse_critical_enter(); 807139023Sdeischen curkse = curthread->kse; 808116977Sdavidxu KSE_SCHED_LOCK(curkse, curkse->k_kseg); 809116977Sdavidxu KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 810113658Sdeischen curthread->active_priority &= ~THR_SIGNAL_PRIORITY; 811119249Sdavidxu SIGFILLSET(sigmask); 812116977Sdavidxu while (1) { 813117706Sdavidxu /* 814117706Sdavidxu * For bound thread, we mask all signals and get a fresh 815117706Sdavidxu * copy of signal mask from kernel 816117706Sdavidxu */ 817117706Sdavidxu if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) { 818117706Sdavidxu __sys_sigprocmask(SIG_SETMASK, &sigmask, 819117706Sdavidxu &curthread->sigmask); 820117706Sdavidxu } 821116977Sdavidxu for (i = 1; i <= _SIG_MAXSIG; i++) { 822116977Sdavidxu if (SIGISMEMBER(curthread->sigmask, i)) 823116977Sdavidxu continue; 824116977Sdavidxu if (SIGISMEMBER(curthread->sigpend, i)) { 825116977Sdavidxu SIGDELSET(curthread->sigpend, i); 826117066Sdavidxu siginfo = curthread->siginfo[i-1]; 827116977Sdavidxu break; 828116977Sdavidxu } 829117706Sdavidxu if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 830117706Sdavidxu && SIGISMEMBER(_thr_proc_sigpending, i)) { 831116977Sdavidxu if (_thr_getprocsig_unlocked(i, &siginfo)) 832116977Sdavidxu break; 833116977Sdavidxu } 83467097Sdeischen } 835116977Sdavidxu if (i <= _SIG_MAXSIG) 836116977Sdavidxu thr_sig_invoke_handler(curthread, i, &siginfo, ucp); 837119249Sdavidxu else { 838119249Sdavidxu if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) { 839119249Sdavidxu __sys_sigprocmask(SIG_SETMASK, 840119249Sdavidxu &curthread->sigmask, NULL); 841119249Sdavidxu } 842116977Sdavidxu break; 843119249Sdavidxu } 84456277Sjasone } 845113658Sdeischen 846139023Sdeischen /* Don't trust after signal handling */ 847139023Sdeischen curkse = curthread->kse; 848116977Sdavidxu KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 849116977Sdavidxu KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); 850119249Sdavidxu _kse_critical_leave(&curthread->tcb->tcb_tmbx); 851119249Sdavidxu /* repost masked signal to kernel, it hardly happens in real world */ 852119249Sdavidxu if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) && 853119249Sdavidxu !SIGISEMPTY(curthread->sigpend)) { /* dirty read */ 854119249Sdavidxu __sys_sigprocmask(SIG_SETMASK, &sigmask, &curthread->sigmask); 855119249Sdavidxu for (i = 1; i <= _SIG_MAXSIG; ++i) { 856119249Sdavidxu if (SIGISMEMBER(curthread->sigpend, i)) { 857119249Sdavidxu SIGDELSET(curthread->sigpend, i); 858119249Sdavidxu if (!_kse_isthreaded()) 859119249Sdavidxu kill(getpid(), i); 860119249Sdavidxu else 861119249Sdavidxu kse_thr_interrupt( 862119249Sdavidxu &curthread->tcb->tcb_tmbx, 863119249Sdavidxu KSE_INTR_SENDSIG, 864119249Sdavidxu i); 865119249Sdavidxu } 866119249Sdavidxu } 867117706Sdavidxu __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 868119249Sdavidxu } 869139023Sdeischen DBG_MSG("<<< thr_sig_rundown (%p)\n", curthread); 870117353Sdavidxu 871139023Sdeischen thr_sigframe_restore(curthread, &psf); 872139023Sdeischen errno = err_save; 87367097Sdeischen} 87467097Sdeischen 87567097Sdeischen/* 876113658Sdeischen * This checks pending signals for the current thread. It should be 877113658Sdeischen * called whenever a thread changes its signal mask. Note that this 878113658Sdeischen * is called from a thread (using its stack). 879113658Sdeischen * 880113658Sdeischen * XXX - We might want to just check to see if there are pending 881113658Sdeischen * signals for the thread here, but enter the UTS scheduler 882113658Sdeischen * to actually install the signal handler(s). 88367097Sdeischen */ 88467097Sdeischenvoid 885113658Sdeischen_thr_sig_check_pending(struct pthread *curthread) 88667097Sdeischen{ 887116977Sdavidxu ucontext_t uc; 888116977Sdavidxu volatile int once; 889119177Sdavidxu int errsave; 89067097Sdeischen 891139023Sdeischen /* 892139023Sdeischen * If the thread is in critical region, delay processing signals. 893139023Sdeischen * If the thread state is not PS_RUNNING, it might be switching 894139023Sdeischen * into UTS and but a THR_LOCK_RELEASE saw check_pending, and it 895139023Sdeischen * goes here, in the case we delay processing signals, lets UTS 896139023Sdeischen * process complicated things, normally UTS will call _thr_sig_add 897139023Sdeischen * to resume the thread, so we needn't repeat doing it here. 898139023Sdeischen */ 899139023Sdeischen if (THR_IN_CRITICAL(curthread) || curthread->state != PS_RUNNING) 900116977Sdavidxu return; 901113658Sdeischen 902119177Sdavidxu errsave = errno; 903116977Sdavidxu once = 0; 904116977Sdavidxu THR_GETCONTEXT(&uc); 905116977Sdavidxu if (once == 0) { 906116977Sdavidxu once = 1; 907113658Sdeischen curthread->check_pending = 0; 908139023Sdeischen _thr_sig_rundown(curthread, &uc); 90956277Sjasone } 910119177Sdavidxu errno = errsave; 91156277Sjasone} 91256277Sjasone 913111035Smini/* 91467097Sdeischen * Perform thread specific actions in response to a signal. 91567097Sdeischen * This function is only called if there is a handler installed 91667097Sdeischen * for the signal, and if the target thread has the signal 91767097Sdeischen * unmasked. 918113658Sdeischen * 919113658Sdeischen * This must be called with the thread's scheduling lock held. 92067097Sdeischen */ 921117907Sdeischenstruct kse_mailbox * 922115080Sdeischen_thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) 92335509Sjb{ 924117907Sdeischen siginfo_t siginfo; 925117907Sdeischen struct kse *curkse; 926117907Sdeischen struct kse_mailbox *kmbx = NULL; 927117907Sdeischen struct pthread *curthread = _get_curthread(); 928113658Sdeischen int restart; 92967097Sdeischen int suppress_handler = 0; 930116977Sdavidxu int fromproc = 0; 931118748Sdavidxu __sighandler_t *sigfunc; 93267097Sdeischen 933117706Sdavidxu DBG_MSG(">>> _thr_sig_add %p (%d)\n", pthread, sig); 934116977Sdavidxu 935116977Sdavidxu curkse = _get_curkse(); 936116977Sdavidxu restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART; 937118748Sdavidxu sigfunc = _thread_sigact[sig - 1].sa_handler; 938116977Sdavidxu fromproc = (curthread == _thr_sig_daemon); 939116977Sdavidxu 940116977Sdavidxu if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK || 941116977Sdavidxu pthread->state == PS_STATE_MAX) 942117907Sdeischen return (NULL); /* return false */ 943116977Sdavidxu 944117706Sdavidxu if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) && 945117706Sdavidxu (curthread != pthread)) { 946117706Sdavidxu PANIC("Please use _thr_send_sig for bound thread"); 947117907Sdeischen return (NULL); 948115080Sdeischen } 949116977Sdavidxu 950139023Sdeischen if (pthread->state != PS_SIGWAIT && 951139023Sdeischen SIGISMEMBER(pthread->sigmask, sig)) { 952139023Sdeischen /* signal is masked, just add signal to thread. */ 953116977Sdavidxu if (!fromproc) { 954116977Sdavidxu SIGADDSET(pthread->sigpend, sig); 955116977Sdavidxu if (info == NULL) 956117066Sdavidxu build_siginfo(&pthread->siginfo[sig-1], sig); 957117066Sdavidxu else if (info != &pthread->siginfo[sig-1]) 958117066Sdavidxu memcpy(&pthread->siginfo[sig-1], info, 959116977Sdavidxu sizeof(*info)); 960116977Sdavidxu } else { 961117066Sdavidxu if (!_thr_getprocsig(sig, &pthread->siginfo[sig-1])) 962117907Sdeischen return (NULL); 963116977Sdavidxu SIGADDSET(pthread->sigpend, sig); 964116977Sdavidxu } 965116977Sdavidxu } 966115080Sdeischen else { 967116977Sdavidxu /* if process signal not exists, just return */ 968116977Sdavidxu if (fromproc) { 969116977Sdavidxu if (!_thr_getprocsig(sig, &siginfo)) 970117907Sdeischen return (NULL); 971116977Sdavidxu info = &siginfo; 972116977Sdavidxu } 973118748Sdavidxu 974118748Sdavidxu if (pthread->state != PS_SIGWAIT && sigfunc == SIG_DFL && 975118748Sdavidxu (sigprop(sig) & SA_KILL)) { 976118748Sdavidxu kse_thr_interrupt(NULL, KSE_INTR_SIGEXIT, sig); 977118748Sdavidxu /* Never reach */ 978118748Sdavidxu } 979118748Sdavidxu 98067097Sdeischen /* 981115080Sdeischen * Process according to thread state: 98267097Sdeischen */ 983115080Sdeischen switch (pthread->state) { 984115080Sdeischen case PS_DEAD: 985115080Sdeischen case PS_DEADLOCK: 986116977Sdavidxu case PS_STATE_MAX: 987117907Sdeischen return (NULL); /* XXX return false */ 988115080Sdeischen case PS_LOCKWAIT: 989115080Sdeischen case PS_SUSPENDED: 99067097Sdeischen /* 991115080Sdeischen * You can't call a signal handler for threads in these 992115080Sdeischen * states. 99367097Sdeischen */ 994113658Sdeischen suppress_handler = 1; 995115080Sdeischen break; 996115080Sdeischen case PS_RUNNING: 997116977Sdavidxu if ((pthread->flags & THR_FLAGS_IN_RUNQ)) { 998115080Sdeischen THR_RUNQ_REMOVE(pthread); 999116977Sdavidxu pthread->active_priority |= THR_SIGNAL_PRIORITY; 1000116977Sdavidxu THR_RUNQ_INSERT_TAIL(pthread); 1001116977Sdavidxu } else { 1002116977Sdavidxu /* Possible not in RUNQ and has curframe ? */ 1003116977Sdavidxu pthread->active_priority |= THR_SIGNAL_PRIORITY; 1004116977Sdavidxu } 1005115080Sdeischen break; 100639805Sjb /* 1007115080Sdeischen * States which cannot be interrupted but still require the 1008115080Sdeischen * signal handler to run: 100939805Sjb */ 1010115080Sdeischen case PS_COND_WAIT: 1011115080Sdeischen case PS_MUTEX_WAIT: 1012115080Sdeischen break; 101339805Sjb 1014115080Sdeischen case PS_SLEEP_WAIT: 1015115080Sdeischen /* 1016115080Sdeischen * Unmasked signals always cause sleep to terminate 1017115080Sdeischen * early regardless of SA_RESTART: 1018115080Sdeischen */ 1019115080Sdeischen pthread->interrupted = 1; 1020115080Sdeischen break; 1021113658Sdeischen 1022115080Sdeischen case PS_JOIN: 1023116977Sdavidxu break; 1024116977Sdavidxu 1025115080Sdeischen case PS_SIGSUSPEND: 1026116977Sdavidxu pthread->interrupted = 1; 1027115080Sdeischen break; 1028113658Sdeischen 1029115080Sdeischen case PS_SIGWAIT: 1030116977Sdavidxu if (info == NULL) 1031117066Sdavidxu build_siginfo(&pthread->siginfo[sig-1], sig); 1032117066Sdavidxu else if (info != &pthread->siginfo[sig-1]) 1033117066Sdavidxu memcpy(&pthread->siginfo[sig-1], info, 1034116977Sdavidxu sizeof(*info)); 1035113658Sdeischen /* 1036115080Sdeischen * The signal handler is not called for threads in 1037115080Sdeischen * SIGWAIT. 1038113658Sdeischen */ 1039115080Sdeischen suppress_handler = 1; 1040116977Sdavidxu /* Wake up the thread if the signal is not blocked. */ 1041118075Sdavidxu if (SIGISMEMBER(*(pthread->data.sigwait->waitset), sig)) { 1042115080Sdeischen /* Return the signal number: */ 1043118075Sdavidxu *(pthread->data.sigwait->siginfo) = pthread->siginfo[sig-1]; 1044115080Sdeischen /* Make the thread runnable: */ 1045117907Sdeischen kmbx = _thr_setrunnable_unlocked(pthread); 1046116977Sdavidxu } else { 1047115080Sdeischen /* Increment the pending signal count. */ 1048116977Sdavidxu SIGADDSET(pthread->sigpend, sig); 1049118075Sdavidxu if (!SIGISMEMBER(pthread->sigmask, sig)) { 1050118748Sdavidxu if (sigfunc == SIG_DFL && 1051118748Sdavidxu sigprop(sig) & SA_KILL) { 1052118748Sdavidxu kse_thr_interrupt(NULL, 1053118748Sdavidxu KSE_INTR_SIGEXIT, 1054118748Sdavidxu sig); 1055118748Sdavidxu /* Never reach */ 1056118748Sdavidxu } 1057117366Sdavidxu pthread->check_pending = 1; 1058117366Sdavidxu pthread->interrupted = 1; 1059117907Sdeischen kmbx = _thr_setrunnable_unlocked(pthread); 1060117366Sdavidxu } 1061116977Sdavidxu } 1062117907Sdeischen return (kmbx); 1063115080Sdeischen } 1064115080Sdeischen 1065116977Sdavidxu SIGADDSET(pthread->sigpend, sig); 1066116977Sdavidxu if (info == NULL) 1067117066Sdavidxu build_siginfo(&pthread->siginfo[sig-1], sig); 1068117066Sdavidxu else if (info != &pthread->siginfo[sig-1]) 1069117066Sdavidxu memcpy(&pthread->siginfo[sig-1], info, sizeof(*info)); 1070139023Sdeischen pthread->check_pending = 1; 1071139023Sdeischen if (!(pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) && 1072139023Sdeischen (pthread->blocked != 0) && !THR_IN_CRITICAL(pthread)) 1073139023Sdeischen kse_thr_interrupt(&pthread->tcb->tcb_tmbx, 1074139023Sdeischen restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0); 1075115080Sdeischen if (suppress_handler == 0) { 1076113658Sdeischen /* 1077113658Sdeischen * Setup a signal frame and save the current threads 1078113658Sdeischen * state: 1079113658Sdeischen */ 1080139023Sdeischen if (pthread->state != PS_RUNNING) { 1081139023Sdeischen if (pthread->flags & THR_FLAGS_IN_RUNQ) 1082139023Sdeischen THR_RUNQ_REMOVE(pthread); 1083139023Sdeischen pthread->active_priority |= THR_SIGNAL_PRIORITY; 1084139023Sdeischen kmbx = _thr_setrunnable_unlocked(pthread); 1085139023Sdeischen } 1086115080Sdeischen } 108767097Sdeischen } 1088117907Sdeischen return (kmbx); 108935509Sjb} 109013546Sjulian 109167097Sdeischen/* 109267097Sdeischen * Send a signal to a specific thread (ala pthread_kill): 109367097Sdeischen */ 109454707Sdeischenvoid 1095113658Sdeischen_thr_sig_send(struct pthread *pthread, int sig) 109654707Sdeischen{ 1097113658Sdeischen struct pthread *curthread = _get_curthread(); 1098117907Sdeischen struct kse_mailbox *kmbx; 109971581Sdeischen 1100117706Sdavidxu if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) { 1101118510Sdeischen kse_thr_interrupt(&pthread->tcb->tcb_tmbx, KSE_INTR_SENDSIG, sig); 1102116977Sdavidxu return; 1103116977Sdavidxu } 1104117706Sdavidxu 1105113658Sdeischen /* Lock the scheduling queue of the target thread. */ 1106113658Sdeischen THR_SCHED_LOCK(curthread, pthread); 1107117706Sdavidxu if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { 1108117907Sdeischen kmbx = _thr_sig_add(pthread, sig, NULL); 1109139023Sdeischen /* Add a preemption point. */ 1110139023Sdeischen if (kmbx == NULL && (curthread->kseg == pthread->kseg) && 1111139023Sdeischen (pthread->active_priority > curthread->active_priority)) 1112139023Sdeischen curthread->critical_yield = 1; 1113116977Sdavidxu THR_SCHED_UNLOCK(curthread, pthread); 1114117907Sdeischen if (kmbx != NULL) 1115117907Sdeischen kse_wakeup(kmbx); 1116116977Sdavidxu /* XXX 1117116977Sdavidxu * If thread sent signal to itself, check signals now. 1118116977Sdavidxu * It is not really needed, _kse_critical_leave should 1119116977Sdavidxu * have already checked signals. 1120116977Sdavidxu */ 1121116977Sdavidxu if (pthread == curthread && curthread->check_pending) 1122116977Sdavidxu _thr_sig_check_pending(curthread); 1123139023Sdeischen 1124116977Sdavidxu } else { 1125116977Sdavidxu THR_SCHED_UNLOCK(curthread, pthread); 112654707Sdeischen } 112754707Sdeischen} 112854707Sdeischen 1129139023Sdeischenstatic inline void 1130139023Sdeischenthr_sigframe_restore(struct pthread *curthread, struct pthread_sigframe *psf) 113135509Sjb{ 1132139023Sdeischen kse_critical_t crit; 1133139023Sdeischen struct kse *curkse; 113413546Sjulian 1135139023Sdeischen THR_THREAD_LOCK(curthread, curthread); 1136139023Sdeischen curthread->cancelflags = psf->psf_cancelflags; 1137139023Sdeischen crit = _kse_critical_enter(); 1138139023Sdeischen curkse = curthread->kse; 1139139023Sdeischen KSE_SCHED_LOCK(curkse, curthread->kseg); 1140139023Sdeischen curthread->flags = psf->psf_flags; 1141139023Sdeischen curthread->interrupted = psf->psf_interrupted; 1142139023Sdeischen curthread->timeout = psf->psf_timeout; 1143139023Sdeischen curthread->data = psf->psf_wait_data; 1144139023Sdeischen curthread->wakeup_time = psf->psf_wakeup_time; 1145139023Sdeischen curthread->continuation = psf->psf_continuation; 1146139023Sdeischen KSE_SCHED_UNLOCK(curkse, curthread->kseg); 1147139023Sdeischen _kse_critical_leave(crit); 1148139023Sdeischen THR_THREAD_UNLOCK(curthread, curthread); 114967097Sdeischen} 115054707Sdeischen 1151139023Sdeischenstatic inline void 1152139023Sdeischenthr_sigframe_save(struct pthread *curthread, struct pthread_sigframe *psf) 115367097Sdeischen{ 1154139023Sdeischen kse_critical_t crit; 1155139023Sdeischen struct kse *curkse; 115667097Sdeischen 1157139023Sdeischen THR_THREAD_LOCK(curthread, curthread); 1158139023Sdeischen psf->psf_cancelflags = curthread->cancelflags; 1159139023Sdeischen crit = _kse_critical_enter(); 1160139023Sdeischen curkse = curthread->kse; 1161139023Sdeischen KSE_SCHED_LOCK(curkse, curthread->kseg); 1162113658Sdeischen /* This has to initialize all members of the sigframe. */ 1163139023Sdeischen psf->psf_flags = (curthread->flags & (THR_FLAGS_PRIVATE | THR_FLAGS_EXITING)); 1164139023Sdeischen psf->psf_interrupted = curthread->interrupted; 1165139023Sdeischen psf->psf_timeout = curthread->timeout; 1166139023Sdeischen psf->psf_wait_data = curthread->data; 1167139023Sdeischen psf->psf_wakeup_time = curthread->wakeup_time; 1168139023Sdeischen psf->psf_continuation = curthread->continuation; 1169139023Sdeischen KSE_SCHED_UNLOCK(curkse, curthread->kseg); 1170139023Sdeischen _kse_critical_leave(crit); 1171139023Sdeischen THR_THREAD_UNLOCK(curthread, curthread); 117267097Sdeischen} 1173116977Sdavidxu 1174116977Sdavidxuvoid 1175116977Sdavidxu_thr_signal_init(void) 1176116977Sdavidxu{ 1177116977Sdavidxu struct sigaction act; 1178117706Sdavidxu __siginfohandler_t *sigfunc; 1179116977Sdavidxu int i; 1180119063Sdavidxu sigset_t sigset; 1181116977Sdavidxu 1182119063Sdavidxu SIGFILLSET(sigset); 1183119063Sdavidxu __sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask); 1184116977Sdavidxu /* Enter a loop to get the existing signal status: */ 1185116977Sdavidxu for (i = 1; i <= _SIG_MAXSIG; i++) { 1186116977Sdavidxu /* Get the signal handler details: */ 1187132122Sdavidxu if (__sys_sigaction(i, NULL, &_thread_sigact[i - 1]) != 0) { 1188116977Sdavidxu /* 1189116977Sdavidxu * Abort this process if signal 1190116977Sdavidxu * initialisation fails: 1191116977Sdavidxu */ 1192116977Sdavidxu PANIC("Cannot read signal handler info"); 1193116977Sdavidxu } 1194117706Sdavidxu /* Intall wrapper if handler was set */ 1195117706Sdavidxu sigfunc = _thread_sigact[i - 1].sa_sigaction; 1196117706Sdavidxu if (((__sighandler_t *)sigfunc) != SIG_DFL && 1197117706Sdavidxu ((__sighandler_t *)sigfunc) != SIG_IGN) { 1198117706Sdavidxu act = _thread_sigact[i - 1]; 1199117706Sdavidxu act.sa_flags |= SA_SIGINFO; 1200118747Sdavidxu act.sa_sigaction = 1201118747Sdavidxu (__siginfohandler_t *)_thr_sig_handler; 1202117706Sdavidxu __sys_sigaction(i, &act, NULL); 1203117706Sdavidxu } 1204116977Sdavidxu } 1205156330Sdeischen if (_thr_dump_enabled()) { 1206116977Sdavidxu /* 1207156330Sdeischen * Install the signal handler for SIGINFO. It isn't 1208156330Sdeischen * really needed, but it is nice to have for debugging 1209156330Sdeischen * purposes. 1210116977Sdavidxu */ 1211156330Sdeischen _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART; 1212156330Sdeischen SIGEMPTYSET(act.sa_mask); 1213156330Sdeischen act.sa_flags = SA_SIGINFO | SA_RESTART; 1214156330Sdeischen act.sa_sigaction = (__siginfohandler_t *)&_thr_sig_handler; 1215156330Sdeischen if (__sys_sigaction(SIGINFO, &act, NULL) != 0) { 1216156330Sdeischen __sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask, 1217156330Sdeischen NULL); 1218156330Sdeischen /* 1219156330Sdeischen * Abort this process if signal initialisation fails: 1220156330Sdeischen */ 1221156330Sdeischen PANIC("Cannot initialize signal handler"); 1222156330Sdeischen } 1223116977Sdavidxu } 1224119063Sdavidxu __sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask, NULL); 1225123974Sdavidxu __sys_sigaltstack(NULL, &_thr_initial->sigstk); 1226116977Sdavidxu} 1227116977Sdavidxu 1228116977Sdavidxuvoid 1229116977Sdavidxu_thr_signal_deinit(void) 1230116977Sdavidxu{ 1231116977Sdavidxu int i; 1232123974Sdavidxu struct pthread *curthread = _get_curthread(); 1233116977Sdavidxu 1234139023Sdeischen /* Clear process pending signals. */ 1235139023Sdeischen sigemptyset(&_thr_proc_sigpending); 1236139023Sdeischen 1237116977Sdavidxu /* Enter a loop to get the existing signal status: */ 1238116977Sdavidxu for (i = 1; i <= _SIG_MAXSIG; i++) { 1239116977Sdavidxu /* Check for signals which cannot be trapped: */ 1240116977Sdavidxu if (i == SIGKILL || i == SIGSTOP) { 1241116977Sdavidxu } 1242116977Sdavidxu 1243116977Sdavidxu /* Set the signal handler details: */ 1244118747Sdavidxu else if (__sys_sigaction(i, &_thread_sigact[i - 1], 1245118747Sdavidxu NULL) != 0) { 1246116977Sdavidxu /* 1247116977Sdavidxu * Abort this process if signal 1248116977Sdavidxu * initialisation fails: 1249116977Sdavidxu */ 1250116977Sdavidxu PANIC("Cannot set signal handler info"); 1251116977Sdavidxu } 1252116977Sdavidxu } 1253123974Sdavidxu __sys_sigaltstack(&curthread->sigstk, NULL); 1254116977Sdavidxu} 1255116977Sdavidxu 1256