How do I pass a parameter to a finaliser? The pointer itself does not have enough information to run the finaliser, I need an extra parameter available at the time the pointer is created. This was easy to do when I could write finalisers in Haskell, of course, since I could just apply the parameter to my finaliser function to get a finaliser that had the correct type. This is what it looked like: foreign import ccall "JVMBridge.h JVMBridge_DeleteGlobalRefGC" rawDeleteGlobalRefGC :: JavaVM -> RawGlobalRef -> IO (); vm <- rawGetJavaVM ?jvmenv; gref <- newForeignPtr rgref (rawDeleteGlobalRefGC vm (MkRawGlobalRef rgref)); return (MkVMRef gref); But with the new FFI I can't do this so easily. How would I pass the 'vm' parameter to a finaliser which is only allowed to look at the 'rgref' pointer? -- Ashley Yakeley, Seattle WA
Hi Ashley, You can use the newForeignPtr the is exported from the Concurrent module (in ghc 6.0), this function has the same signature as the old haskell function. When switching to ghc 6.0 I changed: import Foreign.ForeignPtr to: import Foreign.ForeignPtr hiding (newForeignPtr,addForeignPtrFinalizer) import Foreign.Concurrent And everything kept working fine :-) Hope this helps, (allthough it doesn't answer the question of why these things have changed or how to add parameters to the new newForeignPtr function,) -- Daan
-----Original Message----- From: ffi-admin@haskell.org [mailto:ffi-admin@haskell.org] On Behalf Of Ashley Yakeley Sent: zondag 13 juli 2003 10:15 To: Ffi@haskell.org Subject: More Finaliser Trouble
How do I pass a parameter to a finaliser? The pointer itself does not have enough information to run the finaliser, I need an extra parameter available at the time the pointer is created.
This was easy to do when I could write finalisers in Haskell, of course, since I could just apply the parameter to my finaliser function to get a finaliser that had the correct type. This is what it looked like:
foreign import ccall "JVMBridge.h JVMBridge_DeleteGlobalRefGC" rawDeleteGlobalRefGC :: JavaVM -> RawGlobalRef -> IO ();
vm <- rawGetJavaVM ?jvmenv; gref <- newForeignPtr rgref (rawDeleteGlobalRefGC vm (MkRawGlobalRef rgref)); return (MkVMRef gref);
But with the new FFI I can't do this so easily. How would I pass the 'vm' parameter to a finaliser which is only allowed to look at the 'rgref' pointer?
-- Ashley Yakeley, Seattle WA
_______________________________________________ FFI mailing list FFI@haskell.org http://www.haskell.org/mailman/listinfo/ffi
[...] doesn't answer the question of why these things have changed [...]
We dropped Haskell finalizers because neither Hugs nor NHC could implement them and implementing them would pretty much require them to implement preemptive concurrency (i.e., multiple threads each with their own stacks). These issues were considered important because one goal of the ffi spec was to improve portability between implementations and also because we explicitly decided not to do anything that requires concurrency or other H98 extensions. -- Alastair Reid
Dnia nie 13. lipca 2003 21:20, Alastair Reid napisał:
We dropped Haskell finalizers because neither Hugs nor NHC could implement them and implementing them would pretty much require them to implement preemptive concurrency (i.e., multiple threads each with their own stacks).
Not necessarily preemptive. Hugs-like concurrency would be OK. The point is to be able to protect mutable structures by mutexes. -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/
Dnia nie 13. lipca 2003 21:20, Alastair Reid napisał:
We dropped Haskell finalizers because neither Hugs nor NHC could implement them and implementing them would pretty much require them to implement preemptive concurrency (i.e., multiple threads each with their own stacks).
On Sunday 13 July 2003 11:03 pm, Marcin 'Qrczak' Kowalczyk wrote:
Not necessarily preemptive. Hugs-like concurrency would be OK.
No, Hugs-like concurrency would _not_ be ok. Hugs-like concurrency allows for context switches only when executing concurrency operators (yield, takeMVar, forkIO, ...) and, in particular, can only occur while in the IO monad which allowed us to add concurrency just by changing the way the IO monad was implemented.
The point is to be able to protect mutable structures by mutexes.
In particular, it is the 'thunks' used by the runtime to represent unevaluated Haskell expressions which are mutable and which have to be protected by mutexes. (In GHC, these mutexes are called 'blocking queues'. Since Hugs has only non-preemptive concurrency, it provides a degenerate form of blocking queue called a 'blackhole' which reports that your program has entered a blackhole if you try to enter a locked mutex.) Since the code that evaluates the thunks can be of any type and is not restricted to the IO monad, the way concurrency is implemented in Hugs cannot be used. Instead, we would have to change the way _every_ evaluation happens in Hugs so that we are able to block the current thread if the mutex is taken. For example, we could evaluate each Haskell thread in a separate OS thread, we could evaluate each Haskell thread is a separate user-level thread (as GHC does) or we could use some form of continuation passing implementation (as SML-NJ does). I claim that either of these 'would pretty much require [Haskell implementations] to implement preemptive concurrency'. -- Alastair Reid
Daan Leijen <daanleijen@xs4all.nl> wrote:
(allthough it doesn't answer the question of [...] how to add parameters to the new newForeignPtr function,)
Should there perhaps be something like ... newForeignPtrWithUserData :: Ptr a -> Ptr b -> FunPtr (Ptr a -> Ptr b -> IO ()) -> IO (ForeignPtr a) ... where the second argument is a "userData" pointer that gets passed on to the finalizer? That would correspond to the usual solution used by C programmers. Cheers, Wolfgang
On 13-Jul-2003, Wolfgang Thaller <wolfgang.thaller@gmx.net> wrote:
Daan Leijen <daanleijen@xs4all.nl> wrote:
(allthough it doesn't answer the question of [...] how to add parameters to the new newForeignPtr function,)
Should there perhaps be something like ...
newForeignPtrWithUserData :: Ptr a -> Ptr b -> FunPtr (Ptr a -> Ptr b -> IO ()) -> IO (ForeignPtr a)
... where the second argument is a "userData" pointer that gets passed on to the finalizer?
IMHO yes! -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
In article <20030714071832.GA3813@ceres.cs.mu.oz.au>, Fergus Henderson <fjh@cs.mu.OZ.AU> wrote:
Should there perhaps be something like ...
newForeignPtrWithUserData :: Ptr a -> Ptr b -> FunPtr (Ptr a -> Ptr b -> IO ()) -> IO (ForeignPtr a)
... where the second argument is a "userData" pointer that gets passed on to the finalizer?
IMHO yes!
Well now what if you want to pass two extra pointers? It's true you could "glue" them together, but equally, you can glue together the two pointers passed to newForeignPtrWithUserData. Bear in mind that your newForeignPtrWithUserData, "Ptr a" and "Ptr b" are effectively interchangeable. You have one object, a ForeignPtr, that holds two pointers. When the ForeignPtr gets finalised, it passes both pointers to its finaliser function (assuming it has exactly one). There really isn't a lot of difference between the two of them when there's only one finaliser. -- Ashley Yakeley, Seattle WA
Ashley Yakeley <ashley@semantic.org> wrote:
In article <20030714071832.GA3813@ceres.cs.mu.oz.au>, Fergus Henderson <fjh@cs.mu.OZ.AU> wrote:
Should there perhaps be something like ...
newForeignPtrWithUserData :: Ptr a -> Ptr b -> FunPtr (Ptr a -> Ptr b -> IO > ()) -> IO (ForeignPtr a) ... where the second argument is a "userData" pointer that gets passed on > to the finalizer?
IMHO yes!
Well now what if you want to pass two extra pointers? It's true you could "glue" them together [...]
Of course. That's what I have to do with all userData pointers I use in C, so if I use C finalizers, I'll put up with that...
[...] but equally, you can glue together the two pointers passed to newForeignPtrWithUserData.
Bear in mind that your newForeignPtrWithUserData, "Ptr a" and "Ptr b" are effectively interchangeable. You have one object, a ForeignPtr, that holds two pointers. When the ForeignPtr gets finalised, it passes both pointers to its finaliser function (assuming it has exactly one). There really isn't a lot of difference between the two of them when there's only one finaliser.
I wouldn't say that there's no difference: The type of the ForeignPtr depends on the type of the first pointer only. You can get the first pointer from the ForeignPtr without having to know anything about the finalizer. When you create pointers using different methods (e.g. standard C malloc, pointers to static storage, a Java VM's storage manager, etc.), you will need different finalizers, and some finalizers require extra data to operate. However the resulting ForeignPtrs should all have the same type, as they are pointers to the same kind of data. Cheers, Wolfgang
In article <ead7eb4e64962db8325e9305379508b3@localhost.localdomain>, Wolfgang Thaller <wolfgang.thaller@gmx.net> wrote:
Well now what if you want to pass two extra pointers? It's true you could "glue" them together [...]
Of course. That's what I have to do with all userData pointers I use in C, so if I use C finalizers, I'll put up with that...
The problem is that if you glue them together in Haskell using some tuple type, the native-code finaliser can't un-glue them without calling back into Haskell, which isn't in general allowed. So instead you have to call into native code to do the glue there. For instance, my Java VM reference finaliser needs the reference to finalise and also a "JVM-pointer". So when I'm constucting these things in Haskell, I need to take the JVM pointer and the reference, and call some C function that allocates a little structure of the two and returns a pointer to it. Then I can make a ForeignPtr with that. -- Ashley Yakeley, Seattle WA
participants (6)
-
Alastair Reid -
Ashley Yakeley -
Daan Leijen -
Fergus Henderson -
Marcin 'Qrczak' Kowalczyk -
Wolfgang Thaller