[MLton] interrupted system call

Stephen Weeks MLton@mlton.org
Wed, 24 Mar 2004 11:43:13 -0800


> re too expensive, my interpretation of Matthews thought was that we
> alway run with all signals blocked (more on that below), but when
> the current code checks to see if a signal has occured, instead we
> unblock the signals and then immediately reblock them and then check
> the flag.

My interpretation was that the MLton C signal handler, GC_handler,
would block all signals (I assume this is OK in a C signal handler, is
it?).  Then, GC_finishHandler would unblock them, as it does now.
This would prevent a system call from being interrupted by a signal
more than once.

> The problem is that unblocking and then reblocking signals would
> mean two system calls (both sigblock()) and that is probably too
> expensive.

Ahh, I think I understand. We currently rely on GC_handler to set
limit to zero so that we fail the next limit check.  Your approach
would imply changing our very fast limit check (a single compare) to
two system calls.  Yes, that is unacceptable.

Here's another option: block the signals if the the system call is
interrupted, so that the restart can't be interrupted.  Something like

val Posix.Error.syscall: (unit -> int) -> int =
   fn f =>
   let
      fun call (err: int -> int): int =
	 let
	    val n = f ()
	 in
	    if n = ~1 then err (getErrno ()) else n
	 end
   in
      call (fn e =>
	    if e = intr orelse e = restart
	       then (blockSignals ()
		     ; dynamicWind (fn () => call raiseSys, unblockSignals))
	    else raiseSys e)
   end

That way we only pay the two system calls if the original system call
is interrupted.  We dont pay for limit checks or for
atomic{Begin,End}.

> With regards to `all signals blocked', note that C libraries must be handling
> interrupts.  I guess that the right thing would be to only block signals that
> are handled by ML code.

Makes sense.