Simon Marlow wrote [snip]
Isn't it worth a little effort? Requiring finalizers to be foreign functions is a serious wart in the FFI I agree, as I've stated before. It's not just that it's an irritating restriction, it's also because it looks just the sort of thing that will bite, and bite badly, when people start implementing non-trivial systems where multiple GCs are operating. I've already had far too much of this sort of thing. Tracking down the causes of unreproducible coredumps caused by mysterious interactions between the scheduler, the garbage-collector, and external programs, is not exactly the sort of thing I enjoy doing. [snip] PS. I'm sorry to keep banging on about this. Ultimately it doesn't really matter to me that much, since I only really use mallocForeignPtr. I guess I was just intrigued to see if the problem was really as difficult as we'd thought. [snip] I'm glad you are banging on about it. But since it looks unlikely that there is going to be agreement on the matter, I suggest the following compromise. We remove the restriction that finalizers may not call Haskell functions in the main body of the standard, but add a note that says that implementations may opt to impose such a restriction, provided they document it in some standard way.
George Russell <ger@tzi.de> wrote,
Simon Marlow wrote
PS. I'm sorry to keep banging on about this. Ultimately it doesn't really matter to me that much, since I only really use mallocForeignPtr. I guess I was just intrigued to see if the problem was really as difficult as we'd thought. [snip] I'm glad you are banging on about it. But since it looks unlikely that there is going to be agreement on the matter, I suggest the following compromise. We remove the restriction that finalizers may not call Haskell functions in the main body of the standard, but add a note that says that implementations may opt to impose such a restriction, provided they document it in some standard way.
That's as good as not defining it at all. And given that the type signatures of the two versions are different, it isn't even a matter of imposing a runtime restriction. Cheers, Manuel
Manuel M T Chakravarty wrote:
George Russell <ger@tzi.de> wrote,
Simon Marlow wrote
PS. I'm sorry to keep banging on about this. Ultimately it doesn't really matter to me that much, since I only really use mallocForeignPtr. I guess I was just intrigued to see if the problem was really as difficult as we'd thought. [snip] I'm glad you are banging on about it. But since it looks unlikely that there is going to be agreement on the matter, I suggest the following compromise. We remove the restriction that finalizers may not call Haskell functions in the main body of the standard, but add a note that says that implementations may opt to impose such a restriction, provided they document it in some standard way.
That's as good as not defining it at all.
I agree that it's extremely unsatisfactory, but it seems the best option (to me) of defining it is not going to be accepted. So at least it would be better if GHC's documentation said "We implement the FFI" while Hugs and NHC's said "We implement the FFI with the caveat that finalizers may not call back into Haskell, as specified in section [blah]". Since I regard this caveat as an extremely important one (for example, it severely limits the use of the FFI to link to languages like Java, which also have their own GC) it needs to be stated very clearly in the documentation of those implementations which have it, rather than being left as an embarassing hole which the user will only discover after a long and painful analysis of the core-dumps.
And given that the type signatures of the two versions are different, it isn't even a matter of imposing a runtime restriction. No, that's not true. I'm happy with the existing signature (addForeignFinalizer specifying a pointer to an external function) since that will often be just what you want. I'm just unhappy with the restriction that the roof may fall in if by any means whatever a Haskell function is called from the outside world during the duration of that foreign function.
I agree that it's extremely unsatisfactory, but it seems the best option (to me) of defining it is not going to be accepted. So at least it would be better if GHC's documentation said "We implement the FFI" while Hugs and NHC's said "We implement the FFI with the caveat that finalizers may not call back into Haskell, as specified in section [blah]".
I maintain that it is better to specify something simple and for GHC to document that it goes beyond the specification just as it does for unboxed types and the like. What's the point in going to all the effort of coming up with a common specification, all of us hacking our implementations to match the spec, endless arguing over details of the syntax, types, libraries, etc. if it doesn't achieve the goal of improving portability? It would have been much easier if we'd left our (incompatible) implementations alone and not made an effort at defining a portable ffi spec.
Since I regard this caveat as an extremely important one (for example, it severely limits the use of the FFI to link to languages like Java, which also have their own GC)
I just want to note that I believe what you really need is a bunch of entrypoints into the runtime system not the ability to call Haskell code.
it needs to be stated very clearly in the documentation of those implementations which have it, rather than being left as an embarassing hole which the user will only discover after a long and painful analysis of the core-dumps.
Note that the problem is _exactly_ the same problem faced when using foreign functions which were declared using the 'unsafe' calling convention. The only difference I can see is that unsafe calls are much more common so they are more of a problem. As I was implementing the unsafe stuff in Hugs, it occurred to me that I could probably dynamically detect when an unsafe function (i.e., one which the user promises is not reentrant) performs a reentrant call. The idea is that on making an unsafe call, we set a bit saying that reentrancy is not allowed and on calling into a foreign exported function or performGC we check whether the bit is set. Making this work in a multithreaded setting like GHC would be more painful and more expensive but probably feasible. -- Alastair Reid alastair@reid-consulting-uk.ltd.uk Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/
Alastair Reid wrote: [snip]
I maintain that it is better to specify something simple and for GHC to document that it goes beyond the specification just as it does for unboxed types and the like. I don't believe it's at all simple to specify that Haskell-land may not be invoked at any time during the duration of some C function. I'm not even sure I know what "duration" means, in the presence of concurrency.
What's the point in going to all the effort of coming up with a common specification, all of us hacking our implementations to match the spec, endless arguing over details of the syntax, types, libraries, etc. if it doesn't achieve the goal of improving portability? It would have been much easier if we'd left our (incompatible) implementations alone and not made an effort at defining a portable ffi spec. People who only call C in a fairly simple way can still port their FFI code between Hugs, GHC and NHC. We all know that the current mechanism is a huge improvement on the old non-portable ones. However anyone who goes beyond this needs to be aware of elephant traps, and we should not expect them to read the specification in detail to do so.
Since I regard this caveat as an extremely important one (for example, it severely limits the use of the FFI to link to languages like Java, which also have their own GC)
I just want to note that I believe what you really need is a bunch of entrypoints into the runtime system not the ability to call Haskell code. You also need entrypoints into (say) the Java runtime system, if you are going to interact with Java. Otherwise how are you going to tell Java that one of your Haskell-provided callbacks must be delayed until Hugs has finished its garbage-collection? Or are you proposing that anyone linking Hugs with Java must implement a lock (in Java) which blocks every single callback to Hugs during Hugs GC's?
it needs to be stated very clearly in the documentation of those implementations which have it, rather than being left as an embarassing hole which the user will only discover after a long and painful analysis of the core-dumps.
Note that the problem is _exactly_ the same problem faced when using foreign functions which were declared using the 'unsafe' calling convention. The only difference I can see is that unsafe calls are much more common so they are more of a problem.
The difference is that the "unsafe" calling convention uses the word "unsafe". People who use features which are labelled "unsafe" may be assumed to be aware of the elephant traps in the specification. If they aren't it's their own fault. The reason most calls at the moment are unsafe is because the FFI has mostly been used to link directly to C code in a fairly single-threaded way. I'm not sure even this is a good idea, since we can't go on assuming a single native thread for much longer. [snip]
participants (3)
-
Alastair Reid -
George Russell -
Manuel M T Chakravarty