[Previous] [Contents] [Next]

sigaction()

Examine or specify the action associated with a signal

Synopsis:

#include <signal.h>

int sigaction( int sig,
               const struct sigaction * act,
               struct sigaction * oact );

Library:

libc

Description:

The sigaction() function allows the calling process to examine or specify (or both) the action to be associated with a specific signal. The sig argument specifies the signal (defined in <signal.h>).

If act isn't NULL then the specified signal is modified. If oact isn't NULL, the previous action is stored in the structure it points to. The combination of act and oact allows you to query or set (or both) the action for a signal.

The structure sigaction contains the following members:

void (*sa_handler)();
Address of a signal handler or action for nonqueued signals.
void (*sa_sigaction)(int signo, siginfo_t* info, void* other);
Address of a signal handler or action for queued signals.
sigset_t sa_mask
An additional set of signals to be masked (blocked) during execution of the signal-catching function.
int sa_flags
Special flags to affect behavior of the signal. There are two flags, SA_NOCLDSTOP and SA_SIGINFO, that are defined below.

The sa_handler and sa_sigaction members of act are implemented as a union and share common storage. They only differ in their prototype 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:

function
The address of a signal catching function. See below for details.
SIG_DFL
This sets the signal to the default action. The default action for SIGCHLD, SIGIO, SIGURG and SIGWINCH is to ignore the signal (SIG_IGN). The default action for SIG_HOLD is to stop the process. The default action for SIGCONT is to continue the program. The default for all other signals is to kill the process.
SIG_IGN
This ignores the signal. Setting SIG_IGN for a signal that's pending discards all pending signals, whether it's blocked or not. New signals are discarded. If you ignore SIGCHLD, your children won't enter the zombie state and you're unable to wait on their death using wait() or waitpid().

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, 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).

The siginfo_t structure of the function in sa_handler or sa_sigaction contains at least the following members:

Member Description
int si_signo The signal number, which should match the signo argument to the handler.
int si_code A signal code. The code is provided by the generator of the signal.
union sigval si_value A value associated with the signal. The value is provided by the generator of the signal.

Some of the common si_code values defined by POSIX are:

Signal Description
SI_USER Signal generated by kill() function
SI_QUEUE Signal generated by sigqueue() function
SI_TIMER Signal generated by a timer
SI_ASYNCIO Signal generated by asynchronous IO
SI_MESGQ Signal generated by POSIX (not QNX) messages queues

You can't ignore or catch SIGKILL or SIGSTOP.

The sa_flags member of act contains flags that modify the behavior of the signal. There are two defined flags:

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.

A signal can be targeted 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 (i.e. SIGSEGV) are always delivered to the thread that caused them.


Note: 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().

Returns:

0
Success.
-1
An error occurred (errno is set).

Errors:

EAGAIN
Insufficient system resources are available to set up the signal's action.
EFAULT
A fault occurred trying to access the buffers provided.
EINVAL
The signal signo isn't valid.

Examples:

#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;

    printf( "Enter handler with signal %d.\n", signo );
    if( first ) {
      first = 0;
      kill( getpid(), SIGUSR1 );  /* Prove signal masked */
      kill( getpid(), SIGUSR2 );  /* Prove signal masked */
    }
    printf( "End signal handler.\n" );
  }

/*
 * - 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.
 */

Classification:

POSIX 1003.1

Safety:
Cancellation point No
Interrupt handler No
Signal handler Yes
Thread Yes

See also:

errno, kill(), raise(), sigaddset(), sigdelset(), sigemptyset(), sigfillset(), sigismember(), signal(), SignalKill(), sigpending(), sigprocmask()


[Previous] [Contents] [Next]