
The other complication I can see is that ForeignPtr finalisers can't be Haskell. So I have to call the Haskell finalisation from C. Is that safe? I'm afraid I still don't fully understand why Haskell finalisers are unsafe or why (if) calling Haskell from a C finaliser (which then called C land again) would be any safer.
If you don't mind your code being non-portable, then Foreign.Concurrent provides Haskell finalisers. This support will be available only on Haskell implementations which implement pre-emptive concurrency (i.e. just GHC for now). Cheers, Simon

I'm afraid I still don't fully understand why Haskell finalisers are unsafe or why (if) calling Haskell from a C finaliser (which then called C land again) would be any safer.
The FFI standard doesn't say that calling C finalizers is unsafe (which would imply that the finalizers potentially do something naughty). Rather, the standard says that finalizers are called in a restricted context in which they are not allowed to call back into Haskell. The reason that finalizers must be written in C and cannot call into Haskell is that it requires pretty much all the machinery needed to implement preemptive concurrency (multiple C stacks, context switches, etc.) which was felt to be an excessively high burden on a Haskell implementation just to let you call C functions. (Of course, GHC already has this machinery which is why they provide enhanced functionality.) Why does it require most of the machinery of preemptive concurrency? Suppose that a finalizer requires the value of something that is currently being evaluated by the main thread. (This is very common and pretty much impossible to reason about in Haskell. For example, it could be a dictionary object or the thunk '(==) dict_Int'.) The correct thing to do if this happens is to block the finalizer, run the main thread until the shared thunk is updated with a value, and then restart the finalizer. To block a thread in this way, we have to switch C stacks, perform a context switch, etc. QED. -- Alastair Reid haskell-consulting.com

Hello, Thanks for that explanation, I see the problem now. Though to be honest, I'm not convinced that the situation for Haskell implementations which don't implement pre-emptive concurrency need be as bad as you suggest. But that's probably presumptious of me seeing as I know little about the implementations of either Hugs or nhc (or ghc for that matter:-) I can see there is a potential problem with single threaded programs which may never call yield, though even in this situation it I would think it would be relatively straight forward to have an implicit yield to finalisers at appropriate points (no partially reduced thunks in the heap). But then again, I guess the logic is that since foreign object finalisers will usually be foreign functions which don't re-enter Haskell it's probably not worth the effort. The other thing that strikes me about this is don't we also have the same potential problem with weak pointer finalisers? Can they be supported in Haskell without pre-emptive concurrency? Regards -- Adrian Hey On Monday 05 Jan 2004 4:39 pm, Alastair Reid wrote:
I'm afraid I still don't fully understand why Haskell finalisers are unsafe or why (if) calling Haskell from a C finaliser (which then called C land again) would be any safer.
The FFI standard doesn't say that calling C finalizers is unsafe (which would imply that the finalizers potentially do something naughty). Rather, the standard says that finalizers are called in a restricted context in which they are not allowed to call back into Haskell.
The reason that finalizers must be written in C and cannot call into Haskell is that it requires pretty much all the machinery needed to implement preemptive concurrency (multiple C stacks, context switches, etc.) which was felt to be an excessively high burden on a Haskell implementation just to let you call C functions. (Of course, GHC already has this machinery which is why they provide enhanced functionality.)
Why does it require most of the machinery of preemptive concurrency? Suppose that a finalizer requires the value of something that is currently being evaluated by the main thread. (This is very common and pretty much impossible to reason about in Haskell. For example, it could be a dictionary object or the thunk '(==) dict_Int'.) The correct thing to do if this happens is to block the finalizer, run the main thread until the shared thunk is updated with a value, and then restart the finalizer. To block a thread in this way, we have to switch C stacks, perform a context switch, etc. QED.
-- Alastair Reid haskell-consulting.com

On Monday 05 Jan 2004 3:14 pm, Simon Marlow wrote:
The other complication I can see is that ForeignPtr finalisers can't be Haskell. So I have to call the Haskell finalisation from C. Is that safe? I'm afraid I still don't fully understand why Haskell finalisers are unsafe or why (if) calling Haskell from a C finaliser (which then called C land again) would be any safer.
If you don't mind your code being non-portable, then Foreign.Concurrent provides Haskell finalisers.
Oh yes, so it does :-) I'd just been looking at the FFI documentation (only). Thanks for pointing that out.
This support will be available only on Haskell implementations which implement pre-emptive concurrency (i.e. just GHC for now).
OK, I think understand now thanks to Alistair Reids explanation. I had been trying to keep my code portable (it's a library binding I hope to make available to Haskell folk sometime soon). But this seems to be quite difficult. AFAICS the situation is that the only really portable solution to this problem is for the reference counting thing (or doubly linked lists or whatever) to be done in C (which I guess is what everybody's been saying all along :-). Regards -- Adrian Hey
participants (3)
-
Adrian Hey
-
Alastair Reid
-
Simon Marlow