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