Proposed change to ForeignPtr
Simon Marlow
simonmar at microsoft.com
Wed Sep 11 05:24:58 EDT 2002
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
More information about the FFI
mailing list