signals n.
Skip this Video
Loading SlideShow in 5 Seconds..
Signals PowerPoint Presentation
Download Presentation

Loading in 2 Seconds...

play fullscreen
1 / 58

Signals - PowerPoint PPT Presentation

  • Uploaded on

Signals. What is a signal. A signal is a software interrupt. Usually a signal is sent to a process asynchronously and whatever the process is doing is interrupted. Signals have been around since the early days of Unix, but early versions were not reliable, signals could get lost. Both

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
Download Presentation

PowerPoint Slideshow about 'Signals' - fionn

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

What is a signal

A signal is a software interrupt. Usually a signal is sent to a

process asynchronously and whatever the process is doing

is interrupted.

Signals have been around since the early days of Unix, but

early versions were not reliable, signals could get lost. Both

4.3BSD and SVR3 made revisions to their signal code to make

signals reliable, but the changes were incompatible. Posix.1

standardized the reliable signal routines.


The Life Cycle of a Signal

A signal is born when an event occurs that

generates the signal.

A signal ceases to exist when it is delivered, which

means that some action specified for the signal has

been taken.

Between generation and delivery a signal is said to

be pending.


Conditions that Generate Signals

Terminal generated signals:

occur when users type certain keys on the keyboard. For

example, Ctrl-C normally generates the signal SIGINT.

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.


Some Common Signal Names

SIGABRT process abort implementation defined

SIGALRM timer abnormal termination

SIGBUS access undefined memory implementation defined

SIGCHILD child process terminated ignore

SIGCONT execution continued continue

SIGFPE error in arithmetic implementation defined

SIGHUP terminal hangs up abnormal termination

SIGILL invalid instruction implementation defined

SIGINT Ctrl-C abnormal termination

SIGKILL terminated abnormal termination

SIGPIPE write on pipe w/ no reader abnormal termination

SIGSEGV invalid memory reference implementation defined

SIGTERM termination stop

SIGUSR1 user defined abnormal termination

SIGUSR2 user defined abnormal termination


See all of the signals the os supports by typing

kill -l

See the key sequences that generate

signals on your system by typing

stty -a


A signal is a classic example of an asynchronous event.

They can occur at random times as far as the process is

concerned. A process must tell the kernel what to do

if and when a signal is received. A process can:

* Catch the signal and ignore it

- SIGKILL and SIGSTOP cannot be ignored

- ignored signals have no effect on the process

* Catch the signal and do something with it

* Let the default apply

- usually terminates the process


When you get a signal from a hardware detected error

condition, you should not ignore the signal. Your program

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



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


What to do with a Signal

Ignore the signal. Most signals can be ignored, but


Catch the signal by telling the kernel to call a function

provided by the programmer (signal handler), when a

particular signal is generated.

Let the default action apply. The default for most signals

is to terminate the process.


A really polished program will . . .

Block all signals as soon as your program begins.

Set all keyboard generated signals you don’t want to

handle to be ignored.

Catch SIGTERM and arrange to clean everything up

and terminate when it arrives. This is the standard way

that a sys admin will shut down processes.

Catch all error generated signals and arrange to log them,

print an appropriate error message, do any necessary

clean-up, and terminate.


Generating Signals

from 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

from within a program

#include <sys/types.h>

#include <signal.h>

int kill (pid_t pid, int sig );

returns 0 if successful

if pid is positive, kill sends the signal sig to the process pid (must own the process)

if pid is zero, kill sends the signal to members of the callers process group


Killing a Parent Process

Sounds grim, but …..

#include <stdio.h>

#include <unistd.h>

#include <signal.h>

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

perror(“Error in kill command”);


Sending a Signal to Yourself

#include <stdio.h>

#include <unistd.h>

#include <signal.h>

if (raise(SIGTERM) == -1)

perror(“Error in raise 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.


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 signal mask contains the

set of all of the signals that are currently blocked. The following

functions initialize and modify a signal set.


intsigemptyset(sigset_t *set);

intsigfillset(sigset_t *set);

intsigaddset(sigset_t *set, int sig);

intsigdelset(sigset_t *set, int sig);

intsigismember(constsigset_t *set, int sig);

contains no signals

use either of these

functions to initialize

a signal mask before

using it.

contains all signals

adds a signal to the signalset

deletes a signal from the signalset

This function returns 1 if sig is a

member of the set. Otherwise

it returns 0.

* note that blocking a signal

is different from ignoring

a signal.


Example Code

this code initializes the signal set twosigs so that it contains

just the two signals SIGINT and SIGQUIT.

#include <signal.h>

sigset_t twosigs;

sigemptyset (&twosigs);

sigaddset (&twosigs, SIGINT);

sigaddset (&twosigs, SIGQUIT);

create a signal set

make the signal set empty

add sigint

add sigquit



Installing a signal set

SIG_BLOCK: add this set to the signals currently blocked

SIG_UNBLOCK: delete this set from the signals currently blocked

SIG_SETMASK: set the signal mask to this set

#include <signal.h>

int sigprocmask (int how, const sigset_t *set, sigset_t *oldset);

the function returns the

current set of signals being

blocked in oldset. This allows

the program to restore the

old signal set. If this value

is NULL, then no value is


the set of signals to be

used for the modification.

If this value is NULL, then the

function simply retrieves the

current signal mask and stores

it in oldset. No change is made to

the current signal set.


Example Code

this code adds SIGINT to the set of signals that the

process currently has blocked.

#include <signal.h>

sigset_t mymask;


sigaddset(&mymask, SIGINT);

sigprocmask(SIG_BLOCK, &mymask, NULL);

sigprocmask(SIG_UNBLOCK, &mymask, NULL);

The old set

is not saved.

initialize the mask set

and then set SIGINT

//if a ctrl-C occurs here, it will be blocked.

add to the signal mask

using the signal set

we just created

clears the SIGINT

from the signal mask


Example Code

This code will block Ctrl-C then do some useless work. If

a Ctrl-C comes in during this time, the process does not

see the signal. When the process unblocks it, the signal

is 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 protecting

your 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

There are two issues to think about:

What do you need to do inside of the signal handler

to change the state of the application so that the

application knows that 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


Reentrant Functions

When a signal is handled, the signal handler

has no notion of what the application was doing

when it was interrupted by the signal.

What if the application had just called a function

like malloc, and the signal handler also calls malloc.

- the heap manager could get confused.


Reentrant Functions

Note that when you in the signal handler, you are

limited to making system calls that are considered

to be asynch-signal-safe. These system calls are

guaranteed to be re-entrant. POSIX defines the

system calls that are guaranteed to be



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 parameter

and returns a void.



from Molay chapter 6

#include <stdio.h>

#include <signal.h>

void f(int);

int main ( )


int i;

signal ( SIGINT, kickme);

for (i = 0; i < 10; i++)





return 0;


The signal handler

void kickme ( intsignum )





int main ( )


int i;

signal ( SIGINT, kickme);

for (i = 0; i < 10; i++)





return 0;


install the signal handler

void kickme ( intsignum )





int main ( )


int i;

signal ( SIGINT, kickme);

for (i = 0; i < 10; i++)





return 0;







void kickme ( intsignum )




look at the code – ouch.c


Signal Handlers

#include <signal.h>

intsigaction (int sig, conststructsigaction *act, structsigaction *old);



void (*sa_handler) ( ); // SIG_DFL, SIG_IGN, or pointer to function

sigset_tsa_mask; // additional signals to be blocked while in handler

intsa_flags; // flags and options


May be null

the signal handling

information to be set

for handling this signal.

the signal to

be caught

the function returns the current

signal handling information in

this structure. If NULL, nothing

is returned.

reset to default


eliminates race conditions


Restart any system calls interrupted by this signal once the signal handler has finished


A signal handler is an ordinary function that takes a

single integer parameter and returns a void. The

operating system sets the parameter to the signal

that was delivered to the process. Most signal handlers

ignore this parameter, although it is possible to write a

signal handler that handles several different signals.



The following code segment sets up a signal

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


act.sa_flags = 0;

if (sigaction(SIGINT, &act, NULL) < 0)


// signal handler is installed

this is the actual signal handler. It prints a message.

note that write is signal safe ... printf is not!

load the address of the handler

don’t worry about any other signals

no flags



The following code segment sets up a signal

handler that ignores SIGINT if it is using the

Default 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 current

signal handler in act

This sets the new

signal handler



How do you tell an application that a

signal that it expected has occurred?


See handler.c example

This code uses a shared variable as a flag.

The program computes in an endless loop

until the flag gets set. The flag gets set by

the signal handler for SIGINT.


Waiting for a Signal

One of the primary uses of signals is to keep programs from

burning up cpu time while waiting for some event. Instead of

running in a tight loop and checking to see if a signal has been

received (polling), the program can put itself into a suspended

state until the waited-for event occurs.

#include <unistd.h>

int pause ( );

the return value

is not significant.

pause suspends the process until

any signal that is not being ignored

is delivered to the process. If a signal

is caught by the process, the pause

returns after the signal handler returns.

pause( ) alwaysreturns -1 with errno set to EINTR



process B

process A





The Problem with Pause

to wait for a particular signal, we need to check

which signal caused the pause to return. This

information is not directly available, so we use

an external static variable as a flag which the

signal handler sets to 1. We can then check this

flag when pause returns.

static volatile sig_atomic_t

signal_received = 0;

while(signal_received == 0)

pause( );

// go on to other stuff

the pause call is put into a loop

so that we can check the value

of the flag. If it is still zero, we

must call pause again.

what happens if a signal is delivered

between the test and the pause?

The program does not catch it!!

the pause does not return until another

signal is received. To solve this problem,

we should test the flag while the signal is


Volatile: This value may be changed by

something outside of this scope. It should

not be optimized by the compiler.

sig_atomic_t is a data type that is guaranteed

can be read or written without being interruped.


Does This Work?




sigaddset(&sigset, signum);

sigprocmask(SIG_BLOCK, &sigset, NULL);

while(signal_received == 0)


// signum is the signal we want to catch

No! Now the signal is blocked when the

pause statement is executed, so the

program never receives the signal.



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 is

always -1

sigsuspend sets the signal mask to

the one pointed to by sigmask and

pauses the process in a single atomic

operation. When sigsuspend returns,

the signal mask is reset to the value it

had before sigsuspend was called.


Consider the following code

sigfillset(&mask); // set mask to block all signals

sigdelset(&mask, signum); // remove signum from the set

sigsuspend(&mask); // wait for signum

Now the program pauses. All signals except

signum have been blocked. What’s wrong?


Consider the following code

sigfillset(&mask); // set mask to block all signals

sigdelset(&mask, signum); // remove signum from the set

sigsuspend(&mask); // wait for signum

what happens if the signal is delivered just before

this code block is entered? The signal is handled,

and now sigsuspend puts the program in a wait

condition. If another signal is not delivered, the

program waits forever.


now, all signals

are blocked.

Correct code to wait for a signal (signum)

declare static variable to test. It gets set in the signal hander.

static volatile sig_atomic_tsigreceived = 0;

sigset_tmaskall, maskmost, maskold;

intsignum = SIGNUM;



sigdelset(&maskmost, SIGNUM);

sigprocmask(SIG_SETMASK, &maskall, &maskold);

if (sigreceived == 0)


sigprocmask(SIGSETMASK, &maskold, NULL);

the signal we want to wait for.

block all signals

blocks all signals but SIGNUM

test the flag.

this is the



unblock SIGNUM and pause

as 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


static volatile sig_atomic_tsigreceived = 0;

sigset_tmasknew, maskold;

intsignum = SIGUSR1;

sigprocmask(SIG_SETMASK, NULL, &masknew);

sigaddset(&masknew, signum);

sigprocmask(SIG_SETMASK, &masknew, &maskold);

sigdelset(&masknew, SIGUSR1);

while (sigreceived == 0)


sigprocmask(SIGSETMASK, &maskold, NULL);

The flag

The signal I want to wait for

get current

add my signal to the current set

set mask

now SIGUSR1 is blocked

remove SIGUSR1 from the set

if flag is ok, wait for SIGUSR1 … it is

unblocked by the sigsuspend call



System Calls and Signals

Some system calls, like terminal I/O can block the process for

a very long time.

The capability is needed to be able to interrupt these

system calls so that signals can be delivered during long

waits for I/O.

In POSIX.1, slow system calls that are interrupted

return with -1, and errno set to EINTR. The program

must handle this error explicitly and restart the system

call if desired.


Remember the sigactionstruct ….



void (*sa_handler) ( );



SA_RESTART Restart any system calls interrupted by

this signal once the signal handler has finished


Slow System Calls are those that can block forever. These include

* reads from files that block forever if no data is present.

This includes pipes, network connections, and terminals.

* Writes to the above if the data cannot be accepted.

* opens of files that block until some condition occurs,

for example waiting to open a terminal device until

modem answers the phone.

* pause

* some interprocess communication functions


The following code segment restarts the read system call

if interrupted by a signal.

#include <sys/types>

#include <sys/uio.h>

#include <unistd.h>

#include <errno.h>

intfd, retval, size;

char *buf;

. . .

while (retval = read(fd, buf, size), retval == -1 && errno == EINTR);

if (retval == -1)


// handle errors here …


note the use of the comma operator:

the left-hand expression is evaluated first

then the second expression is evaluated

and the result used as the condition for the

while loop.

that is, the read occurs. Then the

return value is tested. If it failed

because of an interrupt, the read

is re-started.

siglongjump and sigsetjump

see non-local exits in the GNU C library manual

siglongjump and sigsetjump

Used to unwind the call stack

sigsetjump is like a statement label

siglongjump is like a goto … it branches to the label set by sigsetjump

It is not recommended that you use these


A timer keeps track of the passage of time

Calendar time is a point in the time continuum,

for example, October 5, 2001 at 12:30pm. The

Unix time continuum (epoch) begins on January 1, 1970

An interval is a contiguous part of the time continuum,

between two calendar times.

Interval timers generate an interrupt after a specific

time interval.

An elapsed time is the length of an interval, for example,

30 minutes.

An amount of time is a sum of elapsed times.

CPU time is like calendar time, except that it is based

on the subset of the time continuum when a particular

process is actively using a CPU. CPU time is, therefore,

relative to a process


interval timers

Each process has three independent interval timers available:

* A real-time timer that counts elapsed time in real time.

This timer sends a SIGALRM signal to the process

when it expires.

* A virtual timer that counts processor time used by the process.

It only runs when the process is running. This timer sends a

SIGVTALRM signal to the process when it expires.

* A profiling timer that counts both time used by the process

and processor time spent in system calls on behalf of the

process. This timer sends a SIGPROF signal to the process

when it expires. The interval timer mechanism does not

have the fine granularity necessary for profiling native code

Interval Timers



#include <sys/time.h>

intsetitimer(int which, structitimerval *new, structitimerval *old) ;



  • This is the period between successive
  • timer interrupts. If zero, the alarm
  • will only be sent once.

struct timeval it_value;

struct timeval it_interval;

  • This is the period between now and the first
  • timer interrupt. If zero, the alarm is disabled.
comprehensive example

#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

#include <sys/time.h>

// define the signal handler to write an asterisk

char astbuf[ ] = “*”;

void astWriter(int s)


write(2, astbuf, sizeof(char));


Comprehensive Example

note that we use the kernel write call because printf is not



void init_time_interrupt(void)



newact.sa_handler = astWriter; = 0;


sigaction(SIGPROF, &newact, NULL);


Signal handler is installed …

SIGPROF is the signal generated by

the profiling timer.







void setup_interval_timer(void)


structitimerval value;

value.it_interval.tv_sec = 2;

value.it_interval.tv_usec = 0;

value.it_value = value.it_interval;

setitimer(ITIMER_PROF, &value, NULL);




2 secs before

1st interrupt

2 secs between



int main (int argc, char *argv[ ])




// some useless code

for ( ; ; )