ioctl not terminated by SIGALRM (not bug, wish list)

Greg Earle earle at smeagol.UUCP
Fri Jan 10 19:18:20 AEST 1986


I just came across something that is aggravating.  While implementing
an XMODEM program for transfers between PC's (PC-TALK) and Suns, I
encountered this:

My first method of dealing with reading from the transmitter (PC)
with a timeout specified was to
        alarm(TIMEOUT_PERIOD);
        n = read(...);
        alarm(0);       /* turn off alarm when read returns */
Note that this had to be ported to a System V machine, so I didn't use
select().  To avoid read overhead, I read a 'sector' at a time, and the
read routine dishes out the chars one at a time to the caller.
This consideration meant that if the read of the entire sector timed out,
I would have to NAK the sender and retransmit the block.
I found that there were a LOT of re-transmit requests, apparently because the
Sun could suck it in faster than the PC could dish it out (A lot of reads
of < sector size #'s of chars.).  I decided a neat way to throttle the Sun
and reasonably ensure that minimal reads would occur would be to use the
BSD-ism ioctl, FIONREAD.  I implemented a while loop to 'poll' the device
via this ioctl until the FIONREAD said that the necessary number of chars to
read was ready in the input stream.  Then comes the read(), and voila -
everything's wonderful.  Minimal retries due to bad reads.

Now here's the rub.  Unlike read(), which is supposed to return if you
catch the alarm SIGALRM, ioctl WON'T.  Thus, if for any reason a
condition exists which causes the xmitter to time out (as seen by
receiver; e.g. if I start the receiver first, before the xmitter,
receiver will time out after sending the first NAK), the alarm signal
will be delivered while inside the
while-FIONREAD-returns-<-SECSIZ-do-ioctl-again loop.  Since the ioctl
doesn't terminate on the signal, it gets ignored (the signal) and the ioctl
just sits there and loops away ...

I am merely suggesting here that I think it would be good if ioctl would
emulate read()'s behavior w. respect to these signals - return -1 and errno =
EINTR.  I have seen other instances where an ioctl on a line attached to
a PC will hang if the PC is not running a program that opens the COM port
(thus pulling up whatever signals it is that UNIX wants to see on the other
end of the line you are ioctl'ing), and it would be helpful here, as well.

STOP PRESS - another reason I can't use just an alarm(n)-read()-alarm(0)
cycle is because of this statement, in signal(2) [Sun] :
"If a caught signal occurs during certain system calls, causing the call to
terminate prematurely, the call is AUTOMATICALLY RESTARTED. [emphasis MINE]
In particular this can occur during a 'read' or 'write(2)' on a slow device
(such as a terminal; " etc etc.

So much for detecting read timeouts.  Thanks a whole lot.

So...
        (1) Is there any way to disable this 'feature' of restarting the call?
        (2) If I set the line to non-blocking mode, so the read won't block,
        will read return -1 errno=EINTR if by some miracle the alarm signal is
        received during the read? (I assume the read will be way too fast in
        returning to ever timeout, if it's non-blocking)
        (3) Is there any way to do what I want, other than some gross hack
        like doing a setjmp() between the ioctl(FIONREAD) and the read(),
        with the handler doing the longjmp()??

Argghh.....

As always, if there is something I overlooked that makes this impractical
or completely ridiculous, feel free to correct.

        Greg Earle
        JPL Spacecraft Data Systems group
        sdcrdcf!smeagol!earle                   (UUCP)
        ia-sun2!smeagol!earle at cit-vax.arpa      (ARPA)



More information about the Comp.bugs.4bsd.ucb-fixes mailing list