execution stopped (cannot be blocked, caught or ignored)
stop
SIGTERM
termination
abnormal termination
SIGTSTP
terminal stop
stop
SIGTTIN
background process attempting to read
stop
SIGTTOU
background process attempting to write
stop
SIGURG
high bandwidth data available at a socket
ignore
SIGUSR1
user-defined signal 1
abnormal termination
SIGUSR2
user-defined signal 2
abnormal termination
Table 8.1: The POSIX required signals.
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
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 8.4: send SIGUSR1 to process 3423:
if (kill(3423, SIGUSR1) == -1)
perror("Failed to send the SIGUSR1 signal");
Example 8.5: a child kills its parent:
if (kill(getppid(), SIGTERM) == -1)
perror ("Failed to kill parent");
Example 8.5: a process sends a signal to itself:
if (raise(SIGUSR1) != 0)
perror("Failed to raise SIGUSR1");
Example 8.8: kill an infinite loop after 10 seconds:
int main(void) {
alarm(10);
for ( ; ; ) ;
}
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.
if ((sigemptyset(&twosigs) == -1) ||
(sigaddset(&twosigs, SIGINT) == -1) ||
(sigaddset(&twosigs, SIGQUIT) == -1))
perror("Failed to set up signal mask");
Example 8.10: add SIGINT to the set of blocked signals:
sigset_t newsigset;
if ((sigemptyset(&newsigset) == -1) ||
(sigaddset(&newsigset, SIGINT) == -1))
perror("Failed to initialize the signal set");
else if (sigprocmask(SIG_BLOCK, &newsigset, NULL) == -1)
perror("Failed to block SIGINT");
Program 8.1 on page 263 blocks and unblocks SIGINT
Program 8.2 on page 264 blocks a signal while creating two pipes.
Program 8.3 on page 265 blocks all signals before a fork and exec.
Program 8.4 on page 266 blocks some signals while getting a password.
The process signal mask is inherited by the child process.
Signal Activity: Block All Signals
Catching and Ignoring Signals: sigaction
#include <signal.h>
int sigaction(int signo, const struct sigaction *act,
struct sigaction *oact);
struct sigaction {
void (*sa_handler)(int); /* 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 */
void(*sa_sigaction) (int, siginfo_t *, void *); /* realtime handler */
};
Either act or oact may be NULL.
If the SA_SIGINFO flag of the sa_flags field is clear,
sa_handler specifies the action to be taken.
void (*sa_handler)() means a pointer to a function that has no return value.
Example 8.15: ignore SIGINT if the default action is set:
struct sigaction act;
if (sigaction(SIGINT, NULL, &act) == -1) /* Find current SIGINT handler */
perror("Failed to get old handler for SIGINT");
else if (act.sa_handler == SIG_DFL) { /* if SIGINT handler is default */
act.sa_handler = SIG_IGN; /* set new SIGINT handler to ignore */
if (sigaction(SIGINT, &act, NULL) == -1)
perror("Failed to ignore SIGINT");
}
Example 8.16: set up a signal handler for SIGINT:
void catchctrlc(int signo) {
char handmsg[] = "I found Ctrl-C\n";
int msglen = sizeof(handmsg);
write(STDERR_FILENO, handmsg, msglen);
}
...
struct sigaction act;
act.sa_handler = catchctrlc;
act.sa_flags = 0;
if ((sigemptyset(&act.sa_mask) == -1) ||
(sigaction(SIGINT, &act, NULL) == -1))
perror("Failed to set SIGINT to handle Ctrl-C");
Example 8.18: set the action of SIGINT to the default:
struct sigaction newact;
newact.sa_handler = SIG_DFL; /* new handler set to default */
newact.sa_flags = 0; /* no special options */
if ((sigemptyset(&newact.sa_mask) == -1) ||
(sigaction(SIGINT, &newact, NULL) == -1))
perror("Failed to set SIGINT to the default action");
An incorrect implementation of Program 8.5
Program 8.5: A program that terminates gracefully on ctrl-C
Program 8.6: A program to estimate the average value of sin(x)
Waiting for signals
Old way: pause
#include <unistd.h>
int pause(void);
Exercise 8.21: an incorrect way to wait for a signal:
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.
Simple wait for signal:
Suppose we have:
static volatile sig_atomic_t sigreceived = 0;
and have set up the following signal handler for SIGUSR1:
void catch_signal(int signo) {
sigreceived = 1;
}
How to wait for a SIGUSR1 signal:
set a sigset_t, emptymask, to contain no signals
block SIGUSR1 while(sigreceived == 0)
 sigsuspend(&emptymask);
Program 8.7, simplesuspend, shows how to safely block on a specific signal.
Program 8.8 shows how to use Program 8.7.
Programs 8.9 and 8.10 implement a simple biff.
sigwait
This provides an alternative way to wait for signals.
Idea:
Block all signals
Put the signals you want to wait for in a sigset_t
call sigwait
sigwait blocks the process until at least one of these
signals is pending.
It removes one of the pending signals and gives you the corresponding
signal number in the second parameter..
Do what you want: no signal handler needed.
It returns 0 on success and -1 on error with errno set.
#include <signal.h>
int sigwait(const sigset_t *restrict sigmask, int *restrict signo);
Look at Program 8.11 on page 283 that counts signals.
Errors and async-signal safety
Three issues in handling signals:
Certain blocking system calls will return -1 with errno set to
EINTR if a signal is caught while the function is blocked.
See the man page to see of a system call can set errno to
EINTR.
In this case you should usually restart the function since a real error
has not occurred.
The restart library handles this for many of the most important system calls.
Look at the functions in the restart library.
Handling errors in signal handlers.
If you use a function that can modify errno in a signal handler,
you must make sure that it does not interfere with error handling in the
main part of the program.
There is only one errno and it is used by both the main program
and by the signal handler.
Solution: in the signal handler, save and restore errno.
void myhandler(int signo) {
int esaved;
esaved = errno;
write(STDOUT_FILENO, "Got a signal\n", 13);
errno = esaved;
}
Async-signal safety.
Only certain system calls and library functions may be used safely in a
signal handler.
The strtok function is an example of a function that might have
a problem.
In fact, the POSIX standard only guarantees that a small number of
functions are async-signal safe, that is safe to use in a signal handler
and the main program.
Other functions may be async-signal safe in some implementations.
Almost none of the functions in the standard C library are on the list.
_Exit
execve
lseek
sendto
stat
_exit
fchown
lstat
setgid
symlink
accept
fcntl
mkdir
setpgid
sysconf
access
fdatasync
mkfifo
setsid
tcdrain
aio_error
fork
open
setsockopt
tcflow
aio_return
fpathconf
pathconf
setuid
tcflush
aio_suspend
fstat
pause
shutdown
tcgetattr
alarm
fsync
pipe
sigaction
tcgetpgrp
bind
ftruncate
poll
sigaddset
tcsendbreak
cfgetispeed
getegid
posix_trace_event
sigdelset
tcsetattr
cfgetospeed
geteuid
pselect
sigemptyset
tcsetpgrp
cfsetispeed
getgid
raise
sigfillset
time
cfsetospeed
getgroups
read
sigismember
timer_getoverrun
chdir
getpeername
readlink
signal
timer_gettime
chmod
getpgrp
recv
sigpause
timer_settime
chown
getpid
recvfrom
sigpending
times
clock_gettime
getppid
recvmsg
sigprocmask
umask
close
getsockname
rename
sigqueue
uname
connect
getsockopt
rmdir
sigset
unlink
creat
getuid
select
sigsuspend
utime
dup
kill
sem_post
sleep
wait
dup2
link
send
socket
waitpid
execle
listen
sendmsg
socketpair
write
Functions that POSIX guarantees to be async-signal safe.
Realtime Signals: From Section 9.4
Recall the sigaction structure:
struct sigaction {
void (*sa_handler)(int); /* 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 */
void(*sa_sigaction) (int, siginfo_t *, void *); /* realtime handler */
};
If the SA_SIGINFO flag of the sa_flags field is set,
sa_sigaction specifies the action to be taken.
This defines a new type a signal handler that takes three parameters instead
of one.
It also 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;
Signals set up with this type of signal handler are queued.
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 9.9, page 323 shows a program to send a queued signal to a process.
Note that there is no command line function similar to kill.
Program 9.10, page 324, gives an example program that can receive
SIGUSR1 signals.
Next Notes