signals and signal handling. signals a predefined message sent between two processes or from the...

Post on 17-Jan-2016

217 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Signals and Signal Handling

Signals

A predefined message sent between two processes or from the kernel to a process, or by a user to a process

A software version of a hardware interrupt

It is a primitive form of interprocess communication

Signals are asynchronous

A process may receive a signal at any time during its execution

It must be prepared to respond to the signal at that time

Most are assigned an integer value (starting with 1) and a symbolic name

SIGKILL         9       /* Kill, unblockable (POSIX).  */

You can see all the defined signals by executing the command man signal.h

Signals Users send signals

with the keyboard

^c SIGINT          2       /* Interrupt */

To see the mappings of your keystrokes, enter the command stty -a

The kill command utility

kill [-signal] pid

The default signal sent is SIGTERM (15)

You may use either the integer value or the symbolic name of the signal

If after using kill pid, the process doesn't terminate, then use kill -9 pid

The kill( ) system call

Signals

Each signal type has associated with it an action which the kernel will perform on behalf of a process when the process is sent that signal

Process can Perform the default action for that signal, such as

Terminate the process Suspend the process but don't terminate it

Ignore the signal The process will be unaware that the signal has occured Two signals cannot be ignored

– SIGKILL - Terminates a process – SIGSTOP - suspends a process

Catch and handle the signal Execute a pre-arranged signal handler A process can register a special signal-handling function It will be called when the signal is received by the process

kill() system call

kill() system call: send any signal to a process group or process int kill(pid_t pid, int sig); sig is the signal to send (either integer value or symbolic name) pid specifies where to send the signal pid > 0 :The signal is sent to the process whose PID is pid pid = 0 :The signal is sent to all processes whose GID is the same as

the GID of the sender pid = -1 :The signal is sent to all processes that the current process may

send signals to If superuser: The signal is sent to all processes except init (PID 1)

sig = 0 No signal is actually sent, but all error checking is performed This can be used to see if process pid is still alive

RETURN VALUE On success (at least one signal was sent), zero is returned On error, -1 is returned, and errno is set appropriately

Example

See kill_ex.c on webpage under Code Output

> ./kill_ex

child 1 is alive

child 2 is alive

child 1 is alive

child 2 is alive

child 1 is alive

child 2 is alive

Parent is about to suspend child 1

child 2 is alive

child 2 is alive

child 2 is alive

Parent is about to resume child 1

child 1 is alive

child 2 is alive

child 1 is alive

child 2 is alive

child 1 is alive

child 2 is alive

Parent is about to terminate both children

alarm()

alarm( ) system call Each process has an alarm clock timer associated with it which it can use to

send itself SIGALRM signals

unsigned int alarm(unsigned int seconds); E.g. alarm(3) means send the calling process a SIGALRM signal 3

seconds later

If seconds is 0, any currently scheduled alarm is switched off

When alarm( ) is called, any previously scheduled alarms are cancelled alarm( ) returns

The number of seconds remaining until any previously scheduled  alarm was due to be delivered

Or zero if there was no previously scheduled alarm Include <unistd.h>

pause()

pause( ) library function

Suspends the calling process until it receives a signal

The signal must be one that is not currently set to be ignored by the calling process

If the signal is caught and doesn't cause termination

-1 is returned

errno is set to EINTR

If the signal causes termination of the calling process 

pause( ) does not return

Example

alarm(3);

while(1) {

pause();

printf(“Signal Received”); // will be printed when SIGALRM is received.

}

signal()

To ignore or catch a signal, we need to associate a signal-catching routine with that signal

signal( ) system call

sighandler_t signal(int signum, sighandler_t handler); Include <signal.h> signum is the value of the signal to be caught

You may also use the symbolic name for the signal It cannot be SIGKILL or SIGSTOP

handler is a pointer to a function This is the function (handler) that is executed if signal signum is received It may be a user-defined function Or SIG_DFL - the default action for the signal Or SIG_IGN - ignore this signal

The return value is the signal's previous handler

Example: signal_ex.c

/* This program demonstrates ignoring the SIGINT.   Follow the directions in the printf statements   to play with the program*/

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

main(){        void (*oldHandler)(int); /* To hold old handler value */

        printf("I can be Controled-C'ed\n");        sleep(3);        oldHandler = signal(SIGINT, SIG_IGN); /* Ignore Control-C */        printf("I'm protected from Control-C now\n");        sleep(3);        signal(SIGINT, oldHandler); /* Restore old handler */        printf("I can be Control-C'ed again\n");        sleep(3);        printf("Bye!\n");}

signal_ex.c

The line void (*oldHandler)(int); declares oldHandler to be a function that takes one int as an argument and returns a void pointer

Output:

> ./a.out

I can be Controled-C'ed

^C

> ./a.out

I can be Controled-C'ed

I'm protected from Control-C now

^CI can be Control-C'ed again

^C

>

User-defined signal handlers

Use the handler to execute any code that you want when the signal is received

Usually the first line in a hander is another signal( ) statement

This reestablishes the connection between the handler and the signal

This is necessary because most signals are reset to take their default action after being caught and before executing the handler

If you don't immediately execute another signal( ) statement, then you can't catch another signal of the same type

Note that there is a small time frame where if a signal is received, the default action will occur

This is what makes signals an unreliable comminication mechanism

Example: signal_ex2.c

/* This program demonstrates using a signal handler   to catch SIGINT. Notice that the connection   between the signal handler and signal is reestablished   immediately up enter the handler.

   To use:   1. As soon as it is running, hit multiple ^c's then <ret>   2. The signal handler counts the number of ^c's hit and      prints out the total   3. The default signal handler is then reestablished   4. Hit another ^c and the program ends*/

Example: signal_ex2.c #include <stdio.h>

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

int ctrl_c_count = 0;void (* old_handler)(int);void ctrl_c(int);

main(){        int c;

        old_handler = signal(SIGINT, ctrl_c);

        while ((c = getchar())!='\n');        printf("ctrl-c count = %d\n", ctrl_c_count);

        (void) signal(SIGINT, old_handler);

        for (;;);}

void ctrl_c(int signum){        (void) signal(SIGINT, ctrl_c);        ++ctrl_c_count;}

output

> ./a.out

^C^C^C

ctrl-c count = 3

^C

>

sigsaction( ) system call

int sigaction(int signum,  const  struct  sigaction  *act, struct sigaction *oldact);

used to associate an action with a signal

signum is the number of the signal to handle

May be a symbolic name

May not be SIGKILL or SIGSTOP

act is a structure that holds the pointer to the name of the handler to associate with the signal

oldact holds the pointer to the routine that was the signal's previous handler

One important difference between sigaction and signal

The signal handling routine stays installed even after a signal has been caught

So you don't have to reset the signal handler in the signal handling routine

struct sigaction {     void (*sa_handler)(int);     void (*sa_sigaction)(int, siginfo_t *, void *);     sigset_t sa_mask;     int sa_flags;} sa_handler - the name of the handler sa_sigaction - do not use for now sa_mask - gives  a  mask of signals which should be blocked during execution of

the signal handler flags - modify the behavior of the signal handling process

Here is a list of flags on brunel. See man pages for details.– SA_ONSTACK – SA_RESETHAND– SA_NODEFER  – SA_RESTART  – SA_SIGINFO – SA_NOCLDWAIT – SA_NOCLDSTOP

sigaction_ex.c #include <stdio.h>

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

int ctrl_c_count = 0;void ctrl_c(int);

main(){        int c, i;        struct sigaction new_action;        struct sigaction old_action;

        new_action.sa_handler = ctrl_c;        new_action.sa_flags = 0;

        sigaction( SIGINT, &new_action, &old_action );

        for ( i = 0; i < 3; i++ )        {             while ((c = getchar())!='\n');             printf("ctrl-c count = %d\n", ctrl_c_count);        }

        sigaction( SIGINT, &old_action, NULL );

        for (;;);}

void ctrl_c(int signum){        ++ctrl_c_count;}

output

> ./a.out

^C^C

ctrl-c count = 2

^C^C^C^C

ctrl-c count = 6

^C^C^C^C

ctrl-c count = 10

^C

>

sigprocmask( ) system call Each process has a signal mask which is a set of signals that are currently

blocked from delivery If a blocked signal is sent to a process anyway

It is added to a set of pending signals for the process It will be delivered when the block is removed

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

changes the list of currently blocked signals how indicates how the list of signals in set should be treated

SIG_BLOCK The set of blocked signals is the union of the current set and set

SIG_UNBLOCK The signals in set are removed from the current set of blocked signals

SIG_SETMASK The set of blocked signals is set to set

oldset contains the previous value of the signal mask

Example: sigprocmask_ex.c

In this example, I will use SIGUSR1 and SIGUSR2.

The definition of these in signal.h is:

     Name             Value   Default    Event     SIGUSR1          16      Exit       User Signal 1     SIGUSR2          17      Exit       User Signal 2

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

sigset_t new_signals;

int main(){     void signal_catcher( int );  // forward declaration of handler     struct sigaction new_action;

     sigemptyset( &new_signals );  // Empties the set of blocked signals     sigaddset( &new_signals, SIGUSR1 ); // Adds SIGUSR1 to the set of                                         // blocked signals

     sigprocmask( SIG_BLOCK, &new_signals, NULL ); // Unions the set of process                                                   // blocked signals with new_signals

     new_action.sa_handler = signal_catcher;     new_action.sa_flags = 0;

     /* Associate the handler with SIGUSR2 */     sigaction( SIGUSR2, &new_action, NULL );

     printf( "Waiting for signal\n" );     pause( );  // Sleep until a signal is received     printf( "Done\n" );     return 0;}

void signal_catcher( int n ){     printf( "Received signal %i will release SIGUSR1\n", n );     sigprocmask( SIG_UNBLOCK, &new_signals, NULL );     printf( "SIGUSR1 released!\n" );}

Output> ./a.out &

[1] 21551

> Waiting for signal

kill -USR1 21551

> ps

PID TTY TIME CMD

21339 pts/17 0:00 tcsh

21558 pts/17 0:00 ps

21329 pts/17 0:00 csh

21551 pts/17 0:00 a.out

> kill -USR2 21551

Received signal 17 will release SIGUSR1

> ps

PID TTY TIME CMD

21339 pts/17 0:00 tcsh

21329 pts/17 0:00 csh

21559 pts/17 0:00 ps

[1] + User signal 1 ./a.out

Pending signal SIGUSR1 can now

terminate the process

sigsuspend( ) system call

int sigsuspend(const sigset_t *mask);

Is used to suspend a process

It replaces the current signal mask with mask

The process is suspended until a signal is delivered whose action is to

Execute a signal-catching function

Or terminate the process

If the action is to terminate the process, sigsuspend() does not return.

If the action is to execute a signal catching function, sigsuspend() returns after the signal catching function returns. On return, the signal mask is restored to the set that existed before the call to sigsuspend().

sigsuspend_ex.c

/* This program demonstrates using sigsuspend

   To use:   1. a.out &   2. kill -USR1 %1   3. kill -INT %1   4. Then immediately issue a jobs command

*/

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

int main(){     void signal_catcher( int );  // forward declaration of handler     struct sigaction new_action;     sigset_t no_sigs, blocked_sigs, all_sigs;

     sigfillset( &all_sigs );      // Turn all bits on     sigemptyset( &no_sigs );      // Turn all bits off to mean no signals blocked    

sigemptyset( &blocked_sigs );  // Initialize

     new_action.sa_handler = signal_catcher;     new_action.sa_mask    = all_sigs;     new_action.sa_flags   = 0;

     /* Associate the handler with SIGUSR1 */     sigaction( SIGUSR1, &new_action, NULL );

     sigaddset( &blocked_sigs, SIGUSR1 );     sigprocmask( SIG_SETMASK, &blocked_sigs, NULL );     while( 1 )     {          printf( "Waiting for SIGUSR1 signal\n" );          sigsuspend( &no_sigs );     }

     printf( "Done\n" );     return 0;}

void signal_catcher( int n ){     printf( "Beginning important stuff...\n" );     sleep( 10 );     printf( "Ending important stuff\n" );}

Output

> ./a.out &

[1] 21674

> Waiting for SIGUSR1 signal

kill -USR1 21674

Beginning important stuff...

Ending important stuff

Waiting for SIGUSR1 signal

kill -INT 21674

> ps

PID TTY TIME CMD

21339 pts/17 0:00 tcsh

21683 pts/17 0:00 ps

21329 pts/17 0:00 csh

[1] + Interrupt ./a.out

Example: alarm_ex.c/* This program demonstrates the alarm( ) system call */

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

int alarmFlag = 0; /* alarm flag */void alarmHandler(); /* Forward declaration of alarm handler */

main(){        signal(SIGALRM, alarmHandler); /* Install signal handler */        alarm(3); /* Schedule an alarm signal in 3 seconds */        printf("Looping....\n");        while(!alarmFlag) /* Loop until flag set */        {           pause(); /* Wait for signal */        }        printf("Loop ends due to alarm signal\n");}

void alarmHandler(){        printf("An alarm clock signal was received\n");        alarmFlag = 1;}

output

> ./a.out

Looping....

An alarm clock signal was received

Loop ends due to alarm signal

>

Example: sigchld_ex.c

/* This program allows a user to limit the amount of time that a command takes   to execute.  The first parameter to sigchld.out is the maximum # of seconds   that is allowed for execution, and the remaining parameters are the command   itself.

   STEPS:   1. Parent process installs a SIGCHLD handler   2. Parent forks a child process to execute the command   3. Parent sleeps for specified number of seconds.  When it wakes up, it      sends the child process a SIGINT to kill it   4. If child terminates before its parent wakes up, the parent's SIGCHLD      handler is executed, causing the parent to terminate immediately.

   To use: a.out <num of secs> <command>

*/

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

int delay;void childHandler();

main(int argc, char* argv[]){        int pid;        signal(SIGCHLD, childHandler); /* Install death-of-child handler */

        pid = fork(); /* Duplicate */        if (pid == 0) /* Child */        {           execvp(argv[2], &argv[2]); /* execute command */           perror("sigchld"); /* Should never execute */        }        else /* parent */        {           sscanf(argv[1], "%i", &delay); /* Read delay from command line */           printf("delay is: %i\n", delay);           sleep(delay); /* Sleep for the specified number of seconds */           printf("Child %i exceeded limit and is being killed\n", pid);           kill(pid, SIGINT); /* Kill the child */        }}

void childHandler(){        int childPid, childStatus;        childPid = wait(&childStatus); /* Accept child's termination code */        printf("Child %i terminated within %i seconds\n", childPid, delay);        exit (0);}

output

> ./a.out 2 ls

delay is: 2

a.out sigaction_ex.c signal_ex.c sigpending_ex.c sigsuspend_ex.c

alarm_ex.c sigchld_ex.c signal_ex2.c sigprocmask_ex.c

Child 21804 terminated within 2 seconds

> ./a.out 2 sleep 4

delay is: 2

Child 21806 exceeded limit and is being killed

>

top related