/**
@file signal.c
@author Mitch Richling <http://www.mitchr.me/>
@Copyright Copyright 1993 by Mitch Richling. All rights reserved.
@brief UNIX signals and sleep@EOL
@Keywords UNIX signal handler sleep
@Std ISOC POSIX
This C program is intended to illustrate two basic
things: 1) the sleep() system call sleeps until the
application receives a signal and 2) some basic signal
concepts. Demonstrated concepts: 1) How to write a
signal handler, 2) How to have a signal handler handle
more than one signal, 3) How to chain signal handlers,
4) How to set a signal handler, 5) how to ignore
signals, 6) how to reset signal handlers to the default,
and 7) how to set signal handlers back to the last
handler.
The API used is NOT the POSIX one, but rather the older
signal(2) function is the primary work horse here. Some
SRV programmers may recognize the signal(2) function
used in this code as part of the so called "unsafe"
signal API. In System V a signal handler is
unregistered after a signal is received if this API is
used. So the first thing most signal handlers do is to
re-register themselves. This leaves open a possible
race condition as new signals are not blocked. This
behavior is not present in BSD 4.3. Thus in BSD, this
is a safe signal API.
To see an example of the POSIX functions, take a look at
the example program sigaction.c.
@Tested
- Solaris 2.8
- MacOS X.2
- Linux (RH 7.3)
*/
#include <signal.h> /* UNIX signals POSIX */
#include <stdlib.h> /* Standard Lib ISOC */
#include <unistd.h> /* UNIX std stf POSIX */
#include <stdio.h> /* I/O lib ISOC */
int main(int argc, char *argv[]);
void firstUserSignalAction(int sigNum);
void secondUserSignalAction(int sigNum);
/* The following declares a pointer to a function taking an int and returning void */
void (*oldUserSignalAction1) (int);
void (*oldUserSignalAction2) (int);
int main(int argc, char *argv[]) {
/* signal() takes a signal number and a pointer to a signal handler. It
registers that function for that signal, and returns a pointer to the
previous signal handler. SIG_DFL is a pointer to the default signal
handler. SIG_IGN is a pointer to the "ignore" signal handler. SIG_ERR
is a dummy pointer that indicates an error condition. The function can
error for two reasons: 1) errno=EINVAL if the given integer is not a
valid signal number or 2) errno=EINVAL if one tries to give a new handler
for, or tries to ignore, SIGKILL or SIGSTOP. */
oldUserSignalAction1 = signal(SIGUSR1, &firstUserSignalAction);
if(oldUserSignalAction1 == SIG_ERR) {
printf("ERROR: signal() call failed.\n");
return 1;
} /* end if */
/* This is a typical call sequence you might see in real code. Note that
it is common, but not the best. It doesn't check for previous signal
handlers. */
if(SIG_ERR == signal(SIGUSR2, &firstUserSignalAction)) {
printf("ERROR: signal() call failed.\n");
return 1;
} /* end if */
printf("My PID: %ld\n", (long)getpid());
printf("SIGUSR1,SIGUSR2=First. Hit me.\n");
sleep(600);
printf("SIGUSR1,SIGUSR2=First. Hit me.\n");
sleep(600);
printf("SIGUSR1,SIGUSR2=First. Hit me.\n");
sleep(600);
/* Note, with the oldUserSignalAction1 value, we can check to see what was
the handler before. This probably should be done in good code because
child processes inherit signal handlers. */
if(oldUserSignalAction1 == SIG_DFL)
printf("Old signal action was the default.\n");
else if(oldUserSignalAction1 == SIG_IGN)
printf("Old signal action was to ignore.\n");
else
printf("Old signal action was a custom signal handler.\n");
/* One common thing to do with old signal handlers is to "chain" them. For example
we redefine the SIGUSR1 handler, but the first thing that the handler does is to
call the old handler. oldUserSignalAction2 is global so that firstUserSignalAction
can be used for chaining. Note that one should NOT chain outside of the handler
definition because */
oldUserSignalAction2 = signal(SIGUSR1, &secondUserSignalAction);
printf("SIGUSR1=Second,SIGUSR2=First. Hit me.\n");
sleep(600);
printf("SIGUSR1=Second,SIGUSR2=First. Hit me.\n");
sleep(600);
printf("SIGUSR1=Second,SIGUSR2=First. Hit me.\n");
sleep(600);
/* One common thing to do with the return of signal() is to set the signal handler
back to what it was before you mucked with it. This is the method used inside the
sleep() system call. Here we set SIGUSR1 back to what it was before we set it
the second time. */
signal(SIGUSR1, oldUserSignalAction2);
printf("SIGUSR1,SIGUSR2=First. Hit me.\n");
sleep(600);
printf("SIGUSR1,SIGUSR2=First. Hit me.\n");
sleep(600);
printf("SIGUSR1,SIGUSR2=First. Hit me.\n");
sleep(600);
/* We now set SIGUSR1 to the default and SIGUSR2 to ignore. */
signal(SIGUSR1, SIG_DFL);
signal(SIGUSR2, SIG_IGN);
printf("SIGUSR1=deflt, SIGUSR2=ignore. Hit me.\n");
sleep(600);
printf("SIGUSR1=deflt, SIGUSR2=ignore. Hit me.\n");
sleep(600);
printf("SIGUSR1=deflt, SIGUSR2=ignore. Hit me.\n");
sleep(600);
return 0;
} /* end func main */
/* All signal handlers take a single integer argument and return void.
The integer argument has the signal number. This lets one handler
handle multiple signals as demonstrated here. */
void firstUserSignalAction(int sigNum) {
/* We make SIGUSR1 & SIGUSR2 both handled by this function. We can tell
what signal we got from the argument. */
if(sigNum == SIGUSR1)
printf("First handler. This is sigusr1(%d)\n", sigNum);
else
printf("First handler. This is sigusr2(%d)\n", sigNum);
} /* end func firstUserSignalAction */
void secondUserSignalAction(int sigNum) {
(*oldUserSignalAction2) (sigNum);
printf("Second handler. We got signal: %d\n", sigNum);
} /* end func secondUserSignalAction */
Generated by GNU enscript 1.6.4.