Thursday, June 16, 2011

Signals

11.  <signal.h>  Signals

The header <signal.h> provides facilities for handling exceptional conditions that arise during execution, such as an interrupt signal from an external source or an error in execution.
void (*signal(int sig, void (*handler)(int)))(int)
signal specifies the new signal handler handler for the signal sig and returns the previous handler, if successful; otherwise, it returns SIG_ERR.
l  If handler is SIG_DFL, the implementation-defined default behavior is used for the signal.
l  If handler is SIG_IGN, the signal is ignored;
l  Otherwise, the function handler will be called with the value of the signal as its argument.
Valid signals include:

SIGABRT
abnormal termination
e.g.) abort
SIGFPE
arithmetic error
e.g.) zero divide or overflow
SIGILL
illegal function image
e.g.) illegal instruction
SIGINT
interactive attention
e.g.) interrupt
SIGSEGV
illegal storage access
e.g.) access outside memory limits
SIGTERM  
termination request


When the signal sig subsequently occurs, the signal is restored to its default behavior; then the signal handler function is called, as if by (*handler)(sig). If the handler returns, execution will resume where it was when the signal occurred.
The initial state of signals is implementation-defined.
int raise(int sig)
raise sends the signal sig to the program; it returns non-zero if unsuccessful.

Example codes
l sig-1.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sh_SIGABRT(int sig) {
    printf("handling SIGABRT ...\n");
    exit(0);
}

void main() {
    printf("set: sh_SIGABRT\n"); signal(SIGABRT, sh_SIGABRT);
    abort();
    printf("end of main\n");
}
>   sig-1
set: sh_SIGABRT

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
handling SIGABRT ...
>   echo %ERRORLEVEL%
0
l sig-2.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

typedef void (*SH_T)(int);  // signal handler type

void sh_SIGTERM_1(int sig) {
    printf("sh_SIGTERM_1: handling SIGTERM ...\n");
}
void sh_SIGTERM_2(int sig) {
    printf("sh_SIGTERM_2: handling SIGTERM ...\n");
}

void main() {
    SH_T sh;

    printf("set: sh_SIGTERM_1\n");
    if (signal(SIGTERM, sh_SIGTERM_1) == SIG_ERR)
        fprintf(stderr, "cannot set sh_SIGTERM_1\n"), exit(1);

    printf("set: sh_SIGTERM_2\n");
    if ((sh = signal(SIGTERM, sh_SIGTERM_2)) == SIG_ERR)
        fprintf(stderr, "cannot set sh_SIGTERM_2\n"), exit(1);
    raise(SIGTERM);

    printf("reset: sh_SIGTERM_1\n");
    if (signal(SIGTERM, sh) == SIG_ERR)
        fprintf(stderr, "cannot set sh_SIGTERM_1\n"), exit(1);
    raise(SIGTERM);
}
>   sig-2
set: sh_SIGTERM_1
set: sh_SIGTERM_2
sh_SIGTERM_2: handling SIGTERM ...
reset: sh_SIGTERM_1
sh_SIGTERM_1: handling SIGTERM ...
>   echo %ERRORLEVEL%
0
l sig-3.c
#include <stdio.h>
#include <signal.h>
void main() {
    printf("set: SIG_IGN\n"); signal(SIGTERM, SIG_IGN);
    printf("raising SIGTERM ...\n"); raise(SIGTERM);
    printf("raised SIGTERM\n");
    printf("raising SIGTERM ...\n"); raise(SIGTERM);
    printf("raised SIGTERM\n");

    printf("set: SIG_DFL\n"); signal(SIGTERM, SIG_DFL);
    printf("raising SIGTERM ...\n"); raise(SIGTERM);
    printf("raised SIGTERM\n");    // not executed
}
>   sig-3
set: SIG_IGN
raising SIGTERM ...
raised SIGTERM
raising SIGTERM ...
raised SIGTERM
set: SIG_DFL
raising SIGTERM ...
>   echo %ERRORLEVEL%
3
l sig-4.c
#include <stdio.h>
#include <signal.h>

void sh_SIGTERM(int sig) {
    printf("sh_SIGTERM: handling SIGTERM ...\n");
}

void main() {
    printf("set: sh_SIGTERM\n"); signal(SIGTERM, sh_SIGTERM);
    printf("raising SIGTERM ...\n"); raise(SIGTERM);
    printf("raised SIGTERM\n");
    printf("raising SIGTERM ...\n"); raise(SIGTERM);
    printf("raised SIGTERM\n");    // not executed
}
>   sig-4
set: sh_SIGTERM
raising SIGTERM ...
sh_SIGTERM: handling SIGTERM ...
raised SIGTERM
raising SIGTERM ...
l sig-5.c
#include <stdio.h>
#include <signal.h>

void sh_SIGTERM(int sig) {
    printf("handling SIGTERM ...\n");
    printf("set: sh_SIGTERM\n"); signal(SIGTERM, sh_SIGTERM);
}

void main() {
    printf("set: sh_SIGTERM\n"); signal(SIGTERM, sh_SIGTERM);
    printf("raising SIGTERM ...\n"); raise(SIGTERM);
    printf("raised SIGTERM\n");
    printf("raising SIGTERM ...\n"); raise(SIGTERM);
    printf("raised SIGTERM\n");
}
>   sig-5
set: sh_SIGTERM
raising SIGTERM ...
handling SIGTERM ...
set: sh_SIGTERM
raised SIGTERM
raising SIGTERM ...
handling SIGTERM ...
set: sh_SIGTERM
raised SIGTERM
l sig-6.c
#include <stdio.h>
#include <signal.h>

void sh(int sig) {
    if (sig == SIGTERM)
        printf("handling SIGTERM ...\n"), signal(sig, sh);
    else if (sig == SIGABRT)
        printf("handling SIGABRT ...\n"), signal(sig, sh);
    else
        printf("no action for signal '%d' only once\n", sig);
}

void main() {
    signal(SIGTERM, sh);              signal(SIGABRT, sh);
    signal(SIGINT,  sh);              signal(SIGILL,  sh);

    raise(SIGTERM); raise(SIGTERM);
    raise(SIGABRT); raise(SIGABRT);
    raise(SIGILL);
    raise(SIGINT);
    raise(SIGINT); // **
    printf("end of main\n");
}
>   sig-6
handling SIGTERM ...
handling SIGTERM ...
handling SIGABRT ...
handling SIGABRT ...
no action for signal '4' only once
no action for signal '2' only once
l sig-7.c
#include <stdio.h>
#include <signal.h>

void sh_SIGINT(int sig) {
    static int count = 3;
    printf("handle SIGINT ...\n");
    if (--count > 0) signal(SIGINT, sh_SIGINT);
}

void main() {
    signal(SIGINT, sh_SIGINT);
    while (1) ;
}
>   sig-7
^Chandle SIGINT ...
^Chandle SIGINT ...
^Chandle SIGINT ...
^C

No comments: