mcooper@usc-oberon.UUCP (Michael A. Cooper) (08/05/86)
-=-=
[VAX 4.2BSD]
I've been trying to figure out how to jump out of a read()
via a signal alarm. My problem is that things wedge up
when (apparantly) read() is restarted when the alarm goes
off. This occurs when there is no input for read() to read.
Hence, wakeup() is never called by the alarm. Below is the
basic code:
signal(SIGALRM, wakeup);
alarm(3);
recvbuf[0] = getch();
alarm(0);
And here's getch()...
getch()
{
char c;
(void) read(0, &c, 1);
return(c & 0377);
}
According to the signal(3c) manual:
"If a caught signal occurs during certain system calls, caus-
ing the call to terminate prematurely, the call is automati-
cally restarted. In particular this can occur during a read
or write(2) on a slow device (such as a terminal; but not a
file) and during a wait(2)."
I assume this is my problem. Now, has anyone figured out a way
around this? It seems that catching a signal during certain
system calls should not be a problem. It's not too much to ask
for, is it?
--
Michael Cooper, U of Southern California Computing Services, (213) 743-3462
UUCP: {sdcrdcf, uscvax}!usc-oberon!mcooper
ARPA: mcooper@usc-oberon.arpa BITNET: mcooper@uscvaxq
chris@umcp-cs.UUCP (Chris Torek) (08/07/86)
In article <667@usc-oberon.UUCP> mcooper@usc-oberon.UUCP (Michael A. Cooper) writes: >[VAX 4.2BSD] This happens to be important. >I've been trying to figure out how to jump out of a read() >via a signal alarm. Under 4.2, the only way to do that is with setjmp()/longjmp(). >My problem is that things wedge up when (apparantly) read() is >restarted when the alarm goes off. This occurs when there is no >input for read() to read. Hence, wakeup() is never called by the >alarm. Not so! Wakeup() *is* called, but when it returns, your process jumps right back into read(). You must ensure that wakeup() does not simply return. > "If a caught signal occurs during certain system calls, caus- > ing the call to terminate prematurely, the call is automati- > cally restarted. In particular this can occur during a read > or write(2) on a slow device (such as a terminal; but not a > file) and during a wait(2)." > >I assume this is my problem. Now, has anyone figured out a way >around this? It seems that catching a signal during certain >system calls should not be a problem. It's not too much to ask >for, is it? No, not too much. But Berkeley has tried interruptable system calls and restarting system calls, and restarting calls usually win. As a concession to all that code that assumes reads are interrupted, 4.3BSD provides a per-signal flag that allows the old behaviour. But this is portable: jmp_buf timeout; ... if (setjmp(timeout)) { /* nothing from the read */ ... } else { signal(SIGALRM, wakeup); alarm(3); c = getch(); alarm(0); /* got it */ ... } wakeup() { longjmp(timeout, 1); } This method has its pitfalls, however. In particular, on a very loaded system this may never call read() at all. A 4.[23]BSD- specific solution is to use select() rather than alarm(): /* 4.2 style `int's to select(); under 4.3, use fd_set et al */ int getch(timeout) int timeout; { struct timeval tv; int in, cc; char c; tv.tv_sec = 3; tv.tv_usec = 0; in = 1; /* select on stdin */ if ((cc = select(1, &in, (int *) 0, (int *) 0, &tv)) < 0) { /* * Figure out why select quit: EINTR => interrupted * by a signal; else something went wrong. */ ... } if (cc == 0) return (EOF); /* no input ready */ /* the following is not terribly efficient */ if ((cc = read(0, &c, 1)) != 1) { if (cc == 0) return (EOF); /* no input at all */ /* * Handle error */ ... } return (c); } If you are reading more than one character, making select act like alarm becomes quite tricky, as there is no indication as to much time was spent waiting in select before some input arrived. The 4.3BSD select manual warns that in the future, the timeval provided may be modified to reflect this, making that job easier. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu