Presentation is loading. Please wait.

Presentation is loading. Please wait.

SignalsSignals. What is a Signal? A signal is a notification that some event has occurred. Usually a signal is sent to a process asynchronously and whatever.

Similar presentations


Presentation on theme: "SignalsSignals. What is a Signal? A signal is a notification that some event has occurred. Usually a signal is sent to a process asynchronously and whatever."— Presentation transcript:

1 SignalsSignals

2 What is a Signal? A signal is a notification that some event has occurred. Usually a signal is sent to a process asynchronously and whatever the process is doing is interrupted. Signals have been around since the early days of Unix, but early versions were not reliable, signals could get lost. Both 4.3BSD and SVR3 made revisions to their signal code to make signals reliable, but the changes were incompatible. Posix.1 standardized the reliable signal routines. Operating Systems

3 A signal is born when an event occurs that generates the signal. A signal ceases to exist when it is delivered, which means that some action specified for the signal has been taken. Between generation and delivery a signal is said to be pending. The Life Cycle of a Signal Operating Systems

4 Conditions that generate signals Most signals can be generated naturally Operating Systems for example, by a divide by zero error or a segmentation fault All signals can be generated synthetically by one of the following system calls: kill killpg pthread_kill raise sigqueue

5 Conditions that generate signals Five signals cannot be generated naturally Operating Systems SIGKILL SIGSTOP SIGTERM SIGUSR1 SIGUSR2 terminate immediately pause requests termination Signal names are defined in signal.h

6 Conditions that generate signals Terminal generated signals: occur when users type certain keys on the keyboard. For example, Ctrl-C normally generates the signal SIGINT. Operating Systems Hardware exceptions: conditions detected by hardware, like divide by zero, are sent to the kernel. The kernel generates the appropriate signal. The kill( ) function or the kill command: The kill function allows a process to send any signal to another process or process group, as long as it owns that process. Software Conditions: Some software conditions can cause signals to be generated. For example, SIGURG is generated when out of band data arrives over a network connection.

7 A signal is a classic example of an asynchronous event. They can occur at random times as far as the process is concerned. A process must tell the kernel what to do if and when a signal is received. A process can: * Catch the signal and ignore it - sigkill and sigstop cannot be ignored - ignored signals have no effect on the process * Catch the signal and do something with it * Let the default apply - usually terminates the process Operating Systems

8 When you get a signal from a hardware detected error condition, you cannot ignore the signal. Your program will likely not get safely past the condition. Such signals should be handled right away and the program terminated with a call to exit( ) More on this later... Operating Systems

9 TerminologyTerminology A signal is a software notification of an event. A signal is generated when the event that causes the signal occurs. A signal is delivered when the process catches the signal and takes some action on it. A signal that has not been delivered is pending. A signal handler is a function that the programmer writes to take some specific action when a given signal occurs. A program installs a signal handler by calling sigaction( ). A signal handler may choose to ignore a signal, in which case it is thrown away. A process can use a signal mask to block a set of signals. A blocked signal waits in a pending mode until the process unblocks the signal, at which time it is delivered to the process. A signal is a software notification of an event. A signal is generated when the event that causes the signal occurs. A signal is delivered when the process catches the signal and takes some action on it. A signal that has not been delivered is pending. A signal handler is a function that the programmer writes to take some specific action when a given signal occurs. A program installs a signal handler by calling sigaction( ). A signal handler may choose to ignore a signal, in which case it is thrown away. A process can use a signal mask to block a set of signals. A blocked signal waits in a pending mode until the process unblocks the signal, at which time it is delivered to the process. Operating Systems

10 Some Common Signal Names SymbolMeaning SIGABRTabnormal termination, initiated by abort SIGALRMtimeout signal, initiated by alarm SIGFPEarithmetic error, such as divide by zero SIGHUPhang up on controlling terminal SIGILLinvalid hardware instruction SIGINTinteractive attention signal (Ctrl-C) SIGKILLterminate ( cannot be caught or ignored ) SIGPIPEwrite on a pipe with no readers SIGQUITinteractive termination SIGSEGVinvalid memory reference SIGTERMtermination SIGUSR1user defined SIGUSR2user defined default action for all of these signals is to terminate the process. This set is required by Posix.1 Operating Systems

11 Job Control Signals SymbolMeaningDefault Action SIGCHLDchild process has stopped ignore SIGCONTcontinue if stopped continue process SIGSTOPstop signal (can’t be caught/ignored) stop process SIGSTPinteractive stop signal stop process SIGTTINbackground process trys to read stop process SIGTTOUbackground process trys to write stop process See all of the signals the os supports by typing kill -l See the key sequences that generate signals on your system by typing stty -a Operating Systems

12 What to do with a Signal Ignore the signal. Most signals can be ignored, but SIGKILL and SIGSTOP cannot. Catch the signal by telling the kernel to call a function provided by the programmer, when a particular signal is generated. Let the default action apply. The default for most signals is to terminate the process. Operating Systems

13 A really polished program will... Block all signals as soon as your program begins. Set all keyboard generated signals you don’t want to handle to be ignored. Catch SIGTERM and arrange to clean everything up and terminate when it arrives. This is the standard way that a sys admin will shut down processes. Catch all error generated signals and arrange to log them, print an appropriate error message, do any necessary clean-up, and terminate.

14 Generating Signals from the command line A user can only kill a process that he or she owns. Generate a signal with the kill command. From the shell kill –s signal pid This is one of the signal names less the “sig” prefix Example: kill –s USR1 3423

15 Generating Signals #include int kill (pid_t pid, int sig ); if pid is positive, kill sends the signal sig to the process pid (must own the process) if pid is negative, kill sends the signal to the process group |pid| if pid is zero, kill sends the signal to members of the callers process group returns 0 if successful from within a program

16 Killing a Parent Process Sounds grim, but ….. #include if (kill(getppid( ), SIGTERM) == -1) perror(“Error in kill command”);

17 Generating Signals (cont) The function alarm ( unsigned int num ) will generate a SIGALRM signal after num seconds have elapsed. The signal is sent to the calling process. A process needs permission to send a signal to another process. The superuser can send a signal to any process. For others the basic rule is that the real or effective user id of the sender has to be the same as the real or effective user id of the receiver, i.e. you can only send signals to processes that you own...

18 The Signal set A process can temporarily prevent a signal from being delivered by blocking it. Blocked signals do not affect the behavior of the process until they are delivered. The signal mask contains the set of all of the signals that are currently blocked. The following functions initialize and modify a signal set. int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int sig); int sigdelset(sigset_t *set, int sig); int sigismember(const sigset_t *set, int sig); use either of these functions to initialize a signal mask before using it. This function returns 1 if sig is a member of the set. Otherwise it returns 0. contains no signals contains all signals * note that blocking a signal is different from ignoring a signal. adds a signal to the signalset * deletes a signal from the signalset

19 Example Code #include sigset_t twosigs; … sigemptyset (&twosigs); sigaddset (&twosigs, SIGINT); sigaddset (&twosigs, SIGQUIT); this code initializes the signal set twosigs so that it contains just the two signals SIGINT and SIGQUIT. create a signal set make the signal set empty add sigint add sigquit

20 sigprocmask ( ) #include int sigprocmask (int how, const sigset_t *set, sigset_t *oldset); SIG_BLOCK:add this set to the signals currently blocked SIG_UNBLOCK:delete this set from the signals currently blocked SIG_SETMASK:set the signal mask to this set the set of signals to be used for the modification. If this value is NULL, then the function simply retrieves the current signal mask and stores it in oldset. No change is made to the current signal set. the function returns the current set of signals being blocked in oldset. This allows the program to restore the old signal set. If this value is NULL, then no value is returned. Installing a signal set

21 Example code #include sigset_t mymask; … sigemptyset(&mymask); sigaddset(&mymask, SIGINT); sigprocmask(SIG_BLOCK, &mymask, NULL); … sigprocmask(SIG_UNBLOCK, &mymask, NULL); … initialize the mask set and then set SIGINT add to the signal mask using the signal set we just created //if a ctrl-C occurs here, it will be blocked. clears the SIGINT from the signal mask this code adds SIGINT to the set of signals that the process currently has blocked. The old set is not saved.

22 See ex1 on X-Server. This code will block Ctrl-C then do some useless work. If a Ctrl-C comes in during this time, the process does not see the signal. When the process unblocks it, the signal is delivered.

23 Handling Signals Remember that blocking a signal only means that the signal will not be delivered until the signal is unblocked. It is a way of temporarily protecting your code from a signal. Once the signal is unblocked it will be delivered to the process. Then it must be handled in some way. In most cases, an unhandled signal will result in the process terminating.

24 Handling Signals What do you need to do inside of the signal handler to change the state of the application so it is known that the signal occurred? Where do you go after handling the signal. Choices are: return to where the application was when it was interrupted terminate the program do a global jump to another part of the program There are two issues to think about:

25 Note that when you in the signal handler, you are limited to making system calls that are considered to be asynch-signal-safe. These system calls are guaranteed to be re-entrant. POSIX defines the system calls that are asynch-signal-safe.

26

27 The Signal System Call This call was defined by ANSI C, but has been deprecated. It does not work well in multi-process environments. However, it is a simple call and illustrates signal handling effectively. #include void signal ( int signum, void (*act) (int) ) this is just a pointer to a function that takes an integer parameter and returns a void.

28 Example from Molay chapter 6 #include void f(int); int main ( ) { int i; signal ( SIGINT, f); for (i = 0; i < 10; i++) { printf(“hello\n”); sleep(1); } return 0; } void f ( int signum ) { printf(“\nOUCH”); } The signal handler

29 int main ( ) { int i; signal ( SIGINT, f); for (i = 0; i < 10; i++) { printf(“hello\n”); sleep(1); } return 0; } install the signal handler void f ( int signum ) { printf(“\nOUCH”); }

30 int main ( ) { int i; signal ( SIGINT, f); for (i = 0; i < 10; i++) { printf(“hello\n”); sleep(1); } return 0; } void f ( int signum ) { printf(“\nOUCH”); } hello INTERRUPT (SIGINT) ouch look at the code

31 Signal Handlers #include int sigaction (int sig, const struct sigaction *act, struct sigaction *old); struct sigaction { void (*sa_handler) ( ); // SIG_DFL, SIG_IGN, or pointer to function sigset_t sa_mask; // additional signals to be blocked while in handler int sa_flags; // flags and options } the function returns the current signal handling information in this structure. If NULL, nothing is returned. the signal handling information to be set for handling this signal. the signal to be caught SA_RESTART Restart any system calls interrupted by this signal once the signal handler has finished reset to defaultignore eliminates race conditions May be null

32 A signal handler is an ordinary function that takes a single integer parameter and returns a void. The operating system sets the parameter to the signal that was delivered to the process. Most signal handlers ignore this parameter, although it is possible to write a signal handler that handles several different signals.

33 ExampleExample The following code segment sets up a signal handler that catches ctrl-C. … char handlermsg[ ] = “User hit ctrl-c!\n”; void catch_ctrl_c (int signo) { write(STDERR_FILENO, handlermsg, strlen(handlermsg)); } … struct sigaction act; act.sa_handler = catch_ctrl_c; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGINT, &act, NULL) < 0) { // signal handler is installed … this is the actual signal handler. It prints a message. load the address of the handler don’t worry about any other signals no flags note that write is signal safe... printf is not!

34 ExampleExample The following code segment sets up a signal handler that ignores SIGINT if it is using the Default handler for this signal. #include struct sigaction act; … if (sigaction(SIGINT, NULL, &act) == -1) perror(“Could not get the old signal handler for SIGINT”); else if (act.sa_handler == SIG_DFL) { act.sa_handler = SIG_IGN; if (sigaction(SIGINT, &act, NULL) == -1) perror (“Could not ignore SIGINT”); } This just gets the current signal handler in act This sets the new signal handler

35 See handler.c example This code uses a shared variable as a flag. The program computes in an endless loop until the flag gets set. The flag gets set by the signal handler for SIGINT.

36 Waiting for signals One of the primary uses of signals is to keep programs from burning up cpu time while waiting for some event. Instead of running in a tight loop and checking to see if a signal has been received (polling), the program can put itself into a suspended state until the waited-for event occurs. #include int pause ( ); pause suspends the process until a signal that is not being ignored is delivered to the process. If a signal is caught by the process, the pause returns after the signal handler returns. the return value is not significant. pause( ) always returns -1 with errno set to EINTR

37 process A pause() process B signal handler signal

38 A problem with Pause … static volatile sig_atomic_t signal_received = 0; … while(signal_received == 0) pause( ); // go on to other stuff … to wait for a particular signal, we need to check which signal caused the pause to return. This information is not directly available, so we use an external static variable as a flag which the signal handler sets to 1. We can then check this flag when pause returns. the pause call is put into a loop so that we can check the value of the flag. If it is still zero, we must call pause again. what happens if a signal is delivered between the test and the pause? The program does not catch it!! the pause does not return until another signal is received. To solve this problem, we should test the flag while the signal is blocked! Volatile: This value may be changed by something outside of this scope. It should not be optimized by the compiler. sig_atomic_t is a data type that is guaranteed can be read or written without being interruped.

39 But … does this work? … sigset_t sigset; int signum; sigemptyset(&sigset); sigaddset(&sigset, signum); sigprocmask(SIG_BLOCK, &sigset, NULL); while(signal_received == 0) pause(); … // signum is the signal we want to catch No! Now the signal is blocked when the pause statement is executed, so the program never receives the signal.

40 sigsuspendsigsuspend The delivery of signals with pause was a major problem in Unix. It was fixed by adding the sigsuspend operation. int sigsuspend(const sigset_t *sigmask); return value is always -1 sigsuspend sets the signal mask to the one pointed to by sigmask and pauses the process in a single atomic operation. When sigsuspend returns, the signal mask is reset to the value it had before sigsuspend was called.

41 Consider the following code sigfillset(&mask); // set mask to block all signals sigdelset(&mask, signum); // remove signum from the set sigsuspend(&mask); // wait for signum Now the program pauses. All signals except signum have been blocked. What’s wrong?

42 Consider the following code sigfillset(&mask); // set mask to block all signals sigdelset(&mask, signum); // remove signum from the set sigsuspend(&mask); // wait for signum what happens if the signal is delivered just before this code block is entered? The signal is handled, and now sigsuspend puts the program in a wait condition. If another signal is not delivered, the program waits forever.

43 Correct code to wait for a signal (signum) static volatile sig_atomic_t sigreceived = 0; sigset_t maskall, maskmost, maskold; int signum = SIGNUM; sigfillset(&maskall); sigfillset(&maskmost); sigdelset(&maskmost, SIGNUM); sigprocmask(SIG_SETMASK, &maskall, &maskold); if (sigreceived == 0) sigsuspend(&maskmost); sigprocmask(SIGSETMASK, &maskold, NULL); declare static variable to test. It gets set in the signal hander. the signal we want to wait for. block all signals blocks all signals but SIGNUM now, all signals are blocked. test the flag. this is the critical section unblock SIGNUM and pause as an atomic action. after returning from the signal handler, restore the old signal mask.

44 Correct code to wait for a signal... allowing other signals while waiting for SIGUSR1 static volatile sig_atomic_t sigreceived = 0; sigset_t masknew, maskold; int signum = SIGUSR1; sigprocmask(SIG_SETMASK, NULL, &masknew); sigaddset(&masknew, signum); sigprocmask(SIG_SETMASK, &masknew, &maskold); sigdelset(&masknew, SIGUSR1); while (sigreceived == 0) sigsuspend(&masknew); sigprocmask(SIGSETMASK, &maskold, NULL); The flag The signal I want to wait for get current add my signal to the current set set mask now SIGUSR1 is blocked remove SIGUSR1 from the set if flag is ok, wait for SIGUSR1 … it is unblocked by the sigsuspend call restore

45 System Calls and Signals Some system calls, like terminal I/O can block the process for a very long time. The capability is needed to be able to interrupt these system calls so that signals can be delivered during long waits for I/O. In POSIX.1, slow system calls that are interrupted return with -1, and errno set to EINTR. The program must handle this error explicitly and restart the system call if desired.

46 struct sigaction { void (*sa_handler) ( ); sigset_t sa_mask; int sa_flags; Remember the sigaction struct …. SA_RESTART Restart any system calls interrupted by this signal once the signal handler has finished

47 Slow system Calls Slow System Calls are those that can block forever. These include * reads from files that block forever if no data is present. This includes pipes, network connections, and terminals. * Writes to the above if the data cannot be accepted. * opens of files that block until some condition occurs, for example waiting to open a terminal device until modem answers the phone. * pause * some interprocess communication functions

48 The following code segment restarts the read system call if interrupted by a signal. #include int fd, retval, size; char *buf;... while (retval = read(fd, buf, size), retval == -1 && errno == EINTR); if (retval == -1) { // handle errors here … } note the use of the comma operator: the left-hand expression is evaluated first then the second expression is evaluated and the result used as the condition for the while loop. that is, the read occurs. Then the return value is tested. If it failed because of an interrupt, the read is re-started.

49 siglongjump and sigsetjump Used to unwind the call stack sigsetjump is like a statement label siglongjump is like a goto … it branches to the label set by sigsetjump Used to unwind the call stack sigsetjump is like a statement label siglongjump is like a goto … it branches to the label set by sigsetjump see non-local exits in the GNU C library manual It is not recommended that you use these

50 TimersTimers

51 TerminologyTerminology A timer keeps track of the passage of time Calendar time is a point in the time continuum, for example, October 5, 2001 at 12:30pm. The Unix time continuum (epoch) begins on January 1, 1970 An interval is a contiguous part of the time continuum, between two calendar times. Interval timers generate an interrupt after a specific time interval. An elapsed time is the length of an interval, for example, 30 minutes. An amount of time is a sum of elapsed times. CPU time is like calendar time, except that it is based on the subset of the time continuum when a particular process is actively using a CPU. CPU time is, therefore, relative to a process

52 Interval Timers Each process has three independent interval timers available: * A real-time timer that counts elapsed time in real time. This timer sends a SIGALRM signal to the process when it expires. * A virtual timer that counts processor time used by the process. It only runs when the process is running. This timer sends a SIGVTALRM signal to the process when it expires. * A profiling timer that counts both time used by the process and processor time spent in system calls on behalf of the process. This timer sends a SIGPROF signal to the process when it expires. The interval timer mechanism does not have the fine granularity necessary for profiling native code

53 setitimersetitimer #include int setitimer (int which, struct itimerval *new, struct itimerval *old) ; ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF struct timeval it_value; struct timeval it_interval; This is the period between successive timer interrupts. If zero, the alarm will only be sent once. This is the period between now and the first timer interrupt. If zero, the alarm is disabled.

54 Comprehensive Example #include // define the signal handler to write an asterisk char astbuf[ ] = “*”; void astWriter(int s) { write(2, astbuf, sizeof(char)); } note that we use the kernel write call because printf is not asynch-signal-safe.

55 void init_time_interrupt(void) { struct sigaction newact; newact.sa_handler = astWriter; newact.sa.flags = 0; sigemptyset(&newact.sa_mask); sigaction(SIGPROF, &newact, NULL); } Signal handler is installed … SIGPROF is the signal generated by the profiling timer.

56 void setup_interval_timer(void) { struct itimerval value; value.it_interval.tv_sec = 2; value.it_interval.tv_usec = 0; value.it_value = value.it_interval; setitimer(ITIMER_PROF, &value, NULL); } value it_interval it_value tv_sec tv_usec tv_sec tv_usec 2 secs before 1 st interrupt 2 secs between interrupts

57 int main (int argc, char *argv[ ]) { init_time_interrupt(); setup_interval_timer(); // some useless code for ( ; ; ) { } exit(0); }


Download ppt "SignalsSignals. What is a Signal? A signal is a notification that some event has occurred. Usually a signal is sent to a process asynchronously and whatever."

Similar presentations


Ads by Google