Ron Heiby (The Moderator) <unix-request@cbosgd.UUCP> (03/26/85)
Unix Technical Digest Tue, 26 Mar 85 Volume 1 : Issue 34 Today's Topics: [Signal Miscellany] ---------------------------------------------------------------------- Date: 15 Mar 85 13:53:36 GMT From: jack@boring.UUCP Subject: When does ( alarm(1) == alarm(INFINITY) ) ? In article <179@encore.UUCP> ptw@encore.UUCP (P. Tucker Withington) writes: >As I read the manual (I didn't read the code) pause will only return when a >signal is "caught". If the semantics were that it would also return >(immediately) if there were no signal handlers active (since they revert when >caught), the race condition would also disappear. This sounds nice at first, but gives rise to some even weirder situations. For instance, I have a program that uses this feature, and then, later on, decide to put an interrupt handler in it, in case the user wishes to abort the program. Guess what? Suddenly my program stops working!! I wouldn't want to look for *that* bug........ An other approach would be to let pause() return if there is no signal handler for SIGALRM, but I'm sure that there are people who use pause() for things totally unrelated to alarm() calls. By the way, I *do* agree that it might not be a bad idea to have pause() return when there are no signal handlers installed, but I think it is not a complete solution to this race condition. -- Jack Jansen, {decvax|philabs|seismo}!mcvax!jack It's wrong to wish on space hardware. ------------------------------ Date: 16 Mar 85 01:58:36 GMT From: mike@whuxl.UUCP (BALDWIN) Subject: sleep problems System V doesn't have the sleep(1) == sleep(INFIN) problem because it uses setjmp/longjmp to catch the alarm: sleep(amt) { ... signal(SIGALRM, catch); if (setjmp(buf) == 0) { alarm(amt); pause(); } ... } catch() { longjmp(buf, 1); } So if the alarm comes in before the pause, it will skip over the pause. Unfortunately, the longjmp causes a particularly bad thing to happen: if another signal is caught while the sleep is pausing, and the alarm goes off before the signal routine has returned, that signal routine will be cut off in the middle! Michael Baldwin AT&T Bell Labs harpo!whuxl!mike ------------------------------ Date: 19 Mar 85 19:21:11 GMT From: ksbszabo@wateng.UUCP (Kevin Szabo) Subject: Printing in signal handlers (more on ( alarm(1) == alarm(INFINITY))? In article <312@calgary.UUCP> radford@calgary.UUCP (Radford Neal) writes: >I think the moral of all this is: > - Don't use signal handlers if you can avoid it, especially for anything > other than printing an error message and exiting. > > - If you have to use signal handlers, you better think REALLY carefully > about what could happen, or you may write a program which fails > inexplicably once every few weeks. Your second moral should be applied BEFORE you apply the first moral. For instance, you can really confuse STDIO if you were to do the following in a signal handler: BadSignal( n ) { fprintf(stderr,"Huh? Caught unexpected signal %s!\n", list_of_sigs(n) ); } Stdio could have been in the middle of a malloc for flsbuf() or something. You could have gotten a core dump if you were unlucky enough... The problem is that practically none of STDIO is re-entrant. The only thing you can trust in a signal handler is a direct call to the kernel. Thus any printing in a signal handler should probably look like: (I might have the arguments in the wrong order to write() ) BadSignal( n ) { extern caught_signal; char *msg; msg = "Huh? ..."; while( *msg ) { if ( write( fileno(stderr), msg, 1 ) != 1 ) abort(); msg++; } ....spit out the rest of the message.... /* tell the rest of the program that a signal occurred. We'll * handle it outside of the signal handler because it is safer. * Multiple signals will get lost, but they usually do under UNIX * anyway */ caught_signal = n; } Note: The abort() is to get a core dump in case you have done something funny to stderr. You better not be catching SIGILL (or whatever abort causes) otherwise on some systems (4.2 BSD) you will just get an infinite loop. So maybe the first moral of the story is: don't do any more than set an external in a signal handler, otherwise be prepared to look long and hard at what you are doing. Kevin -- Kevin Szabo watmath!wateng!ksbszabo (U of Waterloo VLSI Group, Waterloo Ont.) ------------------------------ Date: 21 Mar 85 06:23:34 GMT From: geoff@utcs.UUCP (Geoff Collyer) Subject: Printing in signal handlers (more on ( alarm(1) == alarm(INFINITY))? In article <2175@wateng.UUCP> ksbszabo@wateng.UUCP (Kevin Szabo) writes: >The problem is that practically none of STDIO is re-entrant. The only >thing you can trust in a signal handler is a direct call to the kernel. I think the real problem is that UNIX allows one to catch signals at all. Given that we don't have cheap processes a la Thoth, catching signals is a necessary evil but signal handlers should be kept simple and in particular should avoid using longjmp (if you have ever read and understood the source, you won't want to use longjmp). At most, setting a global flag often suffices; this also may allow one to omit calls to signal to enable and disable signal catching around critical sections by simply noting the state of the flag at appropriate places. I can't speak for all UNIXes, but the system call interface routines in the PDP-11 v7 C library often aren't re-entrant either: they copy their arguments into static storage, then issue the system call pointing at the static storage. If you interrupt such a routine (say signal(2)) while it is copying its arguments and in the signal catcher you invoke the same system call, then return from the signal catcher without calling longjmp, the first instance of signal will continue to execute, though some of its static storage was trashed by the second call in the signal handler. So if you are going to make those direct calls to the kernel in your signal handler, you'd better do it from assembler or verify that your C library system call interfaces are re-entrant. This is something that I believe Whitesmith's got right: last time I looked they had a standard routine for issuing system calls that left the arguments on the stack and made the system call point at the stacked arguments. ------------------------------ Date: 23 Mar 85 01:40:09 GMT From: wls@astrovax.UUCP (William L. Sebok) Subject: don't do long jumps in signal handlers > I think the real problem is that UNIX allows one to catch signals at all. > Given that we don't have cheap processes a la Thoth, catching signals is a > necessary evil but signal handlers should be kept simple and in particular > should avoid using longjmp (if you have ever read and understood the source, > you won't want to use longjmp). Unfortunately if you wan't to interrupt a 4.2 read() from a terminal you have to do longjmp (or worse). In my opinion, if they didn't want signals to abort terminal reads they should have provided an explicit i/o abort function that could be called from the signal handler. -- Bill Sebok Princeton University, Astrophysics {allegra,akgua,burl,cbosgd,decvax,ihnp4,noao,princeton,vax135}!astrovax!wls ------------------------------ Date: 22 Mar 85 22:23:46 GMT From: gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) Subject: Printing in signal handlers (more on ( alarm(1) == alarm(INFINITY))? My recommendation is to do little more than set a flag in the signal catcher and return. Test this flag at appropriate places in the main program control loop. This is much safer than trying to do anything useful from inside a signal catcher. ------------------------------ End of Unix Technical Digest ****************************** -- Ronald W. Heiby / ihnp4!{wnuxa!heiby|wnuxb!netnews} AT&T Information Systems, Inc. Lisle, IL (CU-D21)