limit check insertion

Matthew Fluet Matthew Fluet <fluet@CS.Cornell.EDU>
Wed, 24 Oct 2001 13:14:57 -0400 (EDT)


> On thinking about it I'm confused about the need for the GC loop.  We already
> limit where context switches between threads can happen (otherwise the space
> that is guarenteed in the check could be gone by the time we allocate).
> Can't we just expand that region to include the GC?  I.e., no context switches
> during the GC and limit check code.
> It must be true currently that we are letting a switch happen as the GC
> is returning.  If we just stop that then we are ok, right?

Yes, except that the way a preemptive thread gets invoked is by a GC.

There are multiple, possibly orthogonal issues.  Limit checks and garbage
collections are a little overloaded in their roles, because they also
support preemptive thread switching and interupt handling.  Forcing
frontier to be 0 and hitting a limit check (even a zero byte limit check)
will invoke the GC, which will switch to the pending thread.

At the other extreme, I could imagine both LimitCheck and
MaybeSwitchThread statements.  MaybeSwitchThread would check some global
state (which would be fiddled with by the runtime the way it currently
fiddles with frontier to force limit check failures); if true, we enter
the runtime to switch to the new thread (acutally, we might not even have
to enter the runtime; if the gcState had a pendingThread field, then we
could use the inline assembly version of threadSwitch to to switch to the
pendingThread); if false, we continue with normal processing.

Under the emerging formalization of limit checks, MaybeSwitchThread would
have the property of resetting the V function to 0 -- i.e., can't assume
any free heap space after switching to another thread and returning.

It is now orthogonal to insert MaybeSwitchThreads and then insert
LimitChecks.  They each follow their own criteria for when they should be
inserted.

The explicit gc loop now becomes implicit by the fact that a LimitCheck
will probably always be inserted immediately after a maybeSwitchThread.
And, this being the case, we come full circle to the current approach: if
we're likely to put a limit check at every possible thread switch point,
why don't we use a limit check to do the thread switch.

Note, however, that with both maybeSwitchThread and limitCheck, you can
get subtly different run-time behavior.  The criteria for
maybeSwitchThread is pretty weak -- something like for every path through
the program, there is no sequence of more than N (N = 10 or 20?) blocks
that does not have a maybeSwitchThread.  So, you could easily end up with
many fewere maybeSwitchThreads than limitChecks.  So, preemptive switches
could be pending for longer than they are with limitChecks forcing the
switch.