Re: continuations and threads sperber@xxxxxx 21 Feb 2000 08:15 UTC

>>>>> "Jim" == Jim Blandy <> writes:

>> > I think this is pretty gross, but it does allow a natural
>> > correspondence between C function calls and Scheme function calls:
>> > continuations preserve active calls to C functions, as well as Scheme
>> > functions.  If it's important to your users to be able to write C
>> > functions that can call and be called by Scheme functions, I think
>> > this is a plausible implementation choice.  I'm not aware of any other
>> > implementation that does this while requiring so little distortion of
>> > your C code.  (But if you know of one, I'd love to hear about it!)
>> There is another way (I have not implemented it yet though)... but it
>> is too complex to describe at this hour of the night!

Jim> :)

Jim> Now that you mention it, there is something I remember Roland McGrath
Jim> implementing for SMLNJ, while working for Olin Shivers.

Jim> I think the basic idea was that frames (activation records) for ML
Jim> functions were kept on the heap (as normal), while frames for C
Jim> functions were kept on a C stack.  You let the ML frames behave like
Jim> the first-class objects they are --- you can call/cc to your heart's
Jim> content --- but if you try to return to a C frame in a non-stacklike
Jim> order, the ML/C boundary code detects this and throws an exception.

Jim> I think he even arranged it so that if you returned early to an older
Jim> C frame, the younger frames would be popped appropriately (via
Jim> longjmp), and any references to younger C frames would be marked
Jim> invalid, so you'd get an error if you tried to use them.

The C FFI Richard Kelsey and I implemented for Scheme 48 does this as
well.  Here's the relevant blurb from the documentation:

There are some complications that occur when mixing calls from C to
   Scheme with continuations and threads. C only supports downward
   continuations (via longjmp()). Scheme continuations that capture a
   portion of the C stack have to follow the same restriction. For
   example, suppose Scheme procedure s0 captures continuation a and then
   calls C procedure c0, which in turn calls Scheme procedure s1.
   Procedure s1 can safely call the continuation a, because that is a
   downward use. When a is called Scheme 48 will remove the portion of
   the C stack used by the call to c0. On the other hand, if s1 captures
   a continuation, that continuation cannot be used from s0, because by
   the time control returns to s0 the C stack used by c0 will no longer
   be valid. An attempt to invoke an upward continuation that is closed
   over a portion of the C stack will raise an exception.

   In Scheme 48 threads are implemented using continuations, so the
   downward restriction applies to them as well. An attempt to return
   from Scheme to C at a time when the appropriate C frame is not on top
   of the C stack will cause the current thread to block until the frame
   is available. For example, suppose thread t0 calls a C procedure which
   calls back to Scheme, at which point control switches to thread t1,
   which also calls C and then back to Scheme. At this point both t0 and
   t1 have active calls to C on the C stack, with t1's C frame above
   t0's. If thread t0 attempts to return from Scheme to C it will block,
   as its frame is not accessable. Once t1 has returned to C and from
   there to Scheme, t0 will be able to resume. The return to Scheme is
   required because context switches can only occur while C code is
   running. T0 will also be able to resume if t1 uses a continuation to
   throw past its call to C.
Cheers =8-} Mike
Friede, Völkerverständigung und überhaupt blabla