static void Abort(const char *msg) { ulwp_t *self; struct sigaction act; sigset_t sigmask; lwpid_t lwpid; /* to help with core file debugging */ panicstr = msg; if ((self = __curthread()) != NULL) { panic_thread = self; lwpid = self->ul_lwpid; } else { lwpid = _lwp_self(); } /* set SIGABRT signal handler to SIG_DFL w/o grabbing any locks */ (void) memset(&act, 0, sizeof (act)); act.sa_sigaction = SIG_DFL; (void) __sigaction(SIGABRT, &act, NULL); /* delete SIGABRT from the signal mask */ (void) sigemptyset(&sigmask); (void) sigaddset(&sigmask, SIGABRT); (void) __lwp_sigmask(SIG_UNBLOCK, &sigmask); (void) _lwp_kill(lwpid, SIGABRT); /* never returns */ (void) kill(getpid(), SIGABRT); /* if it does, try harder */ _exit(127); }
/* * Tell the kernel to block all signals. * Use the schedctl interface, or failing that, use __lwp_sigmask(). * This action can be rescinded only by making a system call that * sets the signal mask: * __lwp_sigmask(), __sigprocmask(), __setcontext(), * __sigsuspend() or __pollsys(). * In particular, this action cannot be reversed by assigning * scp->sc_sigblock = 0. That would be a way to lose signals. * See the definition of restore_signals(self). */ void block_all_signals(ulwp_t *self) { volatile sc_shared_t *scp; enter_critical(self); if ((scp = self->ul_schedctl) != NULL || (scp = setup_schedctl()) != NULL) scp->sc_sigblock = 1; else (void) __lwp_sigmask(SIG_SETMASK, &maskset); exit_critical(self); }
static int perform_flag_actions(spawn_attr_t *sap) { int sig; struct sigaction action; if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) { (void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask); } if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) { (void) memset(&action, 0, sizeof (action)); action.sa_handler = SIG_IGN; for (sig = 1; sig < NSIG; sig++) { if (sigismember(&sap->sa_sigignore, sig)) (void) __sigaction(sig, &action, NULL); } } if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) { (void) memset(&action, 0, sizeof (action)); action.sa_handler = SIG_DFL; for (sig = 1; sig < NSIG; sig++) { if (sigismember(&sap->sa_sigdefault, sig)) (void) __sigaction(sig, &action, NULL); } } if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) { if (setgid(getgid()) != 0 || setuid(getuid()) != 0) return (errno); } if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) { if (setpgid(0, sap->sa_pgroup) != 0) return (errno); } if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) { if (setparam(P_LWPID, P_MYID, sap->sa_schedpolicy, sap->sa_priority) == -1) return (errno); } else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) { if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1) return (errno); } return (0); }
/* * Common code for calling the user-specified signal handler. */ void call_user_handler(int sig, siginfo_t *sip, ucontext_t *ucp) { ulwp_t *self = curthread; uberdata_t *udp = self->ul_uberdata; struct sigaction uact; volatile struct sigaction *sap; /* * If we are taking a signal while parked or about to be parked * on __lwp_park() then remove ourself from the sleep queue so * that we can grab locks. The code in mutex_lock_queue() and * cond_wait_common() will detect this and deal with it when * __lwp_park() returns. */ unsleep_self(); set_parking_flag(self, 0); if (__td_event_report(self, TD_CATCHSIG, udp)) { self->ul_td_evbuf.eventnum = TD_CATCHSIG; self->ul_td_evbuf.eventdata = (void *)(intptr_t)sig; tdb_event(TD_CATCHSIG, udp); } /* * Get a self-consistent set of flags, handler, and mask * while holding the sig's sig_lock for the least possible time. * We must acquire the sig's sig_lock because some thread running * in sigaction() might be establishing a new signal handler. * The code in sigaction() acquires the writer lock; here * we acquire the readers lock to ehance concurrency in the * face of heavy signal traffic, such as generated by java. * * Locking exceptions: * No locking for a child of vfork(). * If the signal is SIGPROF with an si_code of PROF_SIG, * then we assume that this signal was generated by * setitimer(ITIMER_REALPROF) set up by the dbx collector. * If the signal is SIGEMT with an si_code of EMT_CPCOVF, * then we assume that the signal was generated by * a hardware performance counter overflow. * In these cases, assume that we need no locking. It is the * monitoring program's responsibility to ensure correctness. */ sap = &udp->siguaction[sig].sig_uaction; if (self->ul_vfork || (sip != NULL && ((sig == SIGPROF && sip->si_code == PROF_SIG) || (sig == SIGEMT && sip->si_code == EMT_CPCOVF)))) { /* we wish this assignment could be atomic */ (void) memcpy(&uact, (void *)sap, sizeof (uact)); } else { rwlock_t *rwlp = &udp->siguaction[sig].sig_lock; lrw_rdlock(rwlp); (void) memcpy(&uact, (void *)sap, sizeof (uact)); if ((sig == SIGCANCEL || sig == SIGAIOCANCEL) && (sap->sa_flags & SA_RESETHAND)) sap->sa_sigaction = SIG_DFL; lrw_unlock(rwlp); } /* * Set the proper signal mask and call the user's signal handler. * (We overrode the user-requested signal mask with maskset * so we currently have all blockable signals blocked.) * * We would like to ASSERT() that the signal is not a member of the * signal mask at the previous level (ucp->uc_sigmask) or the specified * signal mask for sigsuspend() or pollsys() (self->ul_tmpmask) but * /proc can override this via PCSSIG, so we don't bother. * * We would also like to ASSERT() that the signal mask at the previous * level equals self->ul_sigmask (maskset for sigsuspend() / pollsys()), * but /proc can change the thread's signal mask via PCSHOLD, so we * don't bother with that either. */ ASSERT(ucp->uc_flags & UC_SIGMASK); if (self->ul_sigsuspend) { ucp->uc_sigmask = self->ul_sigmask; self->ul_sigsuspend = 0; /* the sigsuspend() or pollsys() signal mask */ sigorset(&uact.sa_mask, &self->ul_tmpmask); } else { /* the signal mask at the previous level */ sigorset(&uact.sa_mask, &ucp->uc_sigmask); } if (!(uact.sa_flags & SA_NODEFER)) /* add current signal */ (void) sigaddset(&uact.sa_mask, sig); self->ul_sigmask = uact.sa_mask; self->ul_siglink = ucp; (void) __lwp_sigmask(SIG_SETMASK, &uact.sa_mask); /* * If this thread has been sent SIGCANCEL from the kernel * or from pthread_cancel(), it is being asked to exit. * The kernel may send SIGCANCEL without a siginfo struct. * If the SIGCANCEL is process-directed (from kill() or * sigqueue()), treat it as an ordinary signal. */ if (sig == SIGCANCEL) { if (sip == NULL || SI_FROMKERNEL(sip) || sip->si_code == SI_LWP) { do_sigcancel(); goto out; } /* SIGCANCEL is ignored by default */ if (uact.sa_sigaction == SIG_DFL || uact.sa_sigaction == SIG_IGN) goto out; } /* * If this thread has been sent SIGAIOCANCEL (SIGLWP) and * we are an aio worker thread, cancel the aio request. */ if (sig == SIGAIOCANCEL) { aio_worker_t *aiowp = pthread_getspecific(_aio_key); if (sip != NULL && sip->si_code == SI_LWP && aiowp != NULL) siglongjmp(aiowp->work_jmp_buf, 1); /* SIGLWP is ignored by default */ if (uact.sa_sigaction == SIG_DFL || uact.sa_sigaction == SIG_IGN) goto out; } if (!(uact.sa_flags & SA_SIGINFO)) sip = NULL; __sighndlr(sig, sip, ucp, uact.sa_sigaction); #if defined(sparc) || defined(__sparc) /* * If this is a floating point exception and the queue * is non-empty, pop the top entry from the queue. This * is to maintain expected behavior. */ if (sig == SIGFPE && ucp->uc_mcontext.fpregs.fpu_qcnt) { fpregset_t *fp = &ucp->uc_mcontext.fpregs; if (--fp->fpu_qcnt > 0) { unsigned char i; struct fq *fqp; fqp = fp->fpu_q; for (i = 0; i < fp->fpu_qcnt; i++) fqp[i] = fqp[i+1]; } } #endif /* sparc */ out: (void) setcontext(ucp); thr_panic("call_user_handler(): setcontext() returned"); }