[comp.unix.microport] odd behavior in read

hedrick@athos.rutgers.edu (Charles Hedrick) (03/13/88)

I've been playing with jove (a dialect of Emacs) under SV/AT.  It is
essentially unusable.  Every 30 seconds, it hangs for about 5 seconds
with the disk making noises like it is being swapped.  During this
time, if you type anything it is lost.  I believe I now know most of
what is going on, and it is rather alarming (SIGALRM'ing, to be
precise). So here goes:

Jove likes to display the time on the mode line.  In order to keep
this up to date, it uses alarm (2).  The code is classical: There is a
short subroutine that gets the time and updates the mode line.  It
ends by doing alarm(30) to set the next alarm, and signal(SIGALRM,)
with itself as the second argument, to set things so that it gets
called on the alarm.  The code for reading a character then has to be
able to deal with the possibility that read will return -1 with EINTR,
because of the lousy System V interrupt semantics.  Anyway, this
arrangement manages to trigger what looks like one serious performance
deficiency and one outright bug in the kernel.  (If it isn't a bug,
then the people who wrote the SVID should be shot.)  First, most of
the time when the alarm happens, the disk drive makes noises like the
process is being swapped out and in.  This happens even when I have
been typing to it, and there's no other program running, so I know it
is swapped in.  During the time that these swapping noises are going
on, any characters I type are lost.  I put some hacks into the
character read routine.  I clear the read buffer to nulls before
doing the read.  If read returns < 0, I do a strlen on the buffer to
see whether there's anything there.  It turns out that read does
in fact return the characters I have typed, but it sets EINTR and
returns something < 0, so the code quite correctly believes there
is nothing there.

OK, here are the bugs I claim:

1) the program should not swap everytime an alarm goes off.  I assume
it is doing this because of the usual problems with memory management.
(I've seen this before with sbrk, as reported in this group.)  While
I'm sympathetic with the problems of memory allocation using the
blasted 286 chip, I don't see how we can live with a system that
swaps your program everytime it takes a signal.

2) If read has returned data, it should return a count of the data,
not an error.  This is obviously a matter of definition, and it's
always possible that SV/AT is following the SVID (I don't happen to
have it handy).  But clearly you want your code to look like

 do
   nchar = read(0, buffer, sizeof buffer);
  while (nchar < 0 && errno == EINTR);

(Well, actually you want the read to continue automatically after
the signal, so you just need the read, but that's BSD, and it would
be too much to expect SV to work like BSD.  Maybe in SV release 4...)

The current semantics require you to do

 do {
   bzero(buffer, sizeof buffer);
   nchar = read(0, buffer, sizeof buffer);
   if (nchar < 0)
     nchar = strlen(buffer);
  }
  while (nchar < 0 && errno == EINTR);

which is completely absurd, not to mention that it doesn't let you
read nulls all the time, and null happens to be an important command
in Emacs.

3) Even with the completely absurd code above, if I type more
characters than the size of the buffer, the extra ones appear to
be lost.

I am mentioning all of this to the group, rather than just SPR'ing
it to Microport, because I'm hoping someone else will know enough
about System V to verify my understanding that this is a bug.

I can't help wondering whether something like this is happening
in UUCP, and may be at least part of the explanation of the
continual problems people have getting reliable UUCP connections.

PS: for those of you that like jove, it's possible to use it, but you
have to turn off all the timers, so it doesn't use alarm.  When I
get a version I like, I'll post the diffs.  I will probably use
a variant of the horrible hack shown above, so that it is safe to
use the timers.

dyer@spdcc.COM (Steve Dyer) (03/14/88)

The behavior of read() you describe, while very unBerkeleylike, is not
a bug in your particular version of UNIX 386; it's the behavior you'd get
in any version of UNIX other than 4.[23], including V6 and V7.  Trouble is,
now in S5 you can specify to the TTY driver the minimum number of chars to
wait for and/or a time to wait.  This is different from RAW and CBREAK
modes in V7-derived UNIX systems, whose semantics always guarantee that a single
character (or -1) is returned, and doesn't mesh well with the older handling
of signals.  Why don't you try setting the minimum number of chars to wait to 1,
to get the same behavior as a V7 system?  This should make Jove work as well as
any screen editor did under V7.
-- 
Steve Dyer
dyer@harvard.harvard.edu
dyer@spdcc.COM aka {ihnp4,harvard,husc6,linus,ima,bbn,m2c}!spdcc!dyer