I'm afraid George's questions have also rekindled my curiosity about whether implementing Haskell finalizers is really as hard as it sounds. Much has been written, but I still don't think we've got to the nub of the issue.
On the face of it, if you can implement 'foreign import ccall safe', then you have a re-entrant runtime system. The times at which the program can make one of these foreign calls are limited, i.e. in the IO monad only - but I believe there's nothing particularly special about IO computations in the evaluation models used by nhc98 and Hugs (correct me if I'm wrong). Alastair writes: > The way GHC implements preemption is an optimized form of: set a bit > when preemption is needed; and make sure that generated code will test > that bit whenever it is in a position to perform a context switch. > > What you're asking Hugs and NHC to do is: add a function to a list > whenever you have a finalizer to run; make sure the interpreter will > test that bit whenever it is in a position to perform a context > switch. > > It's basically the same. We don't have to mess around with signals to > provide a regular timer interrupt but that's the easy bit of the code. Ok so far. > We can probably avoid messing around with multiple C stacks. That's a > significant saving but, it's the complexity of that is fairly > self-contained - we could probably steal some code from some other > language implementation. > > The cost is going over all data structures in the system making sure > that operations on them are suitably atomic. One of the issues I > remember from old versions of GHC was that some of the primops would > do some work, allocate some memory, then finish the job. The classic > error to make in that code was for the second half of the code to > assume almost anything about what happened in the first half of the > code: how much space is on the stack, does a table have free space in > it, is this pointer into the middle of an object ok? You certainly can't keep local variables live across a heap check, everything has to be saved on the stack. Hugs is different because it has a conservative GC, so doesn't need to save everything on the stack for a GC. But how does it implement a safe foreign call? Presumably it must save away state on the stack in a way that the computation can be resumed safely, and that's all you need in order to be able to run a Haskell finalizer. > The problem is the scope: every single data structure and every bit of > code that accesses it has to be vetted and we have to keep it in mind > as we maintain the code. It's a high price to pay and I don't think > it's necessary (because all you really need is for the runtime systems > to talk to each other in very limited ways). I don't quite understand this: could you give a concrete example of some extra invariant that has to be maintained? In GHC, context switches happen at very precise points (i.e. heap checks) so I don't think we have these kind of problems; certainly I don't remember vetting every single data structure. Can't Hugs use a similar approach? Cheers, Simon _______________________________________________ FFI mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/ffi