Team BBL
Previous Page Next Page

10.14. sigaction Function

The sigaction function allows us to examine or modify (or both) the action associated with a particular signal. This function supersedes the signal function from earlier releases of the UNIX System. Indeed, at the end of this section, we show an implementation of signal using sigaction.

#include <signal.h>

int sigaction(int signo, const struct sigaction
 *restrict act,
              struct sigaction *restrict oact);

Returns: 0 if OK, 1 on error


The argument signo is the signal number whose action we are examining or modifying. If the act pointer is non-null, we are modifying the action. If the oact pointer is non-null, the system returns the previous action for the signal through the oact pointer. This function uses the following structure:

     struct sigaction {
       void      (*sa_handler)(int);   /* addr of signal handler, */
                                       /* or SIG_IGN, or SIG_DFL */
       sigset_t sa_mask;               /* additional signals to block */
       int      sa_flags;              /* signal options, Figure 10.16 */

       /* alternate handler */
       void     (*sa_sigaction)(int, siginfo_t *, void *);
    };

When changing the action for a signal, if the sa_handler field contains the address of a signal-catching function (as opposed to the constants SIG_IGN or SIG_DFL), then the sa_mask field specifies a set of signals that are added to the signal mask of the process before the signal-catching function is called. If and when the signal-catching function returns, the signal mask of the process is reset to its previous value. This way, we are able to block certain signals whenever a signal handler is invoked. The operating system includes the signal being delivered in the signal mask when the handler is invoked. Hence, we are guaranteed that whenever we are processing a given signal, another occurrence of that same signal is blocked until we're finished processing the first occurrence. Recall from Section 10.8 that additional occurrences of the same signal are usually not queued. If the signal occurs five times while it is blocked, when we unblock the signal, the signal-handling function for that signal will usually be invoked only one time.

Once we install an action for a given signal, that action remains installed until we explicitly change it by calling sigaction. Unlike earlier systems with their unreliable signals, POSIX.1 requires that a signal handler remain installed until explicitly changed.

The sa_flags field of the act structure specifies various options for the handling of this signal. Figure 10.16 details the meaning of these options when set. The SUS column contains • if the flag is defined as part of the base POSIX.1 specification, and XSI if it is defined as an XSI extension to the base.

Figure 10.16. Option flags (sa_flags) for the handling of each signal

Option

SUS

FreeBSD 5.2.1

Linux 2.4.22

Mac OS X 10.3

Solaris 9

Description

SA_INTERRUPT

  

  

System calls interrupted by this signal are not automatically restarted (the XSI default for sigaction). See Section 10.5 for more information.

SA_NOCLDSTOP

If signo is SIGCHLD, do not generate this signal when a child process stops (job control). This signal is still generated, of course, when a child terminates (but see the SA_NOCLDWAIT option below). As an XSI extension, SIGCHLD won't be sent when a stopped child continues if this flag is set.

SA_NOCLDWAIT

XSI

If signo is SIGCHLD, this option prevents the system from creating zombie processes when children of the calling process terminate. If it subsequently calls wait, the calling process blocks until all its child processes have terminated and then returns 1 with errno set to ECHILD. (Recall Section 10.7.)

SA_NODEFER

XSI

When this signal is caught, the signal is not automatically blocked by the system while the signal-catching function executes (unless the signal is also included in sa_mask). Note that this type of operation corresponds to the earlier unreliable signals.

SA_ONSTACK

XSI

If an alternate stack has been declared with sigaltstack(2), this signal is delivered to the process on the alternate stack.

SA_RESETHAND

XSI

The disposition for this signal is reset to SIG_DFL, and the SA_SIGINFO flag is cleared on entry to the signal-catching function. Note that this type of operation corresponds to the earlier unreliable signals. The disposition for the two signals SIGILL and SIGTRAP can't be reset automatically, however. Setting this flag causes sigaction to behave as if SA_NODEFER is also set.

SA_RESTART

XSI

System calls interrupted by this signal are automatically restarted. (Refer to Section 10.5.)

SA_SIGINFO

This option provides additional information to a signal handler: a pointer to a siginfo structure and a pointer to an identifier for the process context.


The sa_sigaction field is an alternate signal handler used when the SA_SIGINFO flag is used with sigaction. Implementations might use the same storage for both the sa_sigaction field and the sa_handler field, so applications can use only one of these fields at a time.

Normally, the signal handler is called as

   void handler(int signo);

but if the SA_SIGINFO flag is set, the signal handler is called as

   void handler(int signo, siginfo_t *info, void *context);

The siginfo_t structure contains information about why the signal was generated. An example of what it might look like is shown below. All POSIX.1-compliant implementations must include at least the si_signo and si_code members. Additionally, implementations that are XSI compliant contain at least the following fields:

    struct siginfo {
      int    si_signo;  /* signal number */
      int    si_errno;  /* if nonzero, errno value from <errno.h> */
      int    si_code;   /* additional info (depends on signal) */
      pid_t  si_pid;    /* sending process ID */
      uid_t  si_uid;    /* sending process real user ID */
      void  *si_addr;   /* address that caused the fault */
      int    si_status; /* exit value or signal number */
      long   si_band;   /* band number for SIGPOLL */
      /* possibly other fields also */
    };

Figure 10.17 shows values of si_code for various signals, as defined by the Single UNIX Specification. Note that implementations may define additional code values.

Figure 10.17. siginfo_t code values

Signal

Code

Reason

 

ILL_ILLOPC

illegal opcode

 

ILL_ILLOPN

illegal operand

 

ILL_ILLADR

illegal addressing mode

SIGILL

ILL_ILLTRP

illegal trap

 

ILL_PRVOPC

privileged opcode

 

ILL_PRVREG

privileged register

 

ILL_COPROC

coprocessor error

 

ILL_BADSTK

internal stack error

 

FPE_INTDIV

integer divide by zero

 

FPE_INTOVF

integer overflow

 

FPE_FLTDIV

floating-point divide by zero

 

FPE_FLTOVF

floating-point overflow

SIGFPE

FPE_FLTUND

floating-point underflow

 

FPE_FLTRES

floating-point inexact result

 

FPE_FLTINV

invalid floating-point operation

 

FPE_FLTSUB

subscript out of range

SIGSEGV

SEGV_MAPERR

address not mapped to object

 

SEGV_ACCERR

invalid permissions for mapped object

 

BUS_ADRALN

invalid address alignment

SIGBUS

BUS_ADRERR

nonexistent physical address

 

BUS_OBJERR

object-specific hardware error

 

trAP_BRKPT

process breakpoint trap

SIGTRAP

TRAP_TRACE

process trace trap

 

CLD_EXITED

child has exited

 

CLD_KILLED

child has terminated abnormally (no core)

 

CLD_DUMPED

child has terminated abnormally with core

SIGCHLD

CLD_TRAPPED

traced child has trapped

 

CLD_STOPPED

child has stopped

 

CLD_CONTINUED

stopped child has continued

 

POLL_IN

data can be read

 

POLL_OUT

data can be written

SIGPOLL

POLL_MSG

input message available

 

POLL_ERR

I/O error

 

POLL_PRI

high-priority message available

 

POLL_HUP

device disconnected

 

SI_USER

signal sent by kill

 

SI_QUEUE

signal sent by sigqueue (real-time extension)

Any

SI_TIMER

expiration of a timer set by timer_settime (real-time extension)

 

SI_ASYNCIO

completion of asynchronous I/O request (real-time extension)

 

SI_MESGQ

arrival of a message on a message queue (real-time extension)


If the signal is SIGCHLD, then the si_pid, si_status, and si_uid field will be set. If the signal is SIGILL or SIGSEGV, then the si_addr contains the address responsible for the fault, although the address might not be accurate. If the signal is SIGPOLL, then the si_band field will contain the priority band for STREAMS messages that generate the POLL_IN, POLL_OUT, or POLL_MSG events. (For a complete discussion of priority bands, see Rago [1993].) The si_errno field contains the error number corresponding to the condition that caused the signal to be generated, although its use is implementation defined.

The context argument to the signal handler is a typeless pointer that can be cast to a ucontext_t structure identifying the process context at the time of signal delivery.

When an implementation supports the real-time signal extensions, signal handlers established with the SA_SIGINFO flag will result in signals being queued reliably. A separate range of reserved signals is available for real-time application use. The siginfo structure can contain application-specific data if the signal is generated by sigqueue. We do not discuss the real-time extensions further. Refer to Gallmeister [1995] for more details.

Examplesignal Function

Let's now implement the signal function using sigaction. This is what many platforms do (and what a note in the POSIX.1 Rationale states was the intent of POSIX). Systems with binary compatibility constraints, on the other hand, might provide a signal function that supports the older, unreliable-signal semantics. Unless you specifically require these older, unreliable semantics (for backward compatibility), you should use the following implementation of signal or call sigaction directly. (As you might guess, an implementation of signal with the old semantics could call sigaction specifying SA_RESETHAND and SA_NODEFER.) All the examples in this text that call signal call the function shown in Figure 10.18.

Note that we must use sigemptyset to initialize the sa_mask member of the structure. We're not guaranteed that

    act.sa_mask = 0;

does the same thing.

We intentionally try to set the SA_RESTART flag for all signals other than SIGALRM, so that any system call interrupted by these other signals is automatically restarted. The reason we don't want SIGALRM restarted is to allow us to set a timeout for I/O operations. (Recall the discussion of Figure 10.10.)

Some older systems, such as SunOS, define the SA_INTERRUPT flag. These systems restart interrupted system calls by default, so specifying this flag causes system calls to be interrupted. Linux defines the SA_INTERRUPT flag for compatibility with applications that use it, but the default is to not restart system calls when the signal handler is installed with sigaction. The XSI extension of the Single UNIX Specification specifies that the sigaction function not restart interrupted system calls unless the SA_RESTART flag is specified.

Figure 10.18. An implementation of signal using sigaction
#include "apue.h"

/* Reliable version of signal(), using POSIX sigaction(). */
Sigfunc *
signal(int signo, Sigfunc *func)
{
    struct sigaction    act, oact;

    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
       act.sa_flags |= SA_INTERRUPT;
#endif
    } else {
#ifdef  SA_RESTART
        act.sa_flags |= SA_RESTART;
#endif
    }
    if (sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}

Examplesignal_intr Function

Figure 10.19 shows a version of the signal function that tries to prevent any interrupted system calls from being restarted.

For improved portability, we specify the SA_INTERRUPT flag, if defined by the system, to prevent interrupted system calls from being restarted.

Figure 10.19. The signal_intr function
#include "apue.h"

Sigfunc *
signal_intr(int signo, Sigfunc *func)
{
    struct sigaction    act, oact;

    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
#ifdef  SA_INTERRUPT
    act.sa_flags |= SA_INTERRUPT;
#endif
    if (sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}

    Team BBL
    Previous Page Next Page