Hi Antony, [btw will you be in New Haven around 16-19 Nov? I'm going to swing through there on my next trip over and it'd be good to see you and maybe ever humiliate myself again in the Gunks with you.]
> (My code currently uses touchForeignPtr in a Haskell > finalizer to express a liveness dependency, but this is apparently > not supported by the latest FFI spec. and won't be.) I think it was agreed that we need to replace touchForeignPtr with something else to let us express liveness dependencies. I hope you'll take part in that discussion since you and John Meacham are the only ones who seem to have used it so far. As a strawman to get discussion rolling, would something like the following do the job? -- | -- keepAlive x y ensures that the finalizer for y is not run -- until after the finalizer for x has run to completion. -- Of course, it might not even run then if y is still live -- at that point. keepAlive :: ForeignPtr a -> ForeignPtr b -> IO () Off the top of my head, I'd say the name sucks, the argument order is open to change and the semantics will cause headaches for GHC. Any other objections? :-) > I would really like to have just a little bit more in-depth > understanding of why Haskell finalizers are an impossibility. In > particular, the current finalizers.txt document on cvs.haskell.org > states: >> [...] It turns out that the real killer is shared thunks. Suppose the main thread is evaluating a thunk and is interrupted by a finalizer which needs to evaluate the same thunk. What should you do? The choices are: 1) Report an error. This is easy but semantically wrong. 2) Block the finalizer until the main thread completes evaluation just as GHC does. Blocking the finalizer would require all Haskell implementations to implement preemptive concurrency. This is thought to be an excessive burden. 3) Let the finalizer evaluate it. Eventually both finalizer and main thread will produce equivalent results and update the thunk with the same result. Sounds easy but: - it's quite delicate to achieve this goal. - it would require us to turn off blackholing - an implementation technique which eliminates some serious space leaks. Given the choice of poor semantics, huge implementation effort and reduced portability, and space leaks, we decided to redefine our goals and declare C finalizers adequate. [I tried to describe this problem in finalizers.txt this morning but I think the above is clearer.] >> We want to be able to use mutable Haskell state from a Haskell >> finalizer, but we clearly can't use IORefs. Finalizers which >> modify IORefs will always contain race conditions. > Although I suspect that the reason why we "clearly can't use IORefs" > or why such code will "always contain race conditions" is clear and > obvious to everyone else involved in this discussion, it is not at > all clear to me as an outsider. If someone would be kind enough to > write just a sentence or two clarifying the "obvious" problem, I > would be very grateful. Finalizers in Hugs and NHC behave like interrupts: at some random part of the execution of your program, the finalizer is run. Just as you worry about what happens to your money when interrupting C code like: int old = account.balance; int new = old + 10000; account.balance = new; so you should worry about what happens to the corresponding Haskell code which uses IORefs. One way to fix this instance of the problem in Haskell is to provide an atomic operation to modify the value of an IORef. [Finalizers behave like threads in GHC. The same problem results.] -- Alastair Reid [EMAIL PROTECTED] Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/ _______________________________________________ FFI mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/ffi