[MLton] interrupted system call

Matthew Fluet fluet@cs.cornell.edu
Wed, 24 Mar 2004 20:43:09 -0500 (EST)


> > On the other hand, if signals aren't being handled in ML, then what
> > happens to the signal?  I guess the process is terminated?
>
> If the signal isn't handled in ML, then the handler must either be
> SIG_DFL (terminate the process) or SIG_IGN (ignore the signal).

What I was worried about was if installing a singal handler for _any_
signal meant installing the C side signal handler for all signals.  I.e.,
we'd wait until we got back to ML to decide whether it is a signal handled
by the user.

> > Another issue is critical regions.  If the system call is burried down in
> > the basis, and I try to wrap a higher-level function in atomicBegin/End,
> > then the ML signal handler won't get run in the restart loop.  For some
> > signals, maybe this is o.k. (keep making progress until we leave the
> > critical region), but for the interval timer, this is bad.  Because if the
> > system call is taking an appreciable about of time, then the signal is
> > likely to be raised again when the call is restarted.
>
> To be sure I understand, is the problem that the system call may never
> complete because it is always interrupted by the signal?

Correct.

> > Maybe the right thing is to put a canHandle check in the restart loop, and
> > if we are in a critical region, then just let the exception propagate.
> >
> > Another option might be to have the C signal handler block signals until
> > the ML signal handler gets a chance to run.
>
> While both of these make sense, I'm not yet convinced that we should
> do anything to help a programmer who puts a slow system call in a
> critical section.

Well, I just want to know what to expect from doing
  fun atomicPrint s = (atomicBegin (); print s; atomicEnd ());
which is going to incur (multiple) system calls down below.

Also, I'll remind you of Stephen's original argument against SA_RESTART:

> Suppose we have an SML
> program that installs an SML signal handler for Posix.Signal.usr1 and
> then makes a call to Posix.IO.readVec, which blocks at the read system
> call.  If a SIGUSR1 arrives, then the C runtime system handler will
> run, setting the limit so that at the next limit check the SML handler
> will run, and then terminate.  The system call will then restart and
> block.
>
> So, it looks like to me that the SML signal handler will never get a
> chance to run.  This seems wrong.

I'm just thinking about what it would take to make the basis library
thread safe.  If we wrap Posix.IO.readVec under a restart loop, then
either
1) we must always call Posix.IO.readVec outside a critical region;
   seems like it would be hard to make StreamIO and ImperativeIO
   thread safe.
2) we allow calls to Posix.IO.readVec inside a critical region of the
   Basis;  so, the programmer can assume that thier USR1 signal handler
   will run if they call Posix.IO.readVec outside a critical region, but
   not if they call TextIO.inputLine.

> Hmm, that makes me think that another option is to always block signals
> in a critical section, i.e.  make atomicBegin block signals and
> atomicEnd unblock them.

That thought had occured to me, but then what does canHandle do?  If
signals are blocked in critical sections, then we wouldn't try to invoke
the signal handler anyway.

> Putting the canHandle check in the restart loop makes me nervous -- I
> am worried that it makes code harder to write because then code that
> makes system calls must now always handle the case that the intr
> exception is raised, because it may be called from within a critical
> section.  That seems to obviate most of the benefit of automatic
> restarting.

I think it's just two sides of the same coin:
A) Do I go out of my way to make system calls outside of critical regions
   so that my signal handler always gets a chance to run.
B) Do I go out of my way to handle intr exceptions so that I can put
   system calls inside critical regions.