From: jch@rdg.dec.com (John Haxby)
Subject: Failing system calls and threads
Organization: Digital Equipment Corporation
Date: Fri, 20 Nov 1992 12:07:34 GMT

[First, an apology, this is rather longer that I thought it
 would be.]


Hello,

    While I was writing `cat' (as one does) I tripped up over an
interesting problem around system calls.  The problem revolves around
accurately dealing with system call failures.  In C this is easy, one
writes:

	if (write (fd, buf, sz) < 0)
		if (errno == EINTR)
			/* try again */
		else
			perror ("write")

(more-or-less).  The equivalent code in SRC Modula-3 (2.07) is somewhat
similar, at least in spirit, and this is where the problems arise.
Obviously, if some other thread gets to run between the call to write() and
the examination of errno then the value of errno may no longer be valid or
useful when you come to look at it.

The obvious way around this is to protect the code with some suitable
mutex, eg

	LOCK Cerrno.mu DO
		write (...)
		IF Cerrno.errno ...
	END

but this has at least three significant problems: the overhead in acquiring
a lock around every system call is non-negligable (I assume); not all uses
of errno are guaranteed to be protected (especially in uses within C
libraries); only one outstanding system call is can be permitted (in an
environement that uses kernel-supported threads).

I was thinking about all this while I was making the children's breakfast
this morning: these problems do make using the present Modula-3
implementation somewhat tricky for a good many of the (commercial)
applications I had in mind.  However, whilst putting milk on the Rice
Krispies, it occurred to me that there is a solution, at least for ULTRIX
and probably BSD UNIX.

Before I suggest a solution, though, am I barking up the right tree?  Does
what I say make sense or have I missed something in the implementation?



The solution comes from knowing that errno is introduced by the C library
and not by the kernel: the kernel returns a result and an indication of
whether that result is an error code or a returned value.  On a VAX, the
indication is the carry flag, on a (DEC) mips machine, the indication
is left in a register when the syscall instruction `returns'.  The
implementation of the solution involves re-writing all of the system calls
so that the are of the form (expressed in C)

	int err = sysfunc (&res, arg1, arg2, ...);

The &res is only written to the if the return result is non-zero; the
return result is otherwise what would be written to errno.  The Modula-3
implementation of, say, Unix.write would then look something like this
(syntax notwithstanding :-):

PROCEDURE write (fd: INT; buf: REFANY; sz: INTEGER): INTEGER RAISES{syserr} = 
  VAR
    err: INTEGER;
    res: INTEGER;
  BEGIN
    err := system.syscall (system.write, res, fd, buf, sz);
    IF err # 0 THEN
      RAISE syserr(err)
    ELSE
      RETURN res
   END
END write.

Does this make sense?  Will it avoid the problems I mentioned earlier?
And, a question for the other implementations: can this form of solution be
used? (specifically, are there any implementations out there where errno is
explicitly known by the kernel?)





-- 
John Haxby, Definitively Wrong.
Digital				<jch@rdg.dec.com>
Reading, England		<...!uknet!wessex!jch>

----------------------------------------------------------------
The opinions expressed herein are my own, not my employers.
Newsgroups: comp.lang.modula3