UNIX System Programming Overview Signals 1. Definition 2. Signal Types 3. Generating a Signal 4. Responding to a Signal Objectives 5. Common Uses of Signals – Introduce signals 6. Implementing a read() – Concentrate on sigaction() function Timeout
continued 1730 UNIX System Programming: Signals Maria Hybinette 1 1730 UNIX System Programming: Signals Maria Hybinette 2
1. Definition 7. POSIX Signal Functions A signal is an asynchronous event which is 8. Interrupted System Calls delivered to a process. 9. System Calls inside Handlers 10. More Information Asynchronous means that the event can occur at any time – may be unrelated to the execution of the process – e.g. user types ctrl-C, or the modem hangs
1730 UNIX System Programming: Signals Maria Hybinette 3 1730 UNIX System Programming: Signals Maria Hybinette 4
2. Signal Types (31 in POSIX) Signal Sources terminal memory Name Description Default Action driver management shell command SIGINT Interrupt character typed terminate process SIGQUIT Quit character typed (^\) create core image SIGINT SIGHUP SIGKILL kill -9 terminate process SIGQUIT SIGSEGV Invalid memory reference create core image SIGKILL kernel SIGPIPE SIGPIPE Write on pipe but no reader terminate process SIGALRM alarm() clock ‘rings’ terminate process SIGUSR1 user-defined signal type terminate process SIGWINCH SIGALRM SIGUSR2 user-defined signal type terminate process window : manager a process SIGUSR1
See man 7 signal other user processes 1730 UNIX System Programming: Signals Maria Hybinette 5 1730 UNIX System Programming: Signals Maria Hybinette 6
UNIX: Signals Maria Hybinette 1 3. Generating a Signal kill()
Use the UNIX command: $ kill -KILL 4481 Send a signal to a process (or group of processes). – send a SIGKILL signal to pid 4481 – check #include
kill is not a good name; send_signal Return 0 if ok, -1 on error. might be better.
1730 UNIX System Programming: Signals Maria Hybinette 7 1730 UNIX System Programming: Signals Maria Hybinette 8
4. Responding to a Signal Some pid Values A process can: – ignore/discard the signal (not possible with pid Meaning SIGKILL or SIGSTOP)
> 0 send signal to process pid – execute a signal handler function, and then possibly resume execution or terminate == 0 send signal to all processes whose process group ID – carry out the default action for that signal equals the sender’s pgid. e.g. parent kills all children The choice is called the process’ signal disposition
1730 UNIX System Programming: Signals Maria Hybinette 9 1730 UNIX System Programming: Signals Maria Hybinette 10
signal(): library call Actual Prototype The actual prototype, listed in the “man” page is a bit Specify a signal handler function to deal with a signal type. perplexing but is an expansion of the Sigfunc type:
#include
– signal returns a pointer to a function that returns an int (i.e. it sig_handler_t signal(int signo, sighandler_t handler); returns a pointer to Sigfunc
Signal returns a pointer to a function that returns an int Returns previous signal disposition if ok, SIG_ERR on error.
1730 UNIX System Programming: Signals Maria Hybinette 11 1730 UNIX System Programming: Signals Maria Hybinette 12
UNIX: Signals Maria Hybinette 2 The signal function itself returnsSignal a pointer toHandling a function. Example The return type is the same as the function that is passedThe signal in, toThe be handler function int main() { i.e., aUse function the signal that handling takes caughtlibrary: an or ignored signal.hReceives a single integer signal( SIGINT, foo ); int and returns a void is given as argumentArgument and returns void : Then can use the signal call: sig /* do usual things until SIGINT */ #include
1730 UNIX System Programming: Signals Maria Hybinette 13 1730 UNIX System Programming: Signals Maria Hybinette 14
sig_examp.c
#include
continued continued 1730 UNIX System Programming: Signals Maria Hybinette 15 1730 UNIX System Programming: Signals Maria Hybinette 16
Usage void sig_usr( int signo ) /* argument is signal number */ { $ sig_examp & if( signo == SIGUSR1 ) [1] 4720 printf(“Received SIGUSR1\n”); 0 else if( signo == SIGUSR2 ) $ kill -USR1 4720 printf(“Received SIGUSR2\n”); Received SIGUSR1 else 1 printf(“Error: received signal $ kill -USR2 4720 %d\n”, signo); Received SIGUSR2 2 return; $ kill 4720 /* send SIGTERM */ } [1] + Terminated sig_examp & $ 1730 UNIX System Programming: Signals Maria Hybinette 17 1730 UNIX System Programming: Signals Maria Hybinette 18
UNIX: Signals Maria Hybinette 3 Special Sigfunc * Values Multiple Signals If many signals of the same type are waiting Value Meaning to be handled (e.g. two SIGINTs), then most UNIXs will only deliver one of them. SIG_IGN Ignore / discard the signal. SIG_IGN – the others are thrown away
SIG_DFL Use default action to handle signal.
SIG_ERR Returned by signal() as an error. If many signals of different types are waiting to be handled (e.g. a SIGINT, SIGSEGV, SIGUSR1), they are not delivered in any fixed order.
1730 UNIX System Programming: Signals Maria Hybinette 19 1730 UNIX System Programming: Signals Maria Hybinette 20
pause() The Reset Problem Suspend the calling process until a signal is caught. In Linux (and many other UNIXs), the #include
pause() only returns after a signal handler has Must call signal() again to reinstall the returned. signal handler function.
1730 UNIX System Programming: Signals Maria Hybinette 21 1730 UNIX System Programming: Signals Maria Hybinette 22
To keep catching Reset Problem the signal with this Reset Problem Example function, must call : the signal system int main() void ouch( int sig ) call again. { { signal(SIGINT, foo); printf( "OUCH! - I got signal %d\n", sig ); : (void) signal(SIGINT, ouch); /* do usual things until SIGINT */ } } Problem: from the time int main() that the interrupt function { starts to just before the void foo(int signo) signal handler is re-established (void) signal( SIGINT, ouch ); { the signal will not be while(1) handled. signal(SIGINT, foo); /* reinstall */ { : printf("Hello World!\n"); return; sleep(1); If another SIGINT signal is } } received during this time, default behavior will be done, } 1730 UNIX System Programming: Signals Maria Hybinette 23 1730 UNIX System Programming: Signals Maria Hybinette i.e., program will terminate.24
UNIX: Signals Maria Hybinette 4 Re-installation may be too 5. Common Uses of slow! Signals There is a (very) small time period in foo() 5.1. Ignore a Signal when a new SIGINT signal will cause the default action to be carried out -- process 5.2. Clean up and Terminate termination. 5.3. Dynamic Reconfiguration 5.4. Report Status With signal() there is no answer to this problem. 5.5. Turn Debugging on/off – POSIX signal functions solve it (and some 5.6. Restore Previous Handler other later UNIXs)
1730 UNIX System Programming: Signals Maria Hybinette 25 1730 UNIX System Programming: Signals Maria Hybinette 26
5.2. Clean up and 5.1. Ignore a Signal Terminate : int main() : { /* global variables */ signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN); int my_children_pids; signal(SIGQUIT, SIG_IGN); : : /* do work without interruptions */ void clean_up(int signo); } int main() Cannot ignore/handle SIGKILL or SIGSTOP { Should check for SIG_ERR signal(SIGINT, clean_up); : } continued 1730 UNIX System Programming: Signals Maria Hybinette 27 1730 UNIX System} Programming: Signals Maria Hybinette 28
Problems void clean_up(int signo) { If a program is run in the background then unlink(“/tmp/work-file”); the interrupt and quit signals (SIGINT, kill(my_children_pids, SIGTERM); SIGQUIT) are automatically ignored. wait((int *)0); fprintf(stderr, “Program terminated\n”); Your code should not override these exit(1); changes: } – check if the signal dispositions are SIG_IGN
1730 UNIX System Programming: Signals Maria Hybinette 29 1730 UNIX System Programming: Signals Maria Hybinette 30
UNIX: Signals Maria Hybinette 5 Checking the Disposition 5.3. Dynamic new disposition old disposition Reconfiguration
: : if( signal(SIGINT, SIG_IGN ) != SIG_IGN ) void read_config(int signo); signal(SIGINT, clean_up); int main() if( signal(SIGQUIT, SIG_IGN ) != SIG_IGN ) { signal(SIGQUIT, clean_up); read_config(0); /* dummy argument */ : while (1) /* work forever */ Note: cannot check the signal disposition without } changing it (sigaction that we will look at later , is different) continued 1730 UNIX System Programming: Signals Maria Hybinette 31 1730 UNIX System Programming: Signals Maria Hybinette 32
void read_config(int signo) Problems { int fd;
signal( SIGHUP, read_config ); Reset problem fd = open(“config_file”, O_RDONLY); /* read file and set global vars */ Handler interruption close(fd); – what is the effect of a SIGHUP in the middle of return; read_config()’s execution? } Can only affect global variables.
1730 UNIX System Programming: Signals Maria Hybinette 33 1730 UNIX System Programming: Signals Maria Hybinette 34
void print_status(int signo) 5.4. Report Status { signal(SIGUSR1, print_status); : signal(SIGUSR1, print_status); void print_status(int signo); printf(“%d blocks copied\n”, count); int count; /* global */ return; } int main() { signal(SIGUSR1, print_status); : Reset problem for( count=0; count < BIG_NUM; count++ ) count value not always defined. { /* read block from tape */ Must use global variables for status information /* write block to disk */ } ... } continued 1730 UNIX System Programming: Signals Maria Hybinette 35 1730 UNIX System Programming: Signals Maria Hybinette 36
UNIX: Signals Maria Hybinette 6 5.5. Turn Debugging on/off
: void toggle_debug(int signo); void toggle_debug(int signo) { int debug = 0; /* initialize here */ signal(SIGUSR2, toggle_debug); int main() { debug = ((debug == 1) ? 0 : 1); signal(SIGUSR2, toggle_debug); return; /* do work */ } if (debug == 1) printf(“...”); ... continued 1730 UNIX} System Programming: Signals Maria Hybinette 37 1730 UNIX System Programming: Signals Maria Hybinette 38
5.6. Restore Previous 6. Implementing a read() Handler Timeout : Put an upper limit on an operation that Sigfunc *old_hand; Put an upper limit on an operation that might block forever /* set action for SIGTERM; – e.g. read() save old handler */ old_hand = signal(SIGTERM, foobar); 6.1. alarm() /* do work */ 6.2. Bad read() Timeout /* restore old handler */ 6.3. setjmp() and longjmp() signal(SIGTERM, old_hand); 6.4. Better read() Timeout :
1730 UNIX System Programming: Signals Maria Hybinette 39 1730 UNIX System Programming: Signals Maria Hybinette 40
6.1. alarm() Some Tricky Aspects A process can have at most one alarm timer Set an alarm timer that will ‘ring’ after a running at once. specified number of seconds – a signal is generated – a SIGALRM signal is generated If alarm() is called when there is an existing alarm set then it returns the number #include
UNIX: Signals Maria Hybinette 7 if( signal(SIGALRM, sig_alrm) == SIG_ERR ) 6.2. Bad read() Timeout { printf(“signal(SIGALRM) error\n”); #include
Problems The code assumes that the read() call terminates with an error after being interrupted ( talk about void sig_alrm(int signo) this later). /* do nothing, just handle signal */ { Race Conditon: The kernel may take longer than return; 10 seconds to start the read() after the alarm() } call. – the alarm may ‘ring’ before the read() starts – then the read() is not being timed; may block forever – Two ways two solve this one uses setjmp and the other uses sigprocmask and sigsuspend
1730 UNIX System Programming: Signals Maria Hybinette 45 1730 UNIX System Programming: Signals Maria Hybinette 46
6.3. setjmp() and longjmp() Prototypes
In C we cannot use goto to jump to a label in #include
1730 UNIX System Programming: Signals Maria Hybinette 47 1730 UNIX System Programming: Signals Maria Hybinette 48
UNIX: Signals Maria Hybinette 8 Example Behavior : jmp_buf env; /* global */ In the setjmp() call, env is initialized to information about the current state of the int main() { stack. char line[MAX]; int errval;
The longjmp() call causes the stack to be if(( errval = setjmp(env) ) != 0 ) printf( “error %d: restart\n”, errval ); reset to its env value. while( fgets( line, MAX, stdin ) != NULL ) process_line(line); Execution restarts after the setjmp() call, return 0; } but this time setjmp() returns val. continued 1730 UNIX System Programming: Signals Maria Hybinette 49 1730 UNIX System Programming: Signals Maria Hybinette 50
: void process_line( char * ptr ) { : Stack Frames at setjmp() cmd_add() : } top of stack void cmd_add() main() { int token; stack frame token = get_token(); setjmp(env) if( token < 0 ) /* bad error */ longjmp( env, 1 ); returns 0; env records stack /* normal processing */ direction of } stack growth frames info int get_token() { if( some error ) longjmp( env, 2 ); }
1730 UNIX System Programming: Signals Maria Hybinette 51 1730 UNIX System Programming: Signals Maria Hybinette 52
Stack Frames at longjmp() sleep1() #include
UNIX: Signals Maria Hybinette 9 sleep2() Sleep1 and Sleep2 static void jmp_buf env_alrm; Sleep2 fixes race condition. Even if the void sig_alrm( int signo ) { pause is never executed. longjmp( env_alrm, 1 ); } unsigned int sleep2( unsigned int nsecs ) There is one more problem (will talk about { if( signal( SIGALRM, sig_alrm ) == SIG_ERR ) that after “fixing the earlier read function”) return (nsecs); if( setjmp( env_alrm) == 0 ) { alarm( nsecs ); /* starts timer */ pause(); /* next caugt signal wakes } return( alarm( 0 ) ); continued 1730 UNIX System} Programming: Signals Maria Hybinette 55 1730 UNIX System Programming: Signals Maria Hybinette 56
Status of Variables? 6.4. Better read() Timeout
The POSIX standard says: #include
Nothing is specified about local variables, #define MAXLINE 512 void sig_alrm( int signo ); are they “rolled back” to their original jmp_buf env_alrm; values (at the setjmp call) as the stack”? – they may be restored to their values at the first int main() setjmp(), but maybe not { int n; setjmp() char line[MAXLINE]; Most implementations do not roll back their values : continued 1730 UNIX System Programming: Signals Maria Hybinette 57 1730 UNIX System Programming: Signals Maria Hybinette 58
if( signal(SIGALRM, sig_alrm) == SIG_ERR) { printf(“signal(SIGALRM) error\n”); exit(1); : } if( n < 0 ) /* read error */ fprintf( stderr, “\nread error\n” ); if( setjmp(env_alrm) != 0 ) else { write( 1, line, n ); fprintf(stderr, “\nread() too slow\n”); return 0; exit(2); } }
alarm(10); n = read(0, line, MAXLINE); alarm(0); : continued continued 1730 UNIX System Programming: Signals Maria Hybinette 59 1730 UNIX System Programming: Signals Maria Hybinette 60
UNIX: Signals Maria Hybinette 10 Caveat: Non-local Jumps
void sig_alrm(int signo) From the UNIX man pages: /* interrupt the read() and jump to setjmp() call with value 1 */ WARNINGS If longjmp() or siglongjmp() are called even though env was { never primed by a call to setjmp() or sigsetjmp(), or when longjmp(env_alrm, 1); the last such call was in a function that has since } returned, absolute chaos is guaranteed.
1730 UNIX System Programming: Signals Maria Hybinette 61 1730 UNIX System Programming: Signals Maria Hybinette 62
A Problem Remains! 7. POSIX Signal Functions
If the program has several signal handlers The POSIX signal functions can control then: signals in more ways: – execution might be inside one when an alarm ‘rings’ – can block signals for a while, and deliver them later (good for coding critical sections) – the longjmp() call will jump to the location, and abort the other setjmp() location, and abort the other – can switch off the resetting of the signal signal handler -- might lose / corrupt data disposition when a handler is called (no reset problem)
1730 UNIX System Programming: Signals Maria Hybinette 63 1730 UNIX System Programming: Signals Maria Hybinette 64
7.1. Signal Sets
The POSIX signal system, uses signal sets, to The signal set stores collections of signal deal with pending signals that might otherwise types. be missed while a signal is being processed Sets are used by signal functions to define which signal types are to be processed.
POSIX contains several functions for creating, changing and examining signal sets.
1730 UNIX System Programming: Signals Maria Hybinette 65 1730 UNIX System Programming: Signals Maria Hybinette 66
UNIX: Signals Maria Hybinette 11 Prototypes 7.2. sigprocmask()
#include
1730 UNIX System Programming: Signals Maria Hybinette 67 1730 UNIX System Programming: Signals Maria Hybinette 68
how Meanings A Critical Code Region : Value Meaning sigset_t newmask, oldmask;
sigemptyset( &newmask ); SIG_BLOCK set signals are added to mask sigaddset( &newmask, SIGINT );
SIG_UNBLOCK set signals are removed from mask /* block SIGINT; save old mask */ sigprocmask( SIG_BLOCK, &newmask, &oldmask ); SIG_SETMASK set becomes new mask /* critical region of code */
/* reset mask which unblocks SIGINT */ sigprocmask( SIG_SETMASK, &oldmask, NULL ); : 1730 UNIX System Programming: Signals Maria Hybinette 69 1730 UNIX System Programming: Signals Maria Hybinette 70
7.3. sigaction() sigaction Structure
struct sigaction { Supercedes (more powerful than) signal() void (*sa_handler)( int ); /* action to be taken or SIG_IGN, SIG_DFL */ – sigaction() can be used to code a non- sigset_t sa_mask; /* additional signal to be blocked */ resetting signal() int sa_flags; /* modifies action of the signal */ void (*sa_sigaction)( int, siginfo_t *, void * );
} #include
1730 UNIX System Programming: Signals Maria Hybinette 71 1730 UNIX System Programming: Signals Maria Hybinette 72
UNIX: Signals Maria Hybinette 12 Signal Raising struct sigaction sigaction() Behavior { int main() void (*) (int) sa_handler { sigset_t sa_mask int sa_flags struct sigaction act; A signo signal causes the sa_handler signal }
handler to be called. act.sa_handler = ouch;
sigemptyset( &act.sa_mask ); While sa_handler executes, the signals in Set the signal handler to sa_mask are blocked. Any more signo signals are act.sa_flags = 0; be the function ouch also blocked. sigaction( SIGINT, &act, 0 No); flags are needed here. We can manipulate Possible flags include: while(1) SA_NOCLDSTOP sets of signals.. sa_handler remains installed until it is changed by { SA_RESETHAND another sigaction() call. No reset problem. printf("Hello World!\n");SA_RESTART sleep(1); This call setsSA_NODEFER the signal } handler for the SIGINT (ctrl-C) signal 1730 UNIX System Programming: Signals Maria Hybinette 73 1730 UNIX System} Programming: Signals Maria Hybinette 74
Signal Raising sigexPOS.c /* sigexPOS.c - demonstrate sigaction() */ /* include files as before */ This function will continually capture the ctrl-C (SIGINT) signal. int main(void) { /* struct to deal with action on signal set */ Default behavior is not restored after signal static struct sigaction act; is caught. void catchint(int); /* user signal handler */
To terminate the program, must type ctrl-\, /* set up action to take on receipt of SIGINT */ the SIGQUIT signal. act.sa_handler = catchint;
1730 UNIX System Programming: Signals Maria Hybinette 75 1730 UNIX System Programming: Signals Maria Hybinette 76
/* create full set of signals */ Signals - Ignoring signals sigfillset(&(act.sa_mask)); Other than SIGKILL and SIGSTOP, signals can be /* before sigaction call, SIGINT will terminate ignored: * process */
Instead of in the previous program: /* now, SIGINT will cause catchint to be executed */ sigaction( SIGINT, &act, NULL ); sigaction( SIGQUIT, &act, NULL ); act.sa_handler = catchint /* or whatever */ We use: printf("sleep call #1\n"); act.sa_handler = SIG_IGN; sleep(1); The ^C key will be ignored /* rest of program as before */
1730 UNIX System Programming: Signals Maria Hybinette 77 1730 UNIX System Programming: Signals Maria Hybinette 78
UNIX: Signals Maria Hybinette 13 Restoring previous action A Basic signal()
#include
act.sa_handler = SIG_IGN; act.sa_flags |= SA_INTERRUPT; if( signo != SIGALRM ) sigaction( SIGTERM, &act, NULL ); act.sa_flags |= SA_RESTART; /* any system call interrupted by a signal * other than alarm is restarted */ /* restore old action */ if( sigaction( signo, &act, &oact) < 0 ) sigaction( SIGTERM, &oact, NULL ); return(SIG_ERR); return( oact.sa_handler ); } 1730 UNIX System Programming: Signals Maria Hybinette 79 1730 UNIX System Programming: Signals Maria Hybinette 80
7.4. Other POSIX [sig]longjmp & [sig]setjmp Functions
sigpending() examine blocked signals NOTES (longjmp, sigjmp) POSIX does not specify whether longjmp will restore the signal context. If you want to save and restore signal sigsetjmp() masks, use siglongjmp. siglongjmp() jump functions for use in signal handlers which NOTES (setjmp, sigjmp) handle masks correctly POSIX does not specify whether setjmp will save the signal context. (In SYSV it will not. In BSD4.3 it will, and there is a function _setjmp that will not.) If you want sigsuspend() atomically reset mask to save signal masks, use sigsetjmp. and sleep
1730 UNIX System Programming: Signals Maria Hybinette 81 1730 UNIX System Programming: Signals Maria Hybinette 82
Example 8. Interrupted System Calls #include
UNIX: Signals Maria Hybinette 14 Slow System Functions Non-slow System Functions
Slow system functions carry out I/O on Most system functions are non-slow, including things that can possibly block the caller ones that do disk I/O forever: – e.g. read() of a disk file – read() is sometimes a slow function, sometimes not – pipes, terminal drivers, networks
– some IPC functions Some UNIXs resume non-slow system functions – pause(), some uses of ioctl() after the handler has finished.
Can use signals on slow system functions to Some UNIXs only call the handler after the non- code up timeouts (e.g. did earlier ) slow system function call has finished. 1730 UNIX System Programming: Signals Maria Hybinette 85 1730 UNIX System Programming: Signals Maria Hybinette 86
9. System Calls inside Non-reentrant Functions Handlers
If a system function is called inside a signal A functions may be non-reentrant (only one call handler then it may interact with an interrupted to it at once) for a number of reasons: call to the same function in the main code. – it uses a static data structure – e.g. malloc() – it manipulates the heap: malloc(), free(), etc. This is not a problem if the function is reentrant – a process can contain multiple calls to these functions at – it uses the standard I/O library the same time e,g, scanf(), printf() – e.g. read(), write(), fork(), many more the library uses global data structures in a non-reentrant way
1730 UNIX System Programming: Signals Maria Hybinette 87 1730 UNIX System Programming: Signals Maria Hybinette 88
errno Problem
errno is usually represented by a global variable.
Its value in the program can be changed suddenly by a signal handler which produces a new system function error.
1730 UNIX System Programming: Signals Maria Hybinette 89
UNIX: Signals Maria Hybinette 15