A signal is a software notification to a process of an event.
Terminology:
Symbol | Meaning |
SIGABRT | abnormal termination as initiated by abort |
SIGALRM | timeout signal as initiated by alarm |
SIGFPE | error in arithmetic operation as in division by zero |
SIGHUP | hang up (death) on controlling terminal (process) |
SIGILL | invalid hardware instruction |
SIGINT | interactive attention signal (CTRL-C) |
SIGKILL | terminate (cannot be caught or ignored) |
SIGPIPE | write on a pipe with no readers |
SIGQUIT | interactive termination: dump core (CTRL-|) |
SIGSEGV | invalid memory reference |
SIGTERM | termination |
SIGUSR1 | user-defined signal 1 |
SIGUSR2 | user-defined signal 2 |
Table 5.1, Page 170: POSIX.1 required signals.
Note that SIGKILL is special. It cannot be caught or ignored.
Symbol | Meaning |
SIGCHLD | indicates child process terminated or stopped |
SIGCONT | continue if stopped (done when generated) |
SIGSTOP | stop signal (cannot be caught or ignored) |
SIGTSTP | interactive stop signal |
SIGTTIN | background process attempts to read from controlling terminal |
SIGTTOU | background process attempts to write to controlling terminal |
Table 5.2, Page 171: The job control signals control foreground and background processes.
You can send a signal to a process from the command line using kill
kill -l will list the signals the system understands
kill [-signal] pid will send a signal to a process.
The optional argument may be a name or a number.
The default is SIGTERM.
To unconditionally kill a process, use:
kill -9 pid which is
kill -KILL pid.
From a program you can use the kill system call:
#include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig);Example 5.3, page 172, shows how to send a SIGUSR1 signal to process 3423.
Signal Mask and Signal Sets
How do you deal with a set of signals?
Originally, an int would hold a collection of bits, one per signal.
Now, signal sets of type sigset_t are used.
Here are the routines for handling sets of signals.
You should compare these to the way select handles sets of file descriptors.
#include <signal.h> int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signo); int sigdelset(sigset_t *set, int signo); int sigismember(const sigset_t *set, int signo);sigemptyset initializes the set to contain no signals sigfillset puts all signals in the set
The process signal mask is a set of signals that are blocked.
A blocked signal remains pending after it is generated until the signal
is unblocked.
The process signal mask is modified with the sigprocmask system call.
#include <signal.h> int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
The how can be:
Either set or oset may be NULL.
Example 5.8, page 175, initializes a set to contain 2 signals.
Example 5.9, page 176, blocks SIGINT
Example 5.10, pages 176-177, blocks and unblocks SIGINT in a loop
Example 5.11, pages 177-178, blocks signals while a pipe is created
Example 5.12, pages 178-179, blocks signals while child is created
The process signal mask is inherited by the child process.
Catching and Ignoring Signals: sigaction
#include <signal.h> int sigaction(int signo, const struct sigaction *act, struct sigaction *oact); struct sigaction { void (*sa_handler)(); /* SIG_DFL, SIG_IGN, or pointer to function */ sigset_t sa_mask; /* additional signals to be blocked during execution of handler */ int sa_flags; /* special flags and options */ };Either act or oact may be NULL.
void (*sa_handler)() means a pointer to a function that has not return value.
Example 5.13, page 180: Set up a handler for SIGINT
Example 5.14, pages 180-181: Ignore SIGINT if using the default action
Example 5.15, page 181: Catch SIGINT
Example 5.16, pages 181-182: Set SIGINT to default action
Example 5.17, page 182: return 1 if signal is ignored
Waiting for signals
Old way: pause
#include <unistd.h> int pause(void);Example 5.18, page 183: if a signal is received between the test and the pause, this may block forever.
What you need to do: atomically unblock the signal and suspend the process.
#include <signal.h> int sigsuspend(const sigset_t *sigmask);Sets the signal mask to the one pointed to by sigmask and suspends the process until a signal is received.
Example 5.20, page 184 shows a correct way to wait for a signal.
A biff example
Program 5.1, pages 186-188) uses signals to turn on or off the notification of mail.
System Calls and Signals
Two problems:
system call interruption and
non-reentrant system calls.
System Call Interruption:
while (retval=read(fd, buf,size), retval == -1 && errno == EINTR) ; if (retval == -1) handle real errors here
Non-reentrant system calls:
_exit() | fstat() | read() | sysconf() |
access() | getegid() | rename() | tcdrain() |
alarm() | geteuid() | rmdir() | tcflow() |
cfgetispeed() | getgid() | setgid() | tcflush() |
cfgetospeed() | getgroups() | setpgid() | tcgetattr() |
cfsetispeed() | getpgrp() | setsid() | tcgetpgrp() |
cfsetospeed() | getpid() | setuid() | tcsendbreak() |
chdir() | getppid() | sigaction() | tcsetattr() |
chmod() | getuid() | sigaddset() | tcsetpgrp() |
chown() | kill() | sigdelset() | time() |
close() | link() | sigemptyset() | times() |
creat() | lseek() | sigfillset() | umask() |
dup2() | mkdir() | sigismember() | uname() |
dup() | mkfifo() | sigpending() | unlink() |
execle() | open() | sigprocmask() | utime() |
execve() | pathconf() | sigsuspend() | wait() |
fcntl() | pause() | sleep() | waitpid() |
fork() | pipe() | stat() | write() |
Realtime Signals
In 1993 a new signal interface was added to the POSIX standard.
#include <signal.h> struct sigaction { void (*sa_handler)(); /* SIG_DFL, SIG_IGN, or pointer to function */ void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; /* additional signals to be blocked during execution of handler */ int sa_flags; /* special flags and options */ };This defines a new data type: siginfo_t which is a structure containing at least the following:
int si_signo; /* signal number */ int si_code; /* cause of the signal */ union sigval si_value; /* signal value */where the union sigval contains at least:
int sival_int; void *sival_ptr;When the sa_flags field has the SA_SIGINFO flag set, then sa_sigaction is used for the signal handler rather than sa_handler.
The system call to send one of these signals is called sigqueue
rather than kill:
#include <signal.h> int sigqueue(pid_t pid, int signo, const union sigval value);
On some systems, only certain signals can be queued, those between SIGRTMIN and SIGRTMAX.
Program 5.3, page 195 shows a program to send a queued signal to a process. Note that there is no command line function similar to kill.
Program 5.4, page 196, gives an example program that can receive SIGUSR1 signals.