[ Team LiB ] |
5.8 POSIX Signal HandlingA signal is a notification to a process that an event has occurred. Signals are sometimes called software interrupts. Signals usually occur asynchronously. By this we mean that a process doesn't know ahead of time exactly when a signal will occur. Signals can be sent
The SIGCHLD signal that we described at the end of the previous section is one that is sent by the kernel whenever a process terminates, to the parent of the terminating process. Every signal has a disposition, which is also called the action associated with the signal. We set the disposition of a signal by calling the sigaction function (described shortly) and we have three choices for the disposition:
signal FunctionThe POSIX way to establish the disposition of a signal is to call the sigaction function. This gets complicated, however, as one argument to the function is a structure that we must allocate and fill in. An easier way to set the disposition of a signal is to call the signal function. The first argument is the signal name and the second argument is either a pointer to a function or one of the constants SIG_IGN or SIG_DFL. But, signal is an historical function that predates POSIX. Different implementations provide different signal semantics when it is called, providing backward compatibility, whereas POSIX explicitly spells out the semantics when sigaction is called. The solution is to define our own function named signal that just calls the POSIX sigaction function. This provides a simple interface with the desired POSIX semantics. We include this function in our own library, along with our err_XXX functions and our wrapper functions, for example, that we specify when building any of our programs in this text. This function is shown in Figure 5.6 (the corresponding wrapper function, Signal, is not shown here as it would be the same whether it called our function or a vendor-supplied signal function). Figure 5.6 signal function that calls the POSIX sigaction function.lib/signal.c 1 #include "unp.h" 2 Sigfunc * 3 signal (int signo, Sigfunc *func) 4 { 5 struct sigaction act, oact; 6 act.sa_handler = func; 7 sigemptyset (&act.sa_mask); 8 act.sa_flags = 0; 9 if (signo == SIGALRM) { 10 #ifdef SA_INTERRUPT 11 act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ 12 #endif 13 } else { 14 #ifdef SA_RESTART 15 act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */ 16 #endif 17 } 18 if (sigaction (signo, &act, &oact) < 0) 19 return (SIG_ERR); 20 return (oact.sa_handler); 21 } Simplify function prototype using typedef2–3 The normal function prototype for signal is complicated by the level of nested parentheses. void (*signal (int signo, void (*func) (int))) (int); To simplify this, we define the Sigfunc type in our unp.h header as typedef void Sigfunc(int); stating that signal handlers are functions with an integer argument and the function returns nothing (void). The function prototype then becomes Sigfunc *signal (int signo, Sigfunc *func); A pointer to a signal handling function is the second argument to the function, as well as the return value from the function. Set handler6 The sa_handler member of the sigaction structure is set to the func argument. Set signal mask for handler7 POSIX allows us to specify a set of signals that will be blocked when our signal handler is called. Any signal that is blocked cannot be delivered to a process. We set the sa_mask member to the empty set, which means that no additional signals will be blocked while our signal handler is running. POSIX guarantees that the signal being caught is always blocked while its handler is executing. Set SA_RESTART flag8–17 SA_RESTART is an optional flag. When the flag is set, a system call interrupted by this signal will be automatically restarted by the kernel. (We will talk more about interrupted system calls in the next section when we continue our example.) If the signal being caught is not SIGALRM, we specify the SA_RESTART flag, if defined. (The reason for making a special case for SIGALRM is that the purpose of generating this signal is normally to place a timeout on an I/O operation, as we will show in Section 14.2, in which case, we want the blocked system call to be interrupted by the signal.) Some older systems, notably SunOS 4.x, automatically restart an interrupted system call by default and then define the complement of this flag as SA_INTERRUPT. If this flag is defined, we set it if the signal being caught is SIGALRM. Call sigaction18–20 We call sigaction and then return the old action for the signal as the return value of the signal function. Throughout this text, we will use the signal function from Figure 5.6. POSIX Signal SemanticsWe summarize the following points about signal handling on a POSIX-compliant system:
|
[ Team LiB ] |