jeff@voder.UUCP (07/10/84)
There is a bug in the 4.2 implementation of alarm(3). In the following oldalarm = alarm(newalarm); oldalarm gets the current value of the interval timer *rounded down* to the nearest second. So ... for (...) { oldalarm = alarm((unsigned) 0); ... alarm(oldalarm); } causes the interval timer to be *repeatedly* rounded down. End result: the alarm goes off early. And, of course, if the interval timer just *happened* to be at some value *less* than a second the alarm will be turned off completely. Fortunately, there is an easy workaround; change the previous code to read: for (...) { oldmask = sigblock(1<<SIGALRM); ... sigblock(oldmask); } The fix to alarm() is left as an exercise to the interested reader. Jeff Gilliam No pain, no gain ... *sigh*
gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (07/11/84)
The following fixes the round-down behavior of 4.2BSD alarm(3): /* alarm -- system call emulation for 4.2BSD last edit: 14-Dec-1983 D A Gwyn */ extern int _setitimer(); typedef struct { unsigned long tv_sec; /* seconds */ long tv_usec; /* microseconds */ } timeval; typedef struct { timeval it_interval; /* timer interval */ timeval it_value; /* current value */ } itimerval; unsigned alarm( sec ) unsigned sec; /* timeout in seconds */ { itimerval newit; /* new interval data */ itimerval oldit; /* old interval data */ /* set alarm clock timeout interval (0 disables) */ newit.it_value.tv_sec = (unsigned long)sec; newit.it_value.tv_usec = 0L; /* avoid retriggering once timer expires */ newit.it_interval.tv_sec = 0L; newit.it_interval.tv_usec = 0L; if ( _setitimer( 0, &newit, &oldit ) < 0 ) /* real time */ return -1; /* SIGALRM now pending */ return (unsigned)oldit.it_value.tv_sec + (oldit.it_value.tv_usec > 500L ? 1 : 0); }
muller@sdccsu3.UUCP (Keith Muller) (07/11/84)
> Fortunately, there is an easy workaround; change the previous code > to read: > > for (...) { > oldmask = sigblock(1<<SIGALRM); > ... > sigblock(oldmask); > } I should have looked closer as there is two bugs: (SIGALRM and the second sigblock should be a sigsetmask) for (...) { oldmask = sigblock(1 << (SIGALRM - 1)); .... (void)sigsetmask(oldmask); } Sigblock and sigsetmask together provide a nice way to encapsulate a critical section to protect them from the delivery of asynchronous signals. Along the same grain, sigpause provides a neat way to set a signal mask in an *atomic* manner: oldmask = sigblock(1 << (SIGALRM - 1)); (void)setitimer(.....); sigpause(oldmask); The above code is the only *sure* way to use sigpause with SIGALRM. As you must block against delivery of the SIGALRM between the setitimer() call and the sigpause(). If you don't the program will intermittantly hang forever at the sigpause() (as the SIGALRM *can* be delivered *between* the calls to setitime() and sigpause()). Note that sigpause will restore the signal mask to oldmask after the arrival of the SIGALRM. Keith Muller UCSD Computer Center
muller@sdccsu3.UUCP (Keith Muller) (07/17/84)
> Fortunately, there is an easy workaround; change the previous code > to read: > > for (...) { > oldmask = sigblock(1<<SIGALRM); > ... > sigblock(oldmask); > } This won't work, this will block off SIGTERM not SIGALRM. Sigblock() requires that to block off signal i the i-th bit in the mask must be set. (The bits are numbered from 1 to n). So that line must read: oldmask = sigblock(1 << (SIGALRM - 1)); Note this easily confused with select()'s mask which does NOT need to have 1 subtracted since descriptors are numbered from 0 to n. Keith Muller UCSD Computer Center