Overview Last Week: � How to program UNIX processes (Chapters 7-9) � fork() and exec() Unix System Programming This Week: Signals � UNIX inter-process communication mechanism: signals, pipes and FIFOs. � How to program with UNIX signals (Chapter 10) � Non-local jumps (Chapter 7) � Focus on the sigaction() function 1 2 Maria Hybinette, UGA Maria Hybinette, UGA Outline What is a Signal? � What is a UNIX signal? � A signal is an asynchronous event which is delivered to a process (instantiated by a small � Signal types message) � Generating signals � Asynchronous means that the event can occur � Responding to a signal at any time � Common uses of a signal » may be unrelated to the execution of the process � Implementing a read() time-out » e.g. user types Ctrl-C , or the modem hangs � Non-local jumps setjmp()/longjmp() � Sent from kernel (e.g. detects divide by zero ( SIGFPE ) or could be at the request of another � POSIX signals process to send to another) � Interrupted system calls � Only information that a signal carries is its � System calls inside handlers unique ID and that it arrived 3 4 Maria Hybinette, UGA Maria Hybinette, UGA Signal Types (31 in POSIX) Signal Sources terminal memory ID Name Description Default Action driver management shell command Interrupt from keyboard ( ^C ) 2 SIGINT terminate SIGINT SIGHUP 3 SIGQUIT Quit from keyboard ( ^\ ) terminate & core SIGQUIT 9 SIGKILL kill -9 terminate SIGKILL kernel SIGPIPE 11 SIGSEGV Invalid memory reference terminate & core 14 SIGALRM alarm() clock ‘rings’ terminate SIGWINCH SIGALRM 17 SIGCHLD Child stopped or terminated ignore window 16 SIGUSR1 user-defined signal type terminate manager a process SIGUSR1 � /usr/include/sys/iso/signal_iso.h on atlas other user processes 5 6 Maria Hybinette, UGA Maria Hybinette, UGA
Generating a Signal kill() � Use the UNIX command: {saffron} ./fork_example #include <signal.h> {saffron} kill -KILL 6676 Terminating Parent, PID = 6675 int kill( pid_t pid, int signo ); Running Child, PID = 6676 » sends a SIGKILL signal to {saffron} ps PID TTY TIME CMD processor ID ( pid) 6676 � Send a signal to a process (or group of processes). 6585 ttyp9 00:00:00 tcsh » check pid via (and also to 6676 ttyp9 00:00:06 fork_example � Return 0 if ok, -1 on error. {saffron} kill –s 9 6676 make sure it died) {saffron} ps PID TTY TIME CMD {saffron} ps -l Meaning � pid 6585 ttyp9 00:00:00 tcsh 6678 ttyp9 00:00:00 ps > 0 send signal to process pid � kill is not a good name; == 0 send signal to all processes send_signal might be whose process group ID equals the sender’s pgid . better. e.g. parent kills all children 7 8 Maria Hybinette, UGA Maria Hybinette, UGA Responding to a Signal signal() #include <signal.h> After receiving a signal a process can: � 1. Ignore/Discard/Block out the signal (not possible with void (*signal( int signo, void (*func)(int) ))(int); SIGKILL or SIGSTOP ) 2. Catch the signal; execute a signal handler function, and typedef void Sigfunc( int ); /* Plauger 1992 definition */ then possibly resume execution or terminate Sigfunc *signal( int signo, Sigfunc *handler ); 3. Carry out the default action for that signal � Signal returns a pointer to a function that returns an int (i.e. it The choice is called the process’ signal disposition returns a pointer to Sigfunc ) � � Specify a signal handler function to deal with a signal type. � Returns previous signal disposition if OK, SIG_ERR on error. 9 10 Maria Hybinette, UGA Maria Hybinette, UGA Sketch on how to program with 5. signal returns a pointer 4. The handler 2. The signal to be to a function. function signals Actual Prototype caught or ignored The return type is the same Receives a single is given as argument as the function that is passed integer signo in, argument and i.e., a function that takes an returns void � The actual prototype, listed in the “man” page is a bit int main() int and returns a void { perplexing but is an expansion of the Sigfunc type: signal( SIGINT, foo ); : void (*signal( int signo, void (*handler)(int)))(int); /* do usual things until SIGINT */ return 0; � signal returns a pointer to the previous signal handler } void foo( int signo ) 3. The function to { 6. The returned #include <signal.h> be called when the : /* deal with SIGINT signal */ 1. signal takes two function typedef void Sigfunc(int); /* Plauger 1992 */ specified signal is arguments: takes a integer Sigfunc *signal( int signo, Sigfunc *handler ); received is given as signo and handler return; /* return to program */ parameter. a pointer to the } function handler 11 12 Maria Hybinette, UGA Maria Hybinette, UGA
External Signal Example: signal_example.c {saffron:ingrid:54} signal_example #include <stdio.h> int main( void ) 0: Received SIGUSR1 #include <signal.h> { 1: Received SIGUSR1 #include <unistd.h> int i = 0; 2: Received SIGUSR2 [1] + Stopped (signal) if( signal( SIGUSR1, sig_usr ) == SIG_ERR ) signal_example static void sig_usr( int signo ) perror( "Cannot catch SIGUSR1\n" ); {saffron:ingrid:26} fg signal_example { if( signal( SIGUSR2, sig_usr ) == SIG_ERR ) 3: Received SIGUSR1 if( signo == SIGUSR1 ) perror( "Cannot catch SIGUSR2\n" ); Quit printf( "Received SIGUSR1\n" ); else if( signo == SIGUSR2 ) while( 1 ) printf( "Received SIGUSR2\n" ); { {saffron:ingrid:55} kill -l= else printf( "%d: ", i ); {saffron:ingrid:56} ps -l { pause(); /* until signal handler fprintf( stderr, "ERROR: received signal %d\n", signo ); has processed signal */ {saffron:ingrid:23} kill -USR1 1255 exit(1); i++; {saffron:ingrid:24} kill -USR1 1255 } } {saffron:ingrid:25} kill -USR2 1255 return; return 0; {saffron:ingrid:26} kill -STOP 1255 {saffron:ingrid:27} kill -CONT 1255 } } {saffron:ingrid:28} kill -USR1 1255 {saffron:ingrid:29} kill QUIT 1255 13 14 Maria Hybinette, UGA Maria Hybinette, UGA Internal Signal Example: signal_example2.c Special Sigfunc * Values #include <stdio.h> int main( void ) #include <signal.h> { � Value Meaning #include <unistd.h> int i = 0; if( signal( SIGALRM, handler ) == SIG_ERR ) int beeps = 0; perror( "Cannot catch SIGALRM\n" ); alarm(1); Ignore / discard the signal. SIG_IGN static void handler( int signo ) while( 1 ) { { Use default action to handle signal. SIG_DFL printf( "BEEP\n" ); printf( "%d: ", i ); fflush(stdout); pause(); i++; } Returned by signal() as an error. SIG_ERR if( ++beeps < 5 ) return 0; alarm(1); } else { {cinnamon} signal_example2 printf("BOOM!\n"); 0: BEEP exit(0); 1: BEEP } 2: BEEP return; 3: BEEP 4: BEEP } BOOM! 15 16 Maria Hybinette, UGA Maria Hybinette, UGA Multiple Signals pause() � If many signals of the same type are waiting to #include <unistd.h> be handled (e.g. two SIGINT s), then most UNIXs int pause(void); will only deliver one of them. » the others are thrown away - i.e. pending signals are � Suspend the calling process until a signal is not queued caught. » for each signal type, just have a single bit indicating � Returns -1 with errno assigned EINTR . whether or not the signal has occured (Linux assigns it ERESTARTNOHAND ). � If many signals of different types are waiting to be handled (e.g. a SIGINT , SIGSEGV , SIGUSR1 ), � pause() only returns after a signal handler they are not delivered in any fixed order. has returned. 17 18 Maria Hybinette, UGA Maria Hybinette, UGA
The Reset Problem Reset Problem Example � In Linux (and many other UNIXs), the signal int main() { disposition in a process is reset to its default signal(SIGINT, foo); action immediately after the signal has been : delivered. /* do usual things until SIGINT */ } void foo( int signo ) { � Must call signal() again to reinstall the signal(SIGINT, foo); /* reinstall */ signal handler function. : return; } 19 20 Maria Hybinette, UGA Maria Hybinette, UGA To keep catching the signal with this Reset Problem Re-installation may be too slow! function, must call the signal system call again. : � There is a (very) small time period in foo() when void ouch( int sig ) { a new SIGINT signal will cause the default action printf( "OUCH! - I got signal %d\n", sig ); to be carried out -- process termination. (void) signal( SIGINT, ouch ); Problem: from the time } � With signal() there is no answer to this that the interrupt function int main() starts to just before the problem. { signal handler is re- (void) signal( SIGINT, ouch ); established » POSIX signal functions solve it (and some other later while(1) the signal will not be UNIXs) { handled. printf( "Hello World!\n"); sleep(1); } If another SIGINT signal is } received during this time, default behavior will be done, i.e., program will terminate. 21 22 Maria Hybinette, UGA Maria Hybinette, UGA Common Uses of Signals Ignore a Signal : � Ignore a signal int main() { � Clean up and terminate signal( SIGINT, SIG_IGN ); signal( SIGQUIT, SIG_IGN ); � Dynamic reconfiguration : /* do work without interruptions */ � Report status } � Turn debugging on/off � Cannot ignore/handle SIGKILL or SIGSTOP � Restore a previous handler � Should check for SIG_ERR 23 24 Maria Hybinette, UGA Maria Hybinette, UGA
Recommend
More recommend