SC22/WG14 N789 Changes to signal handling Clive D.W. Feather clive@demon.net 1997-10-22 Abstract ======== The section of the Standard on signals greatly restricts the actions that a signal handler can take. In particular, there are places where the Standard appears to require the program to enter an infinite loop. N773 item 13 attempted to clean up this situation; after discussion at Menlo Park, this paper is a further pass on this matter. Discussion ========== There are effectively three ways that a signal handler can be invoked: (1) through raise (); (2) from some internal asynchronous event, such as a floating-point error; (3) from some external asynchronous event, such as a termination request. For the purposes of this paper, it is assumed that the second and third cases are distinguished by signal number, with SIGFPE, SIGILL, and SIGSEGV falling into (2) and all others into (3). There are four ways a signal handler can complete: (1) returning (2) calling exit() (3) calling abort() (4) calling longjmp() All of these have potential problems; for example, an asynchrous signal might interrupt a call to malloc(), and that might prevent the proper closing of files as part of exit(). The consensus view was that: * signals invoked through raise() should be allowed to do any of these; * external asynchronous signal handlers should be allowed to return. * all asynchronous signal handlers should be allowed to terminate the program, but should not cause the malloc() problems. The best way to do this is to introduce a new _exit() function that *only* terminates the program. In addition, the proposal cleans up some wording issues. Proposal ======== [References are to draft 11 pre 3.] In subclause 7.10.2.1 (The longjmp function), delete paragraph 4. As it bypasses ... undefined. Change the last sentence of subclause 7.11.1.1 (The signal function) paragraph 2 from: Such a function is called a signal handler. to: An invocation of such a function because of a signal, or (recursively) of any further functions called by that invocation (other than functions in the standard library), is called a /signal handler/. Change subclause 7.11.1.1 paragraphs 3 and 4 from: When a signal occurs, ... the value of errno is indeterminate.[189] to: When a signal occurs and /func/ points to a function, it is implementation-defined whether the equivalent of /signal (sig, SIG_DFL)/ is executed or the implementation prevents some implementation-defined set of signals (at least including /sig/) from occuring until the current signal handling has completed; in the case of SIGILL, the implementation may alternatively define that no action is taken. Then the equivalent of /(*func)(sig);/ is executed. If and when the function returns, if the value of /sig/ is /SIGFPE/, /SIGILL/, /SIGSEGV/, or any other implementation-defined value corresponding to a computational exception, the behavior is undefined; otherwise the program will resume execution at the point it was interrupted. If the signal occurs as the result of calling the /abort/ or /raise/ function, the signal handler shall not call the /raise/ function. If the signal occurs other than as the result of calling the /abort/ or /raise/ function, the behavior is undefined if the signal handler refers to any object with static storage duration other than by assigning a value to an object declared as /volatile sig_atomic_t/, or the signal handler calls any function in the standard library other than the /abort/ function, the /_exit/ function, or the /signal/ function with the first argument equal to the signal number corresponding to the signal that caused the invocation of the handler. Furthermore, if such a call to the /signal/ function results in a /SIG_ERR/ return, the value of /errno/ is indeterminate. [189] In subclause 7.11.1.1 paragraph 7, change: ... for the most recent call to /signal/ for ... to: ... for the most recent successful call to /signal/ for ... In subclause 7.11.2.1 (The raise function), change paragraph 2 from: The /raise/ function sends the signal /sig/ to the executing program. to: The /raise/ function carries out the actions described in subclause 7.11.1.1 for the signal /sig/. If a signal handler is called, the /raise/ function shall not return until after the signal handler does. Add a new subclause 7.14.4.4 within 7.14.4 (Communication with the environment), renumbering subsequent subclauses. 7.14.4.4 The _exit function Synopsis #include void _exit (int status); Description The /_exit/ function causes normal program termination to occur immediately. Control is returned to the host environment. The status returned is determined in the same manner as for the /exit/ function. It is implementation-defined whether open output streams are flushed or open streams closed or temporary files removed.