[net.unix-wizards] proper recovery from EINTR

steve@anasazi.uucp (12/10/84)

The folks here at Anasazi have been puzzling over this one for a while.
Any pointers to a solution, or even an informed discussion, would be
appreciated.

The problem is to write two functions v_read and v_write which behave
like the UNIX system calls read and write, except that they work "properly"
on a slow device while (unrelated) signals are being caught.  Specifically,
assume that the file descriptor may denote a "slow" device such as a terminal,
and various signals may be set up to be caught, and other processes may be
doing kill's on those signals at random times.  Despite this, in cases where
read and write would return -1 with errno = EINTR, v_read and v_write are
required to transfer all n bytes correctly, in the correct order, with no
omissions or duplications, and return the number of bytes n that were
transferred (assuming no real error like EOF occurred).

Here is a first cut for v_read (v_write is similar):

	v_read(fd, buf, n)

	int fd, n;
	char *buf;

	{
		register int i;
		register char *cp;
		int serrno;

		serrno = errno;
		cp = buf;
		i = 0;
		while (i < n)
			switch (read(fd, cp, 1))
			{
			  case -1:
				if (errno != EINTR)
					return -1;
				break;
			  case 0:
				errno = serrno;
				return i;
			  case 1:
				cp++;
				i++;
				break;
			  default:
				abort();
			}
		errno = serrno;
		return n;
	}

Some obvious questions:  If you do a read system call with a length > 1,
and EINTR occurs, is there a way to find out how many bytes were actually
transferred?  Even in the length = 1 case, can you really be sure that the
one byte was not transferred?  Finally, is there a way to speed this up,
and avoid n system calls to do the read?

Thanks for any help.

Stephen E. F. Villee (decvax!noao!terak!anasazi!steve)
International Anasazi, Inc.
2219 East University Drive
Phoenix, Arizona 85034
(602) 275-0302

gwyn@BRL-TGR.ARPA (12/10/84)

> The problem is to write two functions v_read and v_write which behave
> like the UNIX system calls read and write, except that they work "properly"
> on a slow device while (unrelated) signals are being caught.

On 4.2BSD, you could block signals during a read() or write() without
losing them.  This would be MUCH better than character-at-a-time
I/O system calls!

phil@rice.ARPA (12/10/84)

> On 4.2BSD, you could block signals during a read() or write() without
> losing them.  This would be MUCH better than character-at-a-time
> I/O system calls!

Ahhh, but sometimes that does not produce the desired effect.  What
about the case where you want the signal to do something (like set a
flag) but you don't want the system call to be interrupted?  I can't
remember for sure, but I think the message that brought this whole
issue up talked about trying to do something like this.

                                William LeFebvre
				Department of Computer Science
				Rice University
                                <phil@Rice.arpa>