0% found this document useful (0 votes)
81 views41 pages

Signals: Chapter 8 of Robbins Book

This document provides an overview of signals in Linux systems programming. It discusses basic signal concepts like generation, delivery, and lifetime. It describes how processes can catch, ignore, or block signals. Functions for manipulating signal masks like sigprocmask and for sending signals like kill and raise are also covered. Examples are provided for setting, sending, and blocking specific signals.

Uploaded by

elemaniaq
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
81 views41 pages

Signals: Chapter 8 of Robbins Book

This document provides an overview of signals in Linux systems programming. It discusses basic signal concepts like generation, delivery, and lifetime. It describes how processes can catch, ignore, or block signals. Functions for manipulating signal masks like sigprocmask and for sending signals like kill and raise are also covered. Examples are provided for setting, sending, and blocking specific signals.

Uploaded by

elemaniaq
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 41

Lecture 7

Chapter 8 of Robbins Book

Signals

BIL 244 – System Programming


Basic Signal Concepts

• A signal is generated when the event that causes the


signal occurs.
• A signal is delivered when the process takes action based
on the signal.
• The lifetime of a signal is the interval between its
generation and delivery.
• A signal that has been generated but not yet delivered is
pending.
• A process catches a signal if it executes a signal handler
when the signal is delivered.
• Alternatively, a process can ignore as signal when it is
delivered, that is to take no action.
BIL 244 – System Programming
Signals

• The function sigaction is used to specify what is to


happen to a signal when it is delivered.
• The signal mask determines the action to be taken when
the signal is generated. It contains a list of signals to be
blocked.
• A blocked signal is not delivered to a process until it is
unblocked.
• The function sigprocmask is used to modify the signal
mask.
• Each signal has a default action which is usually to
terminate the process.
BIL 244 – System Programming
Generating Signals

• Every signal has a symbolic name starting with SIG.


The signal names are defined in signal.h, which must
be included by any C program that uses signals.
• Two signals, SIGUSR1 and SIGUSR2, are available for
users and do not have a preassigned use.
• Some signals such as SIGFPE or SIGSEGV are generated
when certain errors occur; other signals are generated by
specific calls such as alarm.

BIL 244 – System Programming


Signals

signal description default action

SIGABRT process abort implementation dependent


SIGALRM alarm clock abnormal termination
SIGBUS access undefined part of memory object implementation dependent
SIGCHLD child terminated, stopped or continued ignore
SIGCONT execution continued if stopped continue
SIGFPE error in arithmetic operation as in division by zero implementation dependent
SIGHUP hang-up (death) on controlling terminal (process) abnormal termination
SIGILL invalid hardware instruction implementation dependent
SIGINT interactive attention signal (usually Ctrl-C) abnormal termination
SIGKILL terminated (cannot be caught or ignored) abnormal termination
SIGPIPE write on a pipe with no readers abnormal termination
SIGQUIT interactive termination: core dump (usually Ctrl-|) implementation dependent
SIGSEGV invalid memory reference implementation dependent
SIGSTOP execution stopped (cannot be 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

BIL 244 – System Programming


Generating Signals

• Generate signals from the shell with the kill command


• The name kill derives from the fact that, historically, many
signals have the default action of terminating the process.
• The signal_name parameter is a symbolic name for the signal
formed by omitting the leading SIG from the corresponding
symbolic signal name.
kill -s signal_name pid...
kill -l [exit_status]
kill [-signal_name] pid...
kill [-signal_number] pid...

• The last form of kill supports only the signal_number values of


0 for signal 0, 1 for signal SIGHUP, 2 for signal SIGINT, 3 for
signal SIGQUIT, 6 for signal SIGABRT, 9 for signal SIGKILL, 14
for signal SIGALRM and 15 for signal SIGTERM.

BIL 244 – System Programming


Basic Signal Concepts

• The following command is the traditional way to send


signal number 9 (SIGKILL) to process 3423.
#> kill 9 3423

• The following command sends the SIGUSR1 signal to


process 3423
#> kill -s USR1 3423

BIL 244 – System Programming


kill

• Call the kill function in a program to send a signal to a process.


• The kill function takes a process ID and a signal number as
parameters.
• If the pid parameter is greater than zero, kill sends the signal
to the process with that ID.
• If pid is 0, kill sends the signal to members of the caller's
process group. If the pid parameter is -1, kill sends the signal
to all processes for which it has permission to send.
• If the pid parameter is another negative value, kill sends the
signal to the process group with group ID equal to |pid|.

BIL 244 – System Programming


kill

#include <signal.h>
int kill(pid_t pid, int sig);

• If successful, kill returns 0. If unsuccessful, kill returns –1


and sets errno.
• A user may send a signal only to processes that he or she
owns.
• For most signals, kill determines permissions by comparing
the user IDs of caller and target.
• SIGCONT is an exception. For SIGCONT, user IDs are not
checked if kill is sent to a process that is in the same session
• For security purposes, a system may exclude an unspecified
set of processes from receiving the signal
BIL 244 – System Programming
The following code segment sends SIGUSR1 to process 3423.

if (kill(3423, SIGUSR1) == -1)


perror("Failed to send the SIGUSR1 signal");

This scenario sounds grim, but a child process can kill its parent by executing the
following code segment.

if (kill(getppid(), SIGTERM) == -1)


perror ("Failed to kill parent");
Generating Signals

• A process can send a signal to itself with the raise


function. The raise function takes just one parameter,
a signal number.

#include <signal.h>
int raise(int sig);

• If successful, raise returns 0. If unsuccessful, raise


returns a nonzero error value and sets errno. The
raise function sets errno to EINVAL if sig is invalid.

if (raise(SIGUSR1) != 0) /* sending SIGUSR1 to myself*/


perror("Failed to raise SIGUSR1");
BIL 244 – System Programming
Generating Signals

• The alarm function causes a SIGALRM signal to be sent to the


calling process after a specified number of real seconds has
elapsed.
• Requests to alarm are not stacked, so a call to alarm before the
previous timer expires causes the alarm to be reset to the new
value.
• Call alarm with a zero value for seconds to cancel a previous
alarm request.
#include <unistd.h>
unsigned alarm(unsigned seconds);

• The alarm function returns the number of seconds remaining on


the alarm before the call reset the value, or 0 if no previous
alarm was set. The alarm function never reports an error.
BIL 244 – System Programming
simplealarm.c

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

• A process can temporarily prevent a signal from being


delivered by blocking it.
• Blocked signals do not affect the behavior of the process until
they are delivered.
• The process signal mask gives the set of signals that are
currently blocked. The signal mask is of type sigset_t.
• Blocking a signal is different from ignoring a signal.
• When a process blocks a signal, the operating system does not
deliver the signal until the process unblocks the signal.
• A process blocks a signal by modifying its signal mask with
sigprocmask. When a process ignores a signal, the signal is
delivered and the process handles it by throwing it away.
• The process sets a signal to be ignored by calling sigaction
with a handler of SIG_IGN.
BIL 244 – System Programming
Manipulating Signal Masks and Signal Sets

• Specify operations (such as blocking or unblocking) on groups of signals by


using signal sets of type sigset_t.
• Signal sets are manipulated by the five functions listed in the following
synopsis box.
#include <signal.h>
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigismember(const sigset_t *set, int signo);

• The first parameter for each function is a pointer to a sigset_t. The


sigaddset adds signo to the signal set, and the sigdelset removes signo
from the signal set. The sigemptyset function initializes a sigset_t to
contain no signals; sigfillset initializes a sigset_t to contain all signals.
Initialize a signal set by calling either sigemptyset or sigfillset before
using it. The sigismember reports whether signo is in a sigset_t.

BIL 244 – System Programming


The following code segment initializes signal set twosigs to contain exactly the two
signals SIGINT and SIGQUIT

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);

•Some signals, such as SIGSTOP and SIGKILL, cannot be blocked. If an attempt


is made to block these signals, the system ignores the request without
reporting an error.
The following code segment adds SIGINT to the set of signals that the process has blocked

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");
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* a program that blocks and unblocks SIGINT */
int main(int argc, char *argv[]) {
int i;
sigset_t intmask;
int repeatfactor;
double y = 0.0;

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)

int makepair(char *pipe1, char *pipe2) {


sigset_t blockmask;
sigset_t oldmask;
int returncode = 0;

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

• The sigaction function allows the caller to examine or specify


the action associated with a specific signal.
• The sig parameter of sigaction specifies the signal number for
the action. The act parameter is a pointer to a struct
sigaction structure that specifies the action to be taken.
• The oact parameter is a pointer to a struct sigaction
structure that receives the previous action associated with the
signal.
• If act is NULL, the call to sigaction does not change the
action associated with the signal.
• If oact is NULL, the call to sigaction does not return the
previous action associated with the signal.

BIL 244 – System Programming


sigaction

• If successful, sigaction returns 0. If unsuccessful, sigaction returns –1 and sets


errno

#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

struct sigaction newact;

newact.sa_handler = mysighand; /* set the new handler */


newact.sa_flags = 0; /* no special options */
if ((sigemptyset(&newact.sa_mask) == -1) ||
(sigaction(SIGINT, &newact, NULL) == -1))
perror("Failed to install SIGINT signal handler");

The following code segment causes the process to ignore SIGINT if the default action is in
effect for this signal.

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");
}
The following code segment sets up a signal handler that catches the SIGINT signal
generated by Ctrl-C

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");
A program that terminates gracefully when it receives a Ctrl-C.

#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

static volatile sig_atomic_t doneflag = 0;

/* ARGSUSED */
static void setdoneflag(int signo) {
doneflag = 1;
}

int main (void) {


struct sigaction act;
int count = 0;
double sum = 0;
double x;

act.sa_handler = setdoneflag; /* set up signal handler */


act.sa_flags = 0;
if ((sigemptyset(&act.sa_mask) == -1) ||
(sigaction(SIGINT, &act, NULL) == -1)) {
perror("Failed to set SIGINT handler");
return 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);
}

printf("Program terminating ...\n");


if (count == 0)
printf("No values calculated yet\n");
else
printf("Count is %d and average is %f\n", count, sum/count);
return 0;
}
Waiting for Signals

• Signals provide a method for waiting for an event


without busy waiting.
• Busy waiting means continually using CPU cycles to
test for the occurrence of an event. Typically, a
program does this testing by checking the value of a
variable in a loop.
• A more efficient approach is to suspend the process
until the waited-for event occurs; that way, other
processes can use the CPU productively.
• The POSIX pause, sigsuspend and sigwait
functions provide three mechanisms for suspending a
process until a signal occurs.
BIL 244 – System Programming
The pause function

• The pause function suspends the calling thread until the


delivery of a signal whose action is either to execute a
user-defined handler or to terminate the process. If the
action is to terminate, pause does not return. If a signal
is caught by the process, pause returns after the signal
handler returns.
#include <unistd.h>

int pause(void);

• The pause function always returns –1. If interrupted by


a signal, pause sets errno to EINTR
BIL 244 – System Programming
The sigsuspend function

• The delivery of a signal before pause was one of the


major problems with the original UNIX signals, and there
was no simple, reliable way to get around the problem.
• The program must do two operations "at once"—unblock
the signal and start pause.
• Another way of saying this is that the two operations
together should be atomic (i.e., the program cannot be
logically interrupted between execution of the two
operations).
• The sigsuspend function provides a method of achieving
this.
BIL 244 – System Programming
The sigsuspend function

• The sigsuspend function sets the signal mask to the one


pointed to by sigmask and suspends the process until a signal is
caught by the process.
• The sigsuspend function returns when the signal handler of the
caught signal returns. The sigmask parameter can be used to
unblock the signal the program is looking for. When
sigsuspend returns, the signal mask is reset to the value it had
before the sigsuspend function was called.
#include <signal.h>

int sigsuspend(const sigset_t *sigmask);

• The sigsuspend function always returns –1 and sets errno. If


interrupted by a signal, sigsuspend sets errno to EINTR.
BIL 244 – System Programming
An object that allows a program to safely block on a specific signal.

#include <errno.h>
#include <signal.h>
#include <unistd.h>

static int isinitialized = 0;


static struct sigaction oact;
static int signum = 0;
static volatile sig_atomic_t sigreceived = 0;

/* 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 initsuspend(int signo);


int restore(void);
int simplesuspend(void);

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

• The sigwait function blocks until any of the signals specified by


*sigmask is pending and then removes that signal from the set of
pending signals and unblocks.
• When sigwait returns, the number of the signal that was
removed from the pending signals is stored in the location pointed
to by signo.

#include <signal.h>

int sigwait(const sigset_t *restrict sigmask,


int *restrict signo);

• If successful, sigwait returns 0. If unsuccessful, sigwait returns


–1 and sets errno. No mandatory errors are defined for sigwait

BIL 244 – System Programming


A program that counts the number of SIGUSR1 signals sent to it.

#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

• Be aware of three difficulties that can occur when


signals interact with function calls.
• The first concerns whether POSIX functions that
are interrupted by signals should be restarted
• Another problem occurs when signal handlers call
nonreentrant functions.
• A third problem involves the handling of errors
that use errno

BIL 244 – System Programming


Errors and async-signal safety

• Three issues in handling signals:

1. 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.

BIL 244 – System Programming


Errors and async-signal safety

2. 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;
}

BIL 244 – System Programming


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.

BIL 244 – System Programming


Program Control with siglongjmp and sigsetjmp

• 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.

BIL 244 – System Programming


siglongjmp and sigsetjmp

• In the direct approach, the signal handler jumps directly


back to the desired termination point.
• The jump requires unraveling the program stack. A pair of
functions, sigsetjmp and siglongjmp, provides this
capability.
• The sigsetjmp function is analogous to a statement label,
and siglongjmp function is analogous to a goto statement.
• The main difference is that the sigsetjmp and
siglongjmp pair cleans up the stack and signal states as
well as doing the jump.

BIL 244 – System Programming


siglongjmp and sigsetjmp

• Call the sigsetjmp at the point the program is to return


to.
• The sigsetjmp provides a marker in the program
similar to a statement label.
• The caller must provide a buffer, env, of type
sigjmp_buf that sigsetjmp initializes to the collection
of information needed for a jump back to that marker.
#include <setjmp.h>

void siglongjmp(sigjmp_buf env, int val);


int sigsetjmp(sigjmp_buf env, int savemask);

BIL 244 – System Programming


Code to set up a signal handler that returns to the main loop when Ctrl-C is typed.

#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

static sigjmp_buf jmpbuf;


static volatile sig_atomic_t jumpok = 0;

/* 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 */
}

You might also like