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.
Example 5.4, page 173, shows how a child process can kill its parent.
Example 5.5, page 173, shows the use of raise to send a signal to yourself.
Example 5.7, page 174, shows a way to generate a SIGALRM signal after 10 seconds.
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
sigaddset adds one signal to the set
sigdelset removes one signal from the set
sigismember tests to see if a signal is 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:
- SIG_BLOCK
- SIG_UNBLOCK
- SIG_SETMASK
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.
Example 5.19, page 183: Does not work since pause is executed while the signal is blocked.
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.
When it returns the signal mask is restored to what it was before it was called.
This function always returns -1.
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:
- Some system calls that can block indefinitely long will return when a signal
is delivered.
- These system calls return -1 and set errno to EINTR
- You can tell which system calls can do this my looking at the return values
listed on their man pages.
- Two of the system calls that need special attention are read and
write.
- Here is a program segment to restart a read if it is interrupted
by a signal:
while (retval=read(fd, buf,size), retval == -1 && errno == EINTR) ;
if (retval == -1)
handle real errors here
- Note the use fo the 3rd comma in the while statement.
- The write system call can be handled in a similar way.
- Recall that you also need to handle a write that does not write
as many bytes as requested.
Non-reentrant system calls:
- A function that can be safely called from a signal handler is called
async-signal-safe
- Recall that functions like strtok are not async-signal-safe
- The table below gives a complete list of those function calls that must be
async-signal-safe if the POSIX standard is followed.
- Note that the C I/O functions such as fprintf are not included.
- These may be safe under some implementations but not under others.
- Under Solaris, almost everything is async-signal-safe if it can be.
- For compatibility, you should not assume that the ones not in this
list are safe.
_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() |
Functions that POSIX.1 specify as async-signal-safe.
Realtime Signals
In 1993 a new signal interface was added to the POSIX standard.
- This is commonly known as the Realtime Signal Extension and is defined in
POSIX.1b.
- Some of the enhancements include queueing of signals and the passing of
information to the signal handler.
The sigaction structure has been extended to include an additional
field:
#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.