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

Firstclass continuations



Well, I *finally* got a little time to start familiarizing myself with
T, and discovered the following:

-- CATCH creates something called an "escape procedure" whose extent
is dynamic (it lives on the stack) but which is, I imagine, extremely
efficient to create and invoke.

-- CALL-WITH-CURRENT-CONTINUATION creates a different kind of thing,
an "upward continuation" it calls itself, with indefinite extent but
with more overhead to create and invoke -- creation involves copying
the stack into the heap, and invocation requires copying the
continuation back into the stack.

Now I have some questions and a "wish list".  Questions: how do upward
continuations (the ones created with CALL-WITH-CURRENT-CONTINUATION),
which can be multiply invoked, interact with dynamic binding and
UNWIND-PROTECT?  E.g., if a continuation is created in the (dynamic)
scope of an unwind-protect, do the cleanup forms get executed only the
first time the continuation is invoked, or every time, or what?

More philosophically, how *should* this work?  Seems like, for at
least some uses of UNWIND-PROTECT, we want the cleanup forms to be
invoked exactly once, not when the continuation is *invoked* but
rather when it is *reclaimed* as garbage (in the normal case, of
course, these two are closely tied together).  Could we arrange for
the GC to do any cleanups before reclaiming a continuation?

I would greatly prefer that there be only one primitive for grabbing
the current continuation.  The question, seems to me, is whether the
system could be intelligent enough to keep it on the stack (as CATCH
does now) in at least the important cases in which that's possible.
Well, surely Orbit can verify, for a given CATCH, that its
continuation is neither consed with nor passed to a user function
which might squirrel it away; this covers the same cases as Common
Lisp's BLOCK and RETURN.  Would it be acceptable if, in the cases
corresponding to CL's CATCH/THROW (where the THROW is not in the
lexical scope of the CATCH), the continuation were always heap-consed?

And second, I have in mind an application where I want to use
continuations to implement multitasking.  I expect to have a very
large number (hundreds) of little processes, with time slices in the
10 millisecond range (probably with explicit calls to the scheduler
rather than timer interrupts).  I know that copying memory is very
fast on the 68020, but even so, it seems like it would be a win if I
didn't have to keep copying all these little continuations into the
stack in order to invoke them.  Seems like the answer is to implement
discontiguous stacks, so the "live" part of the stack can be in the
appropriate area of memory (as I gather Unix insists) but the
more-or-less permanent part can remain in the heap and be accessed
directly.  I may be revealing my ignorance here -- does this make any
sense in the context of T?

-- Scott