Quantcast
Channel: roman10 » Linux Signals
Viewing all articles
Browse latest Browse all 2

Linux Signal–Part 2. Signal Handler

$
0
0

Previous post covers the basics of Linux signals. This post illustrates how to install a Linux signal handler with examples.

Linux provides two methods to install signal handler, signal and sigaction. sigaction is the preferred method over signal because signal behaves differently on different UNIX and UNIX-like OSes and therefore less compatible than sigaction. This post covers sigaction only.

Before going to sigaction system call, we go through several functions which we’ll need later. You can also go the end of the post to read the source code first and refer to the explaination later.

sigprocmask System Call

A signal can be blocked. In this case, it is not delivered to the process until it is unblocked. After the signal is generated and before it is delivered, the signal is in pending state. sigprocmask system call is used to query blocked signals. It has the following prototype,

#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

how: specify how to change the block signal set. It can be one of the three values.  SIG_BLOCK: the set of blocked signal is the union of current set and the input parameter set SIG_UNBLOCK: the signals specified in set is removed from the set of blocked signals SIG_SETMASK: the set of blocked signals is set to same as the input parameter set

set: if not null, the set value is used to according to the description for how. If null, the blocked signal set is unchanged and how has no meeting.

oldset: if not null, the previous value of the signal mask is returned through oldset.

Signal Sets System Calls

The sigprocmask function returns a data structure of sigset_t type, several functions are defined to manipulate the signal set.

#include <signal.h>

int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigaddset(sigset_t *set, int signum);

int sigdelset(sigset_t *set, int signum);

int sigismember(const sigset_t *set, int signum);

One can tell what the functions do from their names.

pause and sigsuspend System Calls

Two system calls are defined to suspend the execution of a process to wait for a signal to be caught, pause() and sigsuspend(). Their prototypes are as below,

#include <unistd.h>

int pause(void);

 

#include <signal.h>

int sigsuspend(const sigset_t *mask);

pause: Suspends execution until any signal is caught. It only returns when a signal was caught and the signal catching function returned. In this case, it returns -1 and errno is set to EINTR.

sigsuspend: Temporarily changes the signal mask and suspends execution until one of the unmasked signals is caught. The calling process’s signal maks is temporarily replaced by value given in mask input parameter until the sigsuspend returns or the process is terminated.

Note that sigsuspend always returns -1, normally with the error EINTR.

Now we explain the sigaction system call.

sigaction System Call

sigaction is a system call to query and change the actions taken when a process receives a particular signal. The sigaction system call has the following prototype,

#include <signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

signum: specify the signal
act: if not NULL, the action specified by act is installed.
oldact: if not NULL, the previous action is returned.

And the data structure sigaction is defined as below,

struct sigaction {

      void     (*sa_handler)(int);

      void     (*sa_sigaction)(int, siginfo_t *, void *);

      sigset_t   sa_mask;

      int        sa_flags;

      void     (*sa_restorer)(void);

};

The parameters have the following meanings,

sa_handler: specifies the action taken to the signal, SIG_DFL (default action), SIG_IGN (ignore the signal) or a function pointer to a user defined signal handler. The defined signal handler should accepts the signal number as the only input argument.

sa_sigaction: if SA_SIGINFO flag is set in sa_flags, the handler pointed by sa_sigaction should be used.

The handler function should accept three arguments, the signal number, a pointer to an instance of siginfo_t structure (contains information about the signal) and a pointer to an object of type ucontext_t (contains the receiving process context which has been interrupted by the delivered signal. It is a void pointer can be casted to ucontext_t pointer).

The siginfo_t data structure has the following elements,

siginfo_t {

   int      si_signo;    /* Signal number */

   int      si_errno;    /* An errno value */

   int      si_code;     /* Signal code */

   int      si_trapno;   /* Trap number that caused

                            hardware-generated signal

                            (unused on most architectures) */

   pid_t    si_pid;      /* Sending process ID */

   uid_t    si_uid;      /* Real user ID of sending process */

   int      si_status;   /* Exit value or signal */

   clock_t  si_utime;    /* User time consumed */

   clock_t  si_stime;    /* System time consumed */

   sigval_t si_value;    /* Signal value */

   int      si_int;      /* POSIX.1b signal */

   void    *si_ptr;      /* POSIX.1b signal */

   int      si_overrun;  /* Timer overrun count; POSIX.1b timers */

   int      si_timerid;  /* Timer ID; POSIX.1b timers */

   void    *si_addr;     /* Memory location which caused fault */

   int      si_band;     /* Band event */

   int      si_fd;       /* File descriptor */

}

sa_mask: specify the signals should be blocked when the handler is in execution. In other words, the sa_mask adds signals to the signal mask of the process before signal handler is called. And when the signal handler function returns, the signal mask of the process is reset to its previous value. In this way, we can block certain signals when the signal handler is running. In addition, the signal that caused the signal handler to execute is also blocked, unless the SA_NODEFER flag is set.

sa_flags: specifies various options of handling the signal. The actions can be aggregated by the bitwise OR operation. The details of the flags can be referred from Linux man page.

sa_restorer: This is obsolete and should not be used.

An Example

Below is an example of installing a naive signal handler for SIGINT.

#include <stdio.h>

#include <signal.h>

 

void check_block(int signum) {

    sigset_t set;

    if (sigprocmask(0, NULL, &set)==-1) {

        perror("error sigprocmask:");

    } else {

        if (sigismember(&set, signum)) {

            printf("%d is blocked\n", signum);

        } else {

            printf("%d is not blocked\n", signum);

        }

    }

}

 

void my_handler(int signum) {

    check_block(signum);

    printf("inside signal handler: %d\n", signum);

}

 

void my_handler2(int signum, siginfo_t *info, void *context) {

    check_block(signum);

    printf("inside signal handler: %d\n", info->si_signo);

}

 

int main() {

    struct sigaction action;

//    action.sa_handler = my_handler;

//    action.sa_flags = SA_RESTART;

    action.sa_sigaction = my_handler2;

    action.sa_flags = SA_RESTART | SA_SIGINFO;

    sigaction(SIGINT, &action, NULL);

    printf("press cntl + c\n");

    pause();

    printf("after signal handler:\n");

    check_block(SIGINT);

    return 0;

}

The code first installs the signal handler for SIGINT with sigaction system call. Inside the signal handler, it checks if the SIGINT signal is blocked. As described in sa_mask of sigaction system call, the SIGINT  should be blocked inside the signal handler.

After installing the signal handler, the program calls pause() system call to wait for signal to occur. And it checks to see if the SIGINT is blocked again after the execution returns from the signal handler. This time, SIGINT should not be blocked.

Compile the code with command below,

gcc -o sigaction sigaction.c

And a sample execution is as below,

Untitled

Figure 1. Sample Execution of Sigaction Program

SA_RESTART and Interrupted System Call

You may notice that the we set the sa_flags with SA_RESTART in the example above. This has something to do with system calls.

When a signal is caught while a system call is blocked (e.g. waiting for IO), then two results can happen after the signal handler:

  • the call is restarted automatically after the signal handler returns
  • the call fails with errno set to EINTR

With SA_RESTART flag set, some system calls are restarted automatically after the signal handler, including open, wait, waitpid etc. Those system calls return failure if SA_RESTART is not set.

There’re some system calls return failure regardless SA_RESTART is set or not. A special case is the sleep function, which is never restarted but the number of seconds remaining is returned instead of failure.

The detailed list of system calls that are restarted can found with “man 7 signal” command.

The Async-signal-safe Functions

When a signal is caught by a signal handler, the normal execution is temporarily interrupted by the signal handler. If  the signal handler returns instead of terminating the process, the execution continues at where it is interrupted. Special attention needs to be paid for functions inside signal handler because we don’t want signal handler code to interfere with other code.

A bad example of this is the signal handler changes the global static variable which is used by the code after the handler.

POSIX standard defines a list of safe functions which can be called inside the signal handler, the detailed list can be obtained with “man 7 signal”.

Note that in the example above, we called printf() function inside the signal handler, which is actually not safe. If the signal is caught when we are calling printf inside the main function, the results may be unexpected.

References:

1. The Linux Signals Handling Model: http://www.linuxjournal.com/article/3985

2. Linux Signals for the Application Programmer: http://www.linuxjournal.com/article/6483

3. Linux sigaction man page.

4. Linux signal man page (man 7 signal).

5. Advaned Programming in the UNIX environment


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images