sig.c revision f841f6ad96ea6675d6c6b35c749eaac601799fdf
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. 2N/A/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 2N/A/* All Rights Reserved */ 2N/A#
pragma ident "%Z%%M% %I% %E% SMI" 2N/A /* MUST be contiguous */ 2N/A * Internal variables for counting number of user thread stop requests posted. 2N/A * They may not be accurate at some special situation such as that a virtually 2N/A * stopped thread starts to run. 2N/A * Internal variables for broadcasting an event when all thread stop requests 2N/A * Send the specified signal to the specified process. 2N/A * Send the specified signal to the specified thread. 2N/A * Return true if the signal can safely be discarded on generation. 2N/A * That is, if there is no need for the signal on the receiving end. 2N/A * The answer is true if the process is a zombie or 2N/A * if all of these conditions are true: 2N/A * the signal is being ignored 2N/A * the process is single-threaded 2N/A * the signal is not being traced by /proc 2N/A * the signal is not blocked by the process 2N/A return (t ==
NULL ||
/* if zombie or ... */ 2N/A * Return true if this thread is going to eat this signal soon. 2N/A * Note that, if the signal is SIGKILL, we force stopped threads to be 2N/A * set running (to make SIGKILL be a sure kill), but only if the process 2N/A * is not currently locked by /proc (the P_PR_LOCK flag). Code in /proc 2N/A * relies on the fact that a process will not change shape while P_PR_LOCK 2N/A * is set (it drops and reacquires p->p_lock while leaving P_PR_LOCK set). 2N/A * We wish that we could simply call prbarrier() below, in sigtoproc(), to 2N/A * ensure that the process is not locked by /proc, but prbarrier() drops 2N/A * and reacquires p->p_lock and dropping p->p_lock here would be damaging. 2N/A * Do not do anything if the target thread has the signal blocked. 2N/A aston(t);
/* make it do issig promptly */ 2N/A * If a non-null thread pointer is passed, then post the signal 2N/A * to the thread/lwp, otherwise post the signal to the process. 2N/A * Regardless of origin or directedness, 2N/A * SIGKILL kills all lwps in the process immediately 2N/A * and jobcontrol signals affect all lwps in the process. 2N/A * The SSCONT flag will remain set until a stopping 2N/A * signal comes in (below). This is harmless. 2N/A * This test has a race condition which we can't fix: 2N/A * By the time the stopping signal is received by 2N/A * and/or the detached state might have changed. 2N/A * This is a directed signal, wake up the lwp. 2N/A * Make sure that some lwp that already exists 2N/A * in the process fields the signal soon. 2N/A * Wake up an interruptibly sleeping lwp if necessary. 2N/A * If the process is deadlocked, make somebody run and die. 2N/A * If SIGCONT has been posted since we promoted this signal 2N/A * from pending to current, then don't do a jobcontrol stop. 2N/A * Only the first lwp to continue notifies the parent. 2N/A * Returns true if the current process has a signal to process, and 2N/A * the signal is not held. The signal to process is put in p_cursig. 2N/A * This is asked at least once each time a process enters the system 2N/A * (though this can usually be done without actually calling issig by 2N/A * checking the pending signal masks). A signal does not do anything 2N/A * directly to a process; it sets a flag that asks the process to do 2N/A * something to itself. 2N/A * The "why" argument indicates the allowable side-effects of the call: 2N/A * FORREAL: Extract the next pending signal from p_sig into p_cursig; 2N/A * stop the process if a stop has been requested or if a traced signal 2N/A * JUSTLOOKING: Don't stop the process, just indicate whether or not 2N/A * a signal might be pending (FORREAL is needed to tell for sure). 2N/A * XXX: Changes to the logic in these routines should be propagated 2N/A * to lm_sigispending(). See bug 1201594. 2N/A * This function answers the question: 2N/A * "Is there any reason to call issig_forreal()?" 2N/A * We have to answer the question w/o grabbing any locks 2N/A * because we are (most likely) being called after we 2N/A * put ourselves on the sleep queue. 2N/A * Another piece of complexity in this process. When single-stepping a 2N/A * process, we don't want an intervening signal or TP_PAUSE request to 2N/A * suspend the current thread. Otherwise, the controlling process will 2N/A * hang beacuse we will be stopped with TS_PSTART set in t_schedflag. 2N/A * We will trigger any remaining signals when we re-enter the kernel on 2N/A * the single step trap. 2N/A * Don't promote a signal that will stop 2N/A * the process when lwp_nostop is set. * If DTrace's "stop" action has been invoked on us, * Post the signal generated as the result of * DTrace's "raise" action as a normal signal before * the full-fledged signal checking begins. * Another piece of complexity in this process. When * single-stepping a process, we don't want an intervening * signal or TP_PAUSE request to suspend the current thread. * Otherwise, the controlling process will hang beacuse we will * be stopped with TS_PSTART set in t_schedflag. We will * trigger any remaining signals when we re-enter the kernel on * Hold the lwp here for watchpoint manipulation. * Make sure we call ISSIG() in post_syscall() * to re-validate this current signal. * If the request is PR_CHECKPOINT, ignore the rest of signals * or requests. Honor other stop requests or signals later. * Go back to top of loop here to check if an exit or hold * event has occurred while stopped. * Honor SHOLDFORK1, SHOLDWATCH, and TP_HOLDLWP before dealing * with signals or /proc. Another lwp is executing fork1(), * or is undergoing watchpoint activity (remapping a page), * or is executing lwp_suspend() on this lwp. * Again, go back to top of loop to check if an exit * or hold event has occurred while stopped. * We explicitly allow this form of stopping of one * lwp in a process by another lwp in the same process, * even if lwp->lwp_nostop is set, because otherwise a * process can become deadlocked on a fork1(). * Allow this only if lwp_nostop_r is not set, * to avoid a recursive call to prstop(). * Honor requested stop before dealing with the * current signal; a debugger may change it. * Do not want to go back to loop here since this is a special * stop that means: make incremental progress before the next * stop. The danger is that returning to top of loop would most * likely drop the thread right back here to stop soon after it * was continued, violating the incremental progress request. * If a debugger wants us to take a signal it will have * left it in lwp->lwp_cursig. If lwp_cursig has been cleared * or if it's being ignored, we continue on looking for another * signal. Otherwise we return the specified signal, provided * it's not a signal that causes a job control stop. * When stopped on PR_JOBCONTROL, there is no current * signal; we cancel lwp->lwp_cursig temporarily before * calling isjobstop(). The current signal may be reset * by a debugger while we are stopped in isjobstop(). * The signal is being ignored or it caused a * job-control stop. If another current signal * has not been established, return the current * siginfo, if any, to the memory manager. * Loop around again in case we were stopped * on a job control signal and a /proc stop * request was posted or another current signal * was established while we were stopped. * Some lwp in the process has already stopped * showing PR_JOBCONTROL. This is a stop in * sympathy with the other lwp, even if this * lwp is blocking the stopping signal. * Loop on the pending signals until we find a * non-held signal that is traced or not ignored. * First check the signals pending for the lwp, * then the signals pending for the process as a whole. /* no signal was found */ if (
sig == 0) {
/* no signal was found */ * If we have been informed not to stop (i.e., we are being * called from within a network operation), then don't promote * the signal at this time, just return the signal number. * We will call issig() again later when it is safe. * fsig() does not return a jobcontrol stopping signal * with a default action of stopping the process if * lwp_nostop is set, so we won't be causing a bogus * EINTR by this action. (Such a signal is eaten by * isjobstop() when we loop around to do final checks.) * Promote the signal from pending to current. * Note that sigdeq() will set lwp->lwp_curinfo to NULL * if no siginfo_t exists for this signal. t->
t_sig_check =
1;
/* so post_syscall will see signal */ * Loop around to check for requested stop before * performing the usual current-signal actions. * If SIGCLD was dequeued, search for other pending SIGCLD's. * Don't do it if we are returning SIGCLD and the signal * handler will be reset by psig(); this enables reliable * delivery of SIGCLD even when using the old, broken * signal() interface for setting the signal handler. * If we have been blocked since the p_lock was dropped off * above, then this promoted signal might have been handled * already when we were on the way back from sleep queue, so * If we have been informed not to stop, just return the signal * number. Also see comments above. * Return true if the process is currently stopped showing PR_JOBCONTROL. * This is true only if all of the process's lwp's are so stopped. * If this is asked by one of the lwps in the process, exclude that lwp. /* ignore current, zombie and suspended lwps in the test */ * Put ourself (curthread) into the stopped state and notify tracers. * Can't stop a system process. * Don't stop an lwp with SIGKILL pending. * Don't stop if the process or lwp is exiting. * Make sure we don't deadlock on a recursive call to prstop(). * prstop() sets the lwp_nostop_r flag and increments lwp_nostop. * Make sure the lwp is in an orderly state for inspection * by a debugger through /proc or for dumping via core(). * The situation may have changed since we dropped * and reacquired p->p_lock. Double-check now * whether we should stop or not. * The situation may have changed since we dropped * and reacquired p->p_lock. Double-check now * whether we should stop or not. * If SHOLDFORK is in effect and we are stopping * while asleep (not at the top of the stack), * we return now to allow the hold to take effect * when we reach the top of the kernel stack. default:
/* /proc stop */ * Do synchronous stop unless the async-stop flag is set. * If why is PR_REQUESTED and t->t_dtrace_stop flag is set, * then no debugger is present and we also do synchronous stop. * Don't actually wake it up if it's * in one of the lwp_*() syscalls. * Mark it virtually stopped and * notify /proc waiters (below). * force the thread into the kernel * if it is not already there. * We do this just in case one of the threads we asked * to stop is in holdlwps() (called from cfork()) or * Determine if the whole process is jobstopped. * The last lwp to stop notifies the parent. * Turn off the CLDCONT flag now so the first * lwp to continue knows what to do. * Grab p->p_lock before releasing pidlock so the * parent and the child don't have a race condition. * Set p->p_stopsig and wake up sleeping lwps * so they will stop in sympathy with this lwp. * We do this just in case one of the threads we asked * to stop is in holdlwps() (called from cfork()) or * Do process-level notification when all lwps are * either stopped on events of interest to /proc * or are stopped showing PR_SUSPENDED or are zombies. /* neither ISTOPPED nor SUSPENDED? */ /* not paused for watchpoints? */ /* there must not be any remapped watched pages now */ /* ptrace() compatibility */ * Grab p->p_lock before releasing pidlock so * parent and child don't have a race condition. * Special notification for creation of the agent lwp. * The situation may have changed since we dropped * and reacquired p->p_lock. Double-check now * whether we should stop or not. * We always broadcast in the case of SUSPEND_PAUSE. This is * because checks for TP_PAUSE take precedence over checks for * SHOLDWATCH. If a thread is trying to stop because of * SUSPEND_PAUSE and tries to do a holdwatch(), it will be * waiting for the rest of the threads to enter a stopped state. * If we are stopping for a SUSPEND_PAUSE, we may be the last * lwp and not know it, so broadcast just in case. * Need to do this here (rather than after the thread is officially * stopped) because we can't call mutex_enter from a stopped thread. * We may have gotten a SIGKILL or a SIGCONT when * we released p->p_lock; make one last check. * Also check for a /proc run-on-last-close. * This resulted from a SIGCONT posted * while we were not holding p->p_lock. * This resulted from a /proc run-on-last-close. setallwatch();
/* reestablish any watchpoints set while stopped */ prbarrier(p);
/* barrier against /proc locking */ /* Interface for resetting user thread stop count. */ /* Interface for registering a user thread stop request. */ /* Interface for cancelling a user thread stop request */ /* Interface to wait for all user threads to be stopped */ * Perform the action specified by the current signal. * The signal bit has already been cleared by issig(), * the current signal number has been stored in lwp_cursig, * and the current siginfo is now referenced by lwp_curinfo. return;
/* not reached */ * Re-check lwp_cursig after we acquire p_lock. Since p_lock was * dropped between issig() and psig(), a debugger may have cleared * lwp_cursig via /proc in the intervening window. * The signal disposition could have changed since we promoted * this signal from pending to current (we dropped p->p_lock). * This can happen only in a multi-threaded process. * We check lwp_curinfo first since pr_setsig can actually * stuff a sigqueue_t there for SIGKILL. * If we have a sigqueue_t, its sq_external value * trumps the lwp_extsig value. It is theoretically * possible to make lwp_extsig reflect reality, but it * would unnecessarily complicate things elsewhere. * If DTrace user-land tracing is active, give DTrace a * chance to defer the signal until after tracing is * save siginfo pointer here, in case the * the signal's reset bit is on * The presence of a current signal prevents paging * from succeeding over a network. We copy the current * signal information to the side and cancel the current * signal so that sendsig() will succeed. /* p->p_killsqp is freed by freeproc */ #
endif /* _SYSCALL32_IMPL */ ext = 0;
/* lwp_extsig was set above */ * Terminate all LWPs but don't discard them. * If another lwp beat us to the punch by calling exit(), /* if we got a SIGKILL from anywhere, no core dump */ * Find next unheld signal in ssp for thread t. * Don't promote any signals for the parent of a vfork()d * child that hasn't yet released the parent's memory. * Don't promote stopping signals (except SIGSTOP) for a child * of vfork() that hasn't yet released the parent's memory. * Don't promote a signal that will stop * the process when lwp_nostop is set. * Choose SIGKILL and SIGPROF before all other pending signals. * The rest are promoted in signal number order. * Honor the SA_SIGINFO flag if the signal is being caught. * Force the SA_SIGINFO flag if the signal is not being caught. * This is necessary to make sigqueue() and sigwaitinfo() work * properly together when the signal is set to default or is * being temporarily ignored. * Setting the signal action to SIG_IGN results in the * discarding of all pending signals of that signal number. * Setting the signal action to SIG_DFL does the same *only* * if the signal's default behavior is to be ignored. * The signal action is being set to SIG_DFL and the default * behavior is to do something: make sure it is not ignored. * Set all signal actions not already set to SIG_DFL or SIG_IGN to SIG_DFL. * Called from exec_common() for a process undergoing execve() * and from cfork() for a newly-created child of vfork(). * In the vfork() case, 'p' is not the current process. * In both cases, there is only one thread in the process. * The broadcast on p_srwchan_cv is a kludge to * wakeup a possible thread in uadmin(A_SHUTDOWN). * Add to newstate list of the parent * Common code called from sigcld() and issig_forreal() * Give the parent process a SIGCLD if it does not have one pending, * else mark the child process so a SIGCLD can be posted later. * If a SIGCLD is pending, or if SIGCLD is not now being caught, * then just mark the child process so that its SIGCLD will * be posted later, when the first SIGCLD is taken off the * queue or when the parent is ready to receive it, if ever. * This can only happen when the parent is init. * (See call to sigcld(q, NULL) in exit().) * Use KM_NOSLEEP to avoid deadlock. * Search for a child that has a pending SIGCLD for us, the parent. * The queue of SIGCLD signals is implied by the list of children. * We post the SIGCLD signals one at a time so they don't get lost. * When one is dequeued, another is enqueued, until there are no more. * Don't bother if SIGCLD is not now being caught. * count number of sigqueue send by sigaddqa() /* Make sure we should be setting si_pid and friends */ * XXX: Should be KM_SLEEP but * we have to avoid deadlock. * Dequeue a queued siginfo structure. * If a non-null thread pointer is passed then dequeue from * the thread queue, otherwise dequeue from the process queue. * Delete a queued SIGCLD siginfo structure matching the k_siginfo_t argument. * Delete queued siginfo structures. * If a non-null thread pointer is passed then delete from * the thread queue, otherwise delete from the process queue. * We must be holding p->p_lock unless the process is * being reaped or has failed to get started on fork. * Insert a siginfo structure into a queue. * If a non-null thread pointer is passed then add to the thread queue, * otherwise add to the process queue. * The function sigaddqins() is called with sigqueue already allocated. * It is called from sigaddqa() and sigaddq() below. * The value of si_code implicitly indicates whether sigp is to be * explicitly queued, or to be queued to depth one. * issig_forreal() doesn't bother dequeueing signals if SKILLED * is set, and even if it did, we would want to avoid situation * (which would be unique to SIGKILL) where one thread dequeued * the sigqueue_t and another executed psig(). So we create a * separate stash for SIGKILL's sigqueue_t. Because a second * SIGKILL can set SEXTKILLED, we overwrite the existing entry * if (and only if) it was non-extracontractual. if (t !=
NULL)
/* directed to a thread */ else /* directed to a process */ * The function sigaddqa() is called with sigqueue already allocated. * If signal is ignored, discard but guarantee KILL and generation semantics. * It is called from sigqueue() and other places. * Allocate the sigqueue_t structure and call sigaddqins(). * If the signal will be discarded by sigtoproc() or * if the process isn't requesting siginfo and it isn't * blocking the signal (it *could* change it's mind while * the signal is pending) then don't bother creating one. * Handle stop-on-fault processing for the debugger. Returns 0 * if the fault is cleared during the stop, nonzero if it isn't. * Record current fault and siginfo structure so debugger can * Return non-zero if curthread->t_sig_check should be set to 1, that is, * if there are any signals the thread might take on return from the kernel. * If ksigset_t's were a single word, we would do: * return (((p->p_sig | t->t_sig) & ~t->t_hold) & fillset); * If signals are blocked via the schedctl interface * then we only check for the unmaskable signals. /* ONC_PLUS EXTRACT START */ * Mask out all signals except SIGHUP, SIGINT, SIGQUIT * and SIGTERM. (Preserving the existing masks). * This function supports the -intr nfs and ufs mount option. * don't do kernel threads * get access to signal mask * remember the current mask * Unmask the non-maskable signals (e.g., KILL), as long as * they aren't already masked (which could happen at exit). * The first sigdiffset sets lmask to (cantmask & ~curhold). The * second sets the current hold mask to (~0 & ~lmask), which reduces * to (~cantmask | curhold). * Re-enable HUP, QUIT, and TERM iff they were originally enabled * Re-enable INT if it's originally enabled and the NFS mount option * release access to signal mask * Indicate that this lwp is not to be stopped. /* ONC_PLUS EXTRACT END */ * Reset previous mask (See sigintr() above) /* so unmasked signals will be seen */ * Save current signal mask in oldmask, then * Return true if the signal number is in range * and the signal code specifies signal queueing. * The entire pool (with maxcount entries) is pre-allocated at * Return a sigqueue structure back to the pre-allocated pool. /* make sure that p_lock of the affected process is held */ * Free up the pre-allocated sigqueue headers of sigqueue pool * and signotify pool, if possible. * Called only by the owning process during exec() and exit(). * Free up the pre-allocated header and sigq pool if possible. * Free up a single sigqueue structure. * No other code should free a sigqueue directly. * Generate a synchronous signal caused by a hardware * condition encountered by an lwp. Called from trap(). * Avoid a possible infinite loop if the lwp is holding the * signal generated by a trap of a restartable instruction or * if the signal so generated is being ignored by the process. * It's tricky to transmit a sigval between 32-bit and 64-bit * process, since in the 64-bit world, a pointer and an integer * are different sizes. Since we're constrained by the standards * world not to change the types, and it's unclear how useful it is * to send pointers between address spaces this way, we preserve * the 'int' interpretation for 32-bit processes interoperating * with 64-bit processes. The full semantics (pointers or integers) * are available for N-bit processes interoperating with N-bit * The absolute minimum content is si_signo and si_code. * A siginfo generated by user level is structured * differently from one generated by the kernel. * The absolute minimum content is si_signo and si_code. * A siginfo generated by user level is structured * differently from one generated by the kernel. #
endif /* _SYSCALL32_IMPL */