[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Unwind-Protect and Jumping into the Abyss



R James Noble writes:
> So while I try to find ways to avoid the non-local exits in the code
> in question, this is another plaintive cry asking if anyone has ideas
> about incorporating unwind-protect into Self. Given that the VM source
> code is now available, I suppose I could try that - does anyone have
> any idea how difficult it would be? 

We've been planning to put unwinf protect into the system for a while,
but I guess so far it just hasn't gotten to the top of our wish list
yet.  There's lots of code in the system that is vulnerable to
accidental NLRs.  For example, the following code fragment doesn't
release the semaphore if someCondition holds:

    aSemaphore protect: [ someCondition ifTrue: [^ something]]

A possible solution is to introduce two new primitives:

- aBlock _UnwindProtect: protectBlock exececutes the block (i.e. sends
  'value' to it) and invokes the protectBlock if aBlock does a
  non-local return.  A more general primitive could take arguments for
  aBlock, but that would be a little harder to implement.
- _ContinueUnwind continues the last non-local return caught by
  _UnwindProtect.  Presumably, the last statement in the protectBlock
  would call _ContinueUnwind (if continuation is wanted).

While not completely general, this primitive pair would probably cover
most cases and would be relatively simple to implement as long as
super-high performance is not the main goal.  Would these primitives
be ok for you apllication?

> Another related question, (discovered when poking around these things)
> is what happens to blocks that perform a non-local return where the
> method returned to is not in the running process. (Yes, I was
> attempting a work-around where the protected code would be run in
> another Self process). However, a non-local return in this case seems
> to terminate the process without a return value.

Gee, I though nobody would ever discover this :-)  You're right, NLRs
do not work across processes, and it's not quite clear what the
correct semantics would be.  The most consistent semantics would be to
abort the process invoking the block (as today) because the NLR
completely unwinds the process' stack, and then (unlike today)
continue the NLR in the block's "home process".  However, this has
some weird side effects.  For example, the block's home process is
suspended when the NLR occurs, and it would appear to return
non-locally from the _Yield primitive.  To handle this, the scheduler
would have to use unwind protection so it could clean up its queues
before resuming the process.

To make it short, the current implementation does not handle non-local
returns across process boundaries, but I would guess that the "better"
semantics outlined above wouldn't help you.

-Urs