Unix System Programming Overview Outline What Is a Signal? Signal
Total Page:16
File Type:pdf, Size:1020Kb
Overview Last Week: ● How to program UNIX processes (Chapters 7-9) ● fork() and exec() Unix System Programming This Week, and next week: ● UNIX inter-process communication mechanisms: signals, Signals » (next week) pipes and FIFOs. ● How to program with UNIX signals (Chapter 10) » http://en.wikipedia.org/wiki/Unix_signal ● Non-local jumps (Chapter 7) ● Focus on the sigaction() function Maria Hybinette, UGA 1 Maria Hybinette, UGA 2 Outline What is a Signal? ● A signal is an asynchronous event which is ● What is a UNIX signal? delivered to a process (instantiated by a small message) ● Signal types ● Asynchronous means that the event can occur ● Generating signals at any time (e.g., posting at a bulletin board ) ● Responding to a signal » may be unrelated to the execution of the process ● Common uses of a signal – e.g., user types Ctrl-C, or the modem hangs (SIGINT) ● Implementing a read() time-out – e.g,, user types Ctrl-Z (SIGTSTP) ● Sent from kernel (e.g. detects divide by zero ● Non-local jumps setjmp()/longjmp() (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 Maria Hybinette, UGA 3 Maria Hybinette, UGA 4 Signal Types (31 in POSIX) Signal Sources terminal memory ID Name Description Default Action driver management shell command 2 SIGINT Interrupt from keyboard (^C) terminate Ctr-C SIGINT SIGHUP 3 SIGQUIT Quit from keyboard (^\) terminate & core SIGSEGV 9 SIGKILL kill -9 terminate SIGKILL,SIGCONT kernelsig 11 SIGSEGV Invalid memory reference terminate & core SIGPIPE 14 SIGALRM alarm() clock rings terminate SIGWINCH SIGALRM 17 SIGCHLD Child stopped or terminated! ignore Terminal, window 16 SIGUSR1 user-defined signal type terminate manager a process SIGUSR1 ● /usr/include/sys/iso/signal_iso.h on atlas (solaris) ● /usr/src/kernels/2.6.32-431.29.*/include/linux/signal.h SIGFPE other user ● processes /usrMaria Hybinette,/include/ UGA signal.h (user space)! 5 RunningMaria Hybinette, a.out UGA process (division by 0, floating point exception) 6 Generating a Signal kill() ● Use the UNIX command: {saffron} ./fork_example {saffron} kill -KILL 6676 Terminating Parent, PID = 6675 #include <signal.h> » sends a SIGKILL signal to Running Child, PID = 6676 int kill( pid_t pid, int signo ); {saffron} ps processor ID (pid) 6676 PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh ● Send a signal to a process (or group of processes). » check pid via (and also to 6676 ttyp9 00:00:06 fork_example ● make sure it died) {saffron} kill –s 9 6676 Return 0 if ok, -1 on error. {saffron} ps {saffron} ps -l PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh ● Meaning pid 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 better. equals the senders pgid. e.g. parent kills all children ● How do we do this in a program? Maria Hybinette, UGA 7 Maria Hybinette, UGA 8 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 processsignal returns a pointer to Sigfunc) disposition ● Specify a signal handler function to deal with a signal type. ● How is a process disposition set? ● Returns previous signal disposition if OK, SIG_ERR on error. Maria Hybinette, UGA 9 Maria Hybinette, UGA 10 5. signal returns a pointer 4. The handler Sketch on how to program with to a function. 2. The signal to be function The return type is the sameActual caught Prototype or ignored Receives a single signals as the function that is passed is given as argument integer in, signo 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 } 3. The function to be void foo( int signo ) { #include <signal.h> called when the 6. The returned : /* deal with SIGINT signal */ typedef1. signal void takes Sigfunc(int); two specified /* Plauger signal is1992 */ function Sigfuncarguments: *signal( int signo,received Sigfunc is given *handler as ); takes a integer signo and handler parameter. return; /* return to program */ a pointer to the } function handler Maria Hybinette, UGA 11 Maria Hybinette, UGA 12 External Signal Example: signal_example.c #include <stdio.h> int main( void ) {saffron:ingrid:54} signal_example 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 { if( signal( SIGUSR2, sig_usr ) == SIG_ERR ) signal_example 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" ); { else printf( "%d: ", i ); {saffron:ingrid:55} kill -l= {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 } ps –u } {saffron:ingrid:28} kill -USR1 1255 {saffron:ingrid:29} kill QUIT 1255 kill -SIGUSR2 21084 Maria Hybinette, UGA 13 Maria Hybinette, UGA 14 Internal Signal Example: signal_example2.c Special Sigfunc * Values #include <stdio.h> int main( void ) #include <signal.h> { #include <unistd.h> int i = 0; ● Value Meaning if( signal( SIGALRM, handler ) == SIG_ERR ) int beeps = 0; perror( "Cannot catch SIGALRM\n" ); alarm(1); SIG_IGN Ignore / discard the signal. static void handler( int signo ) while( 1 ) { { printf( "BEEP\n" ); printf( "%d: ", i ); SIG_DFL Use default action to handle signal. fflush(stdout); pause(); i++; } SIG_ERR Returned by signal() as an error. 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! Maria Hybinette, UGA 15 Maria Hybinette, UGA 16 Multiple Signals pause() ● If many signals of the same type are waiting to #include <unistd.h> be handled (e.g. two SIGINTs), then most UNIXs int pause(void); will only deliver one of them. » the others are thrown away - i.e. pending signals are not queued ● Suspend the calling process until a signal is caught. » for each signal type, just have a single bit indicating whether or not the signal has occured ● Returns -1 with errno assigned EINTR. ● If many signals of different types are waiting to (Linux assigns it ERESTARTNOHAND). 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. Maria Hybinette, UGA 17 Maria Hybinette, UGA 18 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; } Maria Hybinette, UGA 19 Maria Hybinette, UGA 20 To keep catching the signal with this function, must call Reset Problem the signal system Re-installation may be too slow! call again. : void ouch( int sig ) ● There is a (very) small time period in foo() when { 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 int main() that the interrupt function ● With there is no answer to this starts to just before the signal() { signal handler is re- problem. (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. Maria Hybinette, UGA 21 Maria Hybinette, UGA 22 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 Maria Hybinette, UGA 23 Maria Hybinette, UGA 24 Clean up and Terminate Checking the Disposition ● If a program is run in the new disposition : old disposition /* global variables */ background then