Re: continuations and threads
sperber@xxxxxx 21 Feb 2000 08:15 UTC
>>>>> "Jim" == Jim Blandy <xxxxxx@red-bean.com> 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