Examine or specify the action associated with a signal
#include <signal.h> int sigaction( int sig, const struct sigaction * act, struct sigaction * oact );
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
You can use sigaction() to examine or specify (or both) the action that's associated with a specific signal:
The structure sigaction contains the following members:
The sa_handler and sa_sigaction members of act are implemented as a union and share common storage. They differ only in their prototypes, with sa_handler being used for POSIX 1003.1a signals and sa_sigaction being used for POSIX 1003.1b queued realtime signals. The values stored using either name can be one of:
The function member of sa_handler or sa_sigaction is always invoked with the following arguments:
void handler(int signo, siginfo_t *info, void *other)
If you have an old-style signal handler of the form:
void handler(int signo)
the extra arguments are still placed by the kernel, but the function simply ignores them.
While in the handler, signo is masked, preventing nested signals of the same type. In addition, any signals set in the sa_mask member of act are also ORed into the mask. When the handler returns through a normal return, the previous mask is restored and any pending and now unmasked signals are acted on. You return to the point in the program where it was interrupted. If the thread was blocked in the kernel when the interruption occurred, the kernel call returns with an EINTR (see ChannelCreate() and SyncMutexLock() for exceptions to this).
It isn't safe to use floating-point operations in signal handlers. |
The siginfo_t structure of the function in sa_handler or sa_sigaction contains at least the following members:
You can't ignore or catch SIGKILL or SIGSTOP.
Signal handlers and actions are defined for the process and affect all threads in the process. For example, if one thread ignores a signal, then all threads ignore the signal.
You can target a signal at a thread, process, or process group (see SignalKill()). When targeted at a process, at most one thread receives the signal. This thread must have the signal unblocked (see SignalProcmask()) to be a candidate for receiving it. All synchronously generated signals (e.g. SIGSEGV) are always delivered to the thread that caused them.
If you use longjmp() to return from a signal handler, the signal remains masked. You can use siglongjmp() to restore the mask to the state saved by a previous call to sigsetjmp(). |
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> int main( void ) { extern void handler(); struct sigaction act; sigset_t set; sigemptyset( &set ); sigaddset( &set, SIGUSR1 ); sigaddset( &set, SIGUSR2 ); /* * Define a handler for SIGUSR1 such that when * entered both SIGUSR1 and SIGUSR2 are masked. */ act.sa_flags = 0; act.sa_mask = set; act.sa_handler = &handler; sigaction( SIGUSR1, &act, NULL ); kill( getpid(), SIGUSR1 ); /* Program will terminate with a SIGUSR2 */ return EXIT_SUCCESS; } void handler( signo ) { static int first = 1; if( first ) { first = 0; kill( getpid(), SIGUSR1 ); /* Prove signal masked */ kill( getpid(), SIGUSR2 ); /* Prove signal masked */ } } /* * - SIGUSR1 is set from main(), handler() is called. * - SIGUSR1 and SIGUSR2 are set from handler(). * - however, signals are masked until we return to main(). * - returning to main() unmasks SIGUSR1 and SIGUSR2. * - pending SIGUSR1 now occurs, handler() is called. * - pending SIGUSR2 now occurs. Since we don't have * a handler for SIGUSR2, we are killed. */
Safety: | |
---|---|
Cancellation point | No |
Interrupt handler | No |
Signal handler | Yes |
Thread | Yes |
errno, kill(), pthread_sigmask(), raise(), sigaddset(), sigdelset(), sigemptyset(), sigfillset(), sigismember(), signal(), SignalAction(), SignalKill(), sigpending(), sigprocmask()