Re: continuations and threads Jim Blandy 25 Feb 2000 21:34 UTC
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. Mike> The C FFI Richard Kelsey and I implemented for Scheme 48 does this as Mike> well. Here's the relevant blurb from the documentation: Mike> Mike> There are some complications that occur when mixing calls from C to Mike> Scheme with continuations and threads. C only supports downward Mike> continuations (via longjmp()). Scheme continuations that capture a Mike> portion of the C stack have to follow the same restriction. For Mike> example, suppose Scheme procedure s0 captures continuation a and Mike> then calls C procedure c0, which in turn calls Scheme procedure s1. Mike> Procedure s1 can safely call the continuation a, because that is a Mike> downward use. When a is called Scheme 48 will remove the portion of Mike> the C stack used by the call to c0. On the other hand, if s1 Mike> captures a continuation, that continuation cannot be used from s0, Mike> because by the time control returns to s0 the C stack used by c0 Mike> will no longer be valid. An attempt to invoke an upward Mike> continuation that is closed over a portion of the C stack will Mike> raise an exception. Actually, this is less powerful than what I described. In Roland's system, you don't need to unwind the C stack when s1 invokes a. You only need to unwind the C stack when s0 returns. If s0 instead invokes some continuation b captured by s1, that's fine. The key observation here is that the only necessary connection between C frames and Scheme frames occurs when control crosses a Scheme/C or C/Scheme boundary. Each C frame may be exited only once, and you may only return to a C frame after popping all younger C frames. But beyond those rules, there's no necessary restriction on the way Scheme frames may behave.