Signals: Chapter 8 of Robbins Book
Signals: Chapter 8 of Robbins Book
Signals
#include <signal.h>
int kill(pid_t pid, int sig);
This scenario sounds grim, but a child process can kill its parent by executing the
following code segment.
#include <signal.h>
int raise(int sig);
Since the default action for SIGALRM is to terminate the process, the following program runs
for approximately ten seconds of wall-clock time.
#include <unistd.h>
int main(void) {
alarm(10);
for ( ; ; ) ;
}
Manipulating Signal Masks and Signal Sets
if ((sigemptyset(&twosigs) == -1) ||
(sigaddset(&twosigs, SIGINT) == -1) ||
(sigaddset(&twosigs, SIGQUIT) == -1))
perror("Failed to set up signal mask") ;
•A process can examine or modify its process signal mask with the sigprocmask
function. The how parameter is an integer specifying the manner in which the
signal mask is to be modified. The set parameter is a pointer to a signal set to be
used in the modification. If set is NULL, no modification is made. If oset is not
NULL, the sigprocmask returns in *oset the signal set before the modification.
#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set,
sigset_t *restrict oset);
sigset_t newsigset;
if (argc != 2) {
fprintf(stderr, "Usage: %s repeatfactor\n", argv[0]);
return 1;
}
repeatfactor = atoi(argv[1]);
if ((sigemptyset(&intmask) == -1) || (sigaddset(&intmask, SIGINT) == -1))
{
perror("Failed to initialize the signal mask");
return 1;
}
for ( ; ; ) {
if (sigprocmask(SIG_BLOCK, &intmask, NULL) == -1)
break;
fprintf(stderr, "SIGINT signal blocked\n");
for (i = 0; i < repeatfactor; i++)
y += sin((double)i); /* blocked signals calculations */
fprintf(stderr, "Blocked calculation is finished, y = %f\n", y);
if (sigprocmask(SIG_UNBLOCK, &intmask, NULL) == -1)
break;
fprintf(stderr, "SIGINT signal unblocked\n");
for (i = 0; i < repeatfactor; i++)
y += sin((double)i); /* unblocked signals calculations */
fprintf(stderr, "Unblocked calculation is finished, y=%f\n", y);
}
perror("Failed to change signal mask");
return 1;
}
A function that blocks signals while creating two pipes
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/stat.h>
#define R_MODE (S_IRUSR | S_IRGRP | S_IROTH)
#define W_MODE (S_IWUSR | S_IWGRP | S_IWOTH)
#define RW_MODE (R_MODE | W_MODE)
if (sigfillset(&blockmask) == -1)
return -1;
if (sigprocmask(SIG_SETMASK, &blockmask, &oldmask) == -1)
return -1;
if (((mkfifo(pipe1, RW_MODE) == -1) && (errno != EEXIST)) ||
((mkfifo(pipe2, RW_MODE) == -1) && (errno != EEXIST)))
{
returncode = errno;
unlink(pipe1);
unlink(pipe2);
}
if ((sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) && !returncode)
returncode = errno;
if (returncode) {
errno = returncode;
return -1;
}
return 0;
}
Catching and Ignoring Signals
#include <signal.h>
int sigaction(int signo, const struct sigaction *act,
struct sigaction *oact);
• The struct sigaction structure must have at least the following members.
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 */
};
void (*sa_handler)() means a pointer to a function that has not return value.
BIL 244 – System Programming
The following code segment sets the signal handler for SIGINT to mysighand
The following code segment causes the process to ignore SIGINT if the default action is in
effect for this signal.
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
/* ARGSUSED */
static void setdoneflag(int signo) {
doneflag = 1;
}
while (!doneflag) {
x = (rand() + 0.5)/(RAND_MAX + 1.0);
sum += sin(x);
count++;
printf("Count is %d and average is %f\n", count, sum/count);
}
int pause(void);
#include <errno.h>
#include <signal.h>
#include <unistd.h>
/* ARGSUSED */
static void catcher (int signo) {
sigreceived = 1;
}
int initsuspend (int signo) { /* set up the handler for the pause */
struct sigaction act;
if (isinitialized)
return 0;
act.sa_handler = catcher;
act.sa_flags = 0;
if((sigfillset(&act.sa_mask) == -1)||(sigaction(signo, &act, &oact) == -1))
return -1;
signum = signo;
isinitialized = 1;
return 0;
}
Example continued...
int restore(void) {
if (!isinitialized)
return 0;
if (sigaction(signum, &oact, NULL) == -1)
return -1;
isinitialized = 0;
return 0;
}
int simplesuspend(void) {
sigset_t maskblocked, maskold, maskunblocked;
if (!isinitialized) {
errno = EINVAL;
return -1;
}
if ((sigprocmask(SIG_SETMASK, NULL, &maskblocked) == -1) ||
(sigaddset(&maskblocked, signum) == -1) ||
(sigprocmask(SIG_SETMASK, NULL, &maskunblocked) == -1) ||
(sigdelset(&maskunblocked, signum) == -1) ||
(sigprocmask(SIG_SETMASK, &maskblocked, &maskold) == -1))
return -1;
while(sigreceived == 0)
sigsuspend(&maskunblocked);
sigreceived = 0;
return sigprocmask(SIG_SETMASK, &maskold, NULL);
}
A program that uses the previous functions (waits for SIGUSR1 )
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
fprintf(stderr, "This is process %ld\n", (long)getpid());
for ( ; ; ) {
if (initsuspend(SIGUSR1)) {
perror("Failed to setup handler for SIGUSR1");
return 1;
}
fprintf(stderr, "Waiting for signal\n");
if (simplesuspend()) {
perror("Failed to suspend for signal");
return 1;
}
fprintf(stderr, "Got signal\n");
if (restore()) {
perror("Failed to restore original handler");
return 1;
}
}
return 1;
}
The sigwait function
#include <signal.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
int signalcount = 0;
int signo;
int signum = SIGUSR1;
sigset_t sigset;
if ((sigemptyset(&sigset) == -1) ||
(sigaddset(&sigset, signum) == -1) ||
(sigprocmask(SIG_BLOCK, &sigset, NULL) == -1))
perror("Failed to block signals before sigwait");
fprintf(stderr, "This process has ID %ld\n", (long)getpid());
for ( ; ; )
{
if (sigwait(&sigset, &signo) == -1) {
perror("Failed to wait using sigwait");
return 1;
}
signalcount++;
fprintf(stderr, "Number of signals so far: %d\n", signalcount);
}
}
Handling Signals: Errors and Async-signal Safety
3. 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 garuantees 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.
• Programs sometimes use signals to handle errors that are not fatal
but that can occur in many places in a program.
• For example, a user might want to avoid terminating a program
while aborting a long calculation or an I/O operation that has
blocked for a long time.
• The program's response to Ctrl-C should be to start over at the
beginning (or at some other specified location).
• A similar situation occurs when the program has nested prompts
or menus and should start over when a user misenters a response.
• Object-oriented languages often handle these situations by
throwing exceptions that are caught elsewhere. C programs can
use signals indirectly or directly to handle this type of problem.
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
/* ARGSUSED */
static void chandler(int signo) {
if (jumpok == 0) return;
siglongjmp(jmpbuf, 1);
}
int main(void) {
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = chandler;
if ((sigemptyset(&act.sa_mask) == -1) ||
(sigaction(SIGINT, &act, NULL) == -1)) {
perror("Failed to set up SIGINT handler");
return 1;
}
/* stuff goes here */
fprintf(stderr, "This is process %ld\n", (long)getpid());
if (sigsetjmp(jmpbuf, 1))
fprintf(stderr, "Returned to main loop due to ^c\n");
jumpok = 1;
for ( ; ; )
; /* main loop goes here */
}