The spec says there are no guarantees on the order in which the finalizers are run. Doesn't this make this function almost impossible to use? Suppose one finalizer frees the storage and the other cleans up something it refers to. I'd suggest running the finalizers in the reverse order to the order they were added, i.e. the new finalizer will be run before any existing ones. Now that finalizers are FunPtrs, there should be fewer semantics problems.
The spec says there are no guarantees on the order in which the finalizers are run. Doesn't this make this function almost impossible to use? Suppose one finalizer frees the storage and the other cleans up something it refers to.
I seem to remember that Sigbjorn and Erik dealt with this problem by arranging some kind of GC-visible link between the objects so that until the second finalizer has run, the object will not be considered garbage. I can't remember the details though... Can you remind us how it worked, Sigbjorn? Was it in the heaven from hell paper? -- Alastair
Alastair wrote:
I seem to remember that Sigbjorn and Erik dealt with this problem by arranging some kind of GC-visible link between the objects so that until the second finalizer has run, the object will not be considered garbage.
Sorry, this was nonsense - I hadn't noticed that is was a single ForeignPtr (in Haskell land) as well as being a single object (in C land). Seems like it'd be reasonable to specify an order for these. An alternative would be to drop addForeignPtrFinalizer. I have no idea what the motivation for this function is since I can't think when you'd need/want/prefer to add finalization actions incrementally instead of doing it in one step. Can someone give a motivating example where there is some advantage in adding finalization actions incrementally? -- Alastair
On Tue, Sep 24, 2002 at 06:07:12PM +0100, Alastair Reid wrote:
Seems like it'd be reasonable to specify an order for these.
An alternative would be to drop addForeignPtrFinalizer. I have no idea what the motivation for this function is since I can't think when you'd need/want/prefer to add finalization actions incrementally instead of doing it in one step. Can someone give a motivating example where there is some advantage in adding finalization actions incrementally?
Consider regcomp in Test.Regex.Posix. You malloc an array of bytes and make that a ForeignPtr by adding finalizerFree (your ptr_free). Then you pass it to the C regcomp() function. Now you want to add the C regfree() function as a finalizer. You could call both from a single C finalizer (as Manuel suggests in another thread) but I prefer Haskell. Also that option doesn't work if the array was allocated with mallocForeignPtrBytes.
Consider regcomp in Test.Regex.Posix.
I didn't find this example at all convincing because the existing finalizer was written as a monolithic whole and this is a simpler, clearer way to write the finalizer. But, while thinking about what was wrong with the example, I found something which does convince me. Suppose you live in a world with multiple allocators (and, hence, multiple free functions). [The GHC folk have this with their mallocFP vs malloc distinction.] In this case, you'd have to write a separate finalizer for each allocator because each allocator has its own free function. This would be really inconvenient. So I think I agree that addFPFinalizer should specify a strict evaluation order for the finalizers. I guess what this means for GHC is that all the finalizers should be executed in a single thread. A
On Wed, Sep 25, 2002 at 06:18:35AM +0100, Alastair Reid wrote:
Consider regcomp in Test.Regex.Posix.
I didn't find this example at all convincing because the existing finalizer was written as a monolithic whole and this is a simpler, clearer way to write the finalizer.
If the libraries used newForeignPtr with the type now given in the FFI spec, that finalizer would have to be rewritten in C: void finalize_reg(regex_t *r) { regfree(r); hs_free(r); } Since the order of multiple finalizers is unspecified, one is forced to define a single finalizer in the foreign language that calls your finalizers in the right order. If the struct were allocated with mallocForeignPtr, you need another C call to use as the finalizer for that, say hs_f_free(). Each foreign language needs a name for each finalizer. It would work, but it's ugly, and it underlines the uselessness of addForeignPtrFinalizer without a specified order.
On Wed, Sep 25, 2002 at 09:33:04AM +0100, Ross Paterson wrote:
If the struct were allocated with mallocForeignPtr, you need another C call to use as the finalizer for that, say hs_f_free().
Sorry, that's wrong: If the struct were allocated with mallocForeignPtr, you're stuck. You've no choice but to use addForeignPtrFinalizer, except that you can't because the order of finalizers is unspecified.
participants (2)
-
Alastair Reid -
Ross Paterson