Signals
What is a Signal?A signal is a notification that some event has occurred.Usually a signal is sent to a process asynchronously andwhatever the process is doing is interrupted.
Signals have been around since the early days of Unix, butearly versions were not reliable, signals could get lost. Both4.3BSD and SVR3 made revisions to their signal code to makesignals reliable, but the changes were incompatible. Posix.1standardized the reliable signal routines.
OperatingSystems
A signal is born when an event occurs that generates the signal.
A signal ceases to exist when it is delivered, whichmeans that some action specified for the signal hasbeen taken.
Between generation and delivery a signal is said tobe pending.
The Life Cycle of a Signal
OperatingSystems
Conditions that generate signalsMost signals can be generated naturally
OperatingSystems
for example, by a divide by zero erroror a segmentation fault
All signals can be generated synthetically by oneof the following system calls:
killkillpgpthread_killraisesigqueue
Conditions that generate signalsFive signals cannot be generated naturally
OperatingSystems
SIGKILLSIGSTOPSIGTERMSIGUSR1SIGUSR2
terminate immediatelypauserequests termination
Signal names are defined in signal.h
Conditions that generate signalsTerminal generated signals: occur when users type certain keys on the keyboard. For example, Ctrl-C normally generates the signal SIGINT.
OperatingSystems
Hardware exceptions: conditions detected by hardware, like divide by zero, are sent to the kernel. The kernel generates the appropriate signal.The kill( ) function or the kill command:
The kill function allows a process to send any signal to another process or process group, as long as it owns that process.
Software Conditions: Some software conditions can cause signals to be generated. For example, SIGURG is generated when out of band data arrives over a network connection.
A signal is a classic example of an asynchronous event.They can occur at random times as far as the process isconcerned. A process must tell the kernel what to doif and when a signal is received. A process can:
* Ignore a signal - sigkill and sigstop cannot be ignored - ignored signals have no effect on the process
* Catch the signal and call a function
* Let the default apply - usually terminates the process
OperatingSystems
When you get a signal from a hardware detected errorcondition, you cannot ignore the signal. Your programwill likely not get safely past the condition.
Such signals should be handled right away and the program terminated with a call to exit( )
More on this later . . .
OperatingSystems
TerminologyA signal is a software notification of an event.
A signal is generated when the event that causes the signal occurs.
A signal is delivered when the process catches the signal and takes some action on it. A signal that has not been delivered is pending.
A signal handler is a function that the programmer writes to take some specific action when a given signal occurs.
A program installs a signal handler by calling sigaction( ). A signal handler may choose to ignore a signal, in which case it is thrown away.
A process can use a signal mask to block a set of signals. A blocked signal waits in a pending mode until the process unblocks the signal, at which time it is delivered to the process.
OperatingSystems
Some Common Signal Names
Symbol Meaning
SIGABRT abnormal termination, initiated by abortSIGALRM timeout signal, initiated by alarmSIGFPE arithmetic error, such as divide by zeroSIGHUP hang up on controlling terminalSIGILL invalid hardware instructionSIGINT interactive attention signal (Ctrl-C)SIGKILL terminate ( cannot be caught or ignored )SIGPIPE write on a pipe with no readersSIGQUIT interactive terminationSIGSEGV invalid memory referenceSIGTERM terminationSIGUSR1 user definedSIGUSR2 user defined default action for all
of these signals is to terminatethe process.
This set is required by Posix.1OperatingSystems
Job Control Signals
Symbol Meaning Default Action
SIGCHLD child process has stopped ignoreSIGCONT continue if stopped continue processSIGSTOP stop signal (can’t be caught/ignored) stop processSIGSTP interactive stop signal stop processSIGTTINbackground process trys to read stop processSIGTTOU background process trys to write stop process
See all of the signals theos supports by typing
kill -l
See the key sequences that generatesignals on your system by typing
stty -a
OperatingSystems
What to do with a Signal
Ignore the signal. Most signals can be ignored, butSIGKILL and SIGSTOP cannot.
Catch the signal by telling the kernel to call a functionprovided by the programmer, when a particular signalis generated.
Let the default action apply. The default for most signalsis to terminate the process.
OperatingSystems
A really polished program will . . .Block all signals as soon as your program begins.
Set all keyboard generated signals you don’t want tohandle to be ignored.
Catch SIGTERM and arrange to clean everything upand terminate when it arrives. This is the standard waythat a sys admin will shut down processes.
Catch all error generated signals and arrange to log them,print an appropriate error message, do any necessaryclean-up, and terminate.
Generating Signalsfrom the command line
A user can only kill a process that he or she owns.
Generate a signal with the kill command. From the shell
kill –s signal pid
This is one of the signal names less the “sig” prefix
Example: kill –s USR1 3423
Generating Signals
#include <sys/types.h>#include <signal.h>
int kill (pid_t pid, int sig );
if pid is positive, kill sends the signal sig to the process pid (must own the process)if pid is negative, kill sends the signal to the process group |pid|if pid is zero, kill sends the signal to members of the callers process group
returns 0 if successful
from within a program
Killing a Parent ProcessSounds grim, but …..
#include <stdio.h>#include <unistd.h>#include <signal.h>
if (kill(getppid( ) , SIGTERM) == -1) perror(“Error in kill command”);
Generating Signals (cont)The function
alarm ( unsigned int num )
will generate a SIGALRM signal after num seconds have elapsed. The signal is sent to the calling process.
A process needs permission to send a signal to another process. The superuser can send a signal to any process. For others the basic rule is that the real or effective user id of the sender has to be the same as the real or effective user id of the receiver, i.e. you can only send signals to processes that you own...
The Signal set
A process can temporarily prevent a signal from being deliveredby blocking it. Blocked signals do not affect the behavior of theprocess until they are delivered. The signal mask contains theset of all of the signals that are currently blocked. The followingfunctions initialize and modify a signal set.
int sigemptyset(sigset_t *set);int sigfillset(sigset_t *set);int sigaddset(sigset_t *set, int sig);int sigdelset(sigset_t *set, int sig);int sigismember(const sigset_t *set, int sig);
use either of thesefunctions to initializea signal mask beforeusing it.
This function returns 1 if sig is a member of the set. Otherwiseit returns 0.
contains no signalscontains all signals
* note that blocking a signalis different from ignoring a signal.
adds a signal to the signalset
*
deletes a signal from the signalset
Example Code
#include <signal.h>sigset_t twosigs;…
sigemptyset (&twosigs);sigaddset (&twosigs, SIGINT);sigaddset (&twosigs, SIGQUIT);
this code initializes the signal set twosigs so that it containsjust the two signals SIGINT and SIGQUIT.
create a signal set
make the signal set emptyadd sigint
add sigquit
sigprocmask ( )
#include <signal.h>
int sigprocmask (int how, const sigset_t *set, sigset_t *oldset);
SIG_BLOCK: add this set to the signals currently blockedSIG_UNBLOCK: delete this set from the signals currently blockedSIG_SETMASK: set the signal mask to this set
the set of signals to beused for the modification.If this value is NULL, then thefunction simply retrieves thecurrent signal mask and storesit in oldset. No change is made tothe current signal set.
the function returns thecurrent set of signals beingblocked in oldset. This allows the program to restore the old signal set. If this valueis NULL, then no value is returned.
Installing a signal set
Example code
#include <signal.h>
sigset_t mymask;…sigemptyset(&mymask);sigaddset(&mymask, SIGINT);sigprocmask(SIG_BLOCK, &mymask, NULL);…sigprocmask(SIG_UNBLOCK, &mymask, NULL);…
initialize the mask setand then set SIGINT
add to the signal maskusing the signal setwe just created
//if a ctrl-C occurs here, it will be blocked.
clears the SIGINTfrom the signal mask
this code adds SIGINT to the set of signals that the process currently has blocked.
The old setis not saved.
See ex1 on X-Server.
This code will block Ctrl-C then do some useless work. Ifa Ctrl-C comes in during this time, the process does notsee the signal. When the process unblocks it, the signalis delivered.
Handling Signals
Remember that blocking a signal only means that the signal will not be delivered until the signal is unblocked. It is a way of temporarily protectingyour code from a signal. Once the signal is unblocked it will be delivered to the process. Then it must be handled in some way. In most cases, an unhandled signal will result in the process terminating.
Handling Signals
What do you need to do inside of the signal handlerto change the state of the application so it is knownthat the signal occurred?
Where do you go after handling the signal. Choices are:
return to where the application was when it was interrupted terminate the program do a global jump to another part of the program
There are two issues to think about:
Note that when you are in the signal handler, you arelimited to making system calls that are consideredto be asynch-signal-safe. These system calls areguaranteed to be re-entrant. POSIX defines thesystem calls that are asynch-signal-safe.
The Signal System Call
This call was defined by ANSI C, but has been deprecated.It does not work well in multi-process environments. However,it is a simple call and illustrates signal handling effectively.
#include <signal.h>
void signal ( int signum, void (*act) (int) )
this is just a pointer to a function that takes an integer parameterand returns a void.
Examplefrom Molay chapter 6
#include <stdio.h>#include <signal.h>
void f(int);
int main ( ){ int i; signal ( SIGINT, f); for (i = 0; i < 10; i++) { printf(“hello\n”); sleep(1); } return 0;}
void f ( int signum ){ printf(“\nOUCH”);}
The signal handler
int main ( ){ int i; signal ( SIGINT, f); for (i = 0; i < 10; i++) { printf(“hello\n”); sleep(1); } return 0;}
install the signal handler
void f ( int signum ){ printf(“\nOUCH”);}
int main ( ){ int i; signal ( SIGINT, f); for (i = 0; i < 10; i++) { printf(“hello\n”); sleep(1); } return 0;}
void f ( int signum ){ printf(“\nOUCH”);}
hellohellohello
INTERRUPT (SIGINT)
ouch
look at the code
Signal Handlers
#include <signal.h>
int sigaction (int sig, const struct sigaction *act, struct sigaction *old);
struct sigaction{ void (*sa_handler) ( ); // SIG_DFL, SIG_IGN, or pointer to function sigset_t sa_mask; // additional signals to be blocked while in handler int sa_flags; // flags and options}
the function returns the currentsignal handling information in this structure. If NULL, nothingis returned.
the signal handlinginformation to be setfor handling this signal.
the signal to be caught
SA_RESTART Restart any system calls interrupted by this signal once the signal handler has finished
reset to default ignore
eliminates race conditions
May be null
A signal handler is an ordinary function that takes asingle integer parameter and returns a void. The operating system sets the parameter to the signalthat was delivered to the process. Most signal handlersignore this parameter, although it is possible to write asignal handler that handles several different signals.
ExampleThe following code segment sets up a signalhandler that catches ctrl-C.
…char handlermsg[ ] = “User hit ctrl-c!\n”;void catch_ctrl_c (int signo){ write(STDERR_FILENO, handlermsg, strlen(handlermsg));}…struct sigaction act;
act.sa_handler = catch_ctrl_c;sigemptyset(&act.sa_mask);act.sa_flags = 0;if (sigaction(SIGINT, &act, NULL) < 0){ // signal handler is installed…
this is the actual signal handler. It prints a message.
load the address of the handlerdon’t worry about any other signals
no flags
note that write is signal safe ... printf is not!
ExampleThe following code segment sets up a signalhandler that ignores SIGINT if it is using theDefault handler for this signal.
#include <signal.h> #include <stdio.h> struct sigaction act;
… if (sigaction(SIGINT, NULL, &act) == -1) perror(“Could not get the old signal handler for SIGINT”); else if (act.sa_handler == SIG_DFL) { act.sa_handler = SIG_IGN; if (sigaction(SIGINT, &act, NULL) == -1) perror (“Could not ignore SIGINT”); }
This just gets the currentsignal handler in act
This sets the newsignal handler
See handler.c example
This code uses a shared variable as a flag.The program computes in an endless loopuntil the flag gets set. The flag gets set by the signal handler for SIGINT.
Waiting for signalsOne of the primary uses of signals is to keep programs fromburning up cpu time while waiting for some event. Instead ofrunning in a tight loop and checking to see if a signal has beenreceived (polling), the program can put itself into a suspended state until the waited-for event occurs.
#include <unistd.h>
int pause ( );
pause suspends the process untila signal that is not being ignoredis delivered to the process. If a signalis caught by the process, the pausereturns after the signal handler returns.
the return valueis not significant.
pause( ) always returns -1 with errno set to EINTR
process A
pause()
process B
signalhandler
signal
A problem with Pause
…static volatile sig_atomic_tsignal_received = 0;
…
while(signal_received == 0) pause( );
// go on to other stuff
…
to wait for a particular signal, we need to checkwhich signal caused the pause to return. Thisinformation is not directly available, so we usean external static variable as a flag which the signal handler sets to 1. We can then check thisflag when pause returns.
the pause call is put into a loopso that we can check the value of the flag. If it is still zero, wemust call pause again.
what happens if a signal is deliveredbetween the test and the pause?
The program does not catch it!!the pause does not return until anothersignal is received. To solve this problem,we should test the flag while the signal isblocked!
Volatile: This value may be changed bysomething outside of this scope. It shouldnot be optimized by the compiler.
sig_atomic_t is a data type that is guaranteedcan be read or written without being interruped.
But … does this work?…sigset_t sigset;int signum;
sigemptyset(&sigset);sigaddset(&sigset, signum);sigprocmask(SIG_BLOCK, &sigset, NULL);
while(signal_received == 0) pause();…
// signum is the signal we want to catch
No! Now the signal is blocked when thepause statement is executed, so theprogram never receives the signal.
sigsuspend
The delivery of signals with pause was a major problem in Unix.It was fixed by adding the sigsuspend operation.
int sigsuspend(const sigset_t *sigmask);
return value isalways -1
sigsuspend sets the signal mask tothe one pointed to by sigmask and pauses the process in a single atomicoperation. When sigsuspend returns, the signal mask is reset to the value ithad before sigsuspend was called.
Consider the following code
sigfillset(&mask); // set mask to block all signalssigdelset(&mask, signum); // remove signum from the setsigsuspend(&mask); // wait for signum
Now the program pauses. All signals exceptsignum have been blocked. What’s wrong?
Consider the following code
sigfillset(&mask); // set mask to block all signalssigdelset(&mask, signum); // remove signum from the setsigsuspend(&mask); // wait for signum
what happens if the signal is delivered just beforethis code block is entered? The signal is handled,and now sigsuspend puts the program in a waitcondition. If another signal is not delivered, theprogram waits forever.
Correct code to wait for a signal (signum)
static volatile sig_atomic_t sigreceived = 0;
sigset_t maskall, maskmost, maskold;int signum = SIGNUM;
sigfillset(&maskall);sigfillset(&maskmost);sigdelset(&maskmost, SIGNUM);sigprocmask(SIG_SETMASK, &maskall, &maskold);if (sigreceived == 0) sigsuspend(&maskmost);sigprocmask(SIGSETMASK, &maskold, NULL);
declare static variable to test. It gets set in the signal hander.
the signal we want to wait for.
block all signalsblocks all signals but SIGNUM
now, all signalsare blocked.
test the flag.this is thecriticalsection
unblock SIGNUM and pauseas an atomic action.
after returning from the signal handler, restore the old signal mask.
Correct code to wait for a signal... allowing other signals while waiting
for SIGUSR1
static volatile sig_atomic_t sigreceived = 0;
sigset_t masknew, maskold;int signum = SIGUSR1;
sigprocmask(SIG_SETMASK, NULL, &masknew);sigaddset(&masknew, signum);sigprocmask(SIG_SETMASK, &masknew, &maskold);sigdelset(&masknew, SIGUSR1);while (sigreceived == 0) sigsuspend(&masknew);sigprocmask(SIGSETMASK, &maskold, NULL);
The flag
The signal I want to wait for
get currentadd my signal to the current set
set masknow SIGUSR1 is blocked remove SIGUSR1 from the set
if flag is ok, wait for SIGUSR1 … it isunblocked by the sigsuspend call
restore