I want to use ForeignObj for large transient data,
but Hugs ForeignObj implementation is quite mysterious...
Three ForeignObj interfaces are described as such in exts/Foreign.hs.
primitive makeForeignObj :: Addr{-x-} -> Addr{-free-} -> IO ForeignObj
primitive writeForeignObj :: ForeignObj -> Addr -> IO ()
primitive eqForeignObj :: ForeignObj -> ForeignObj -> Bool
The latter argument of makeForeignObj is a mystery.
1.
I thought it is a pointer of function
(with type of [void (*)(void *);] ?).
foreign import "foo" "newFO" newFO :: IO Addr
foreign import "foo" "delFO" delFO :: Addr -> IO ()
primitive unsafeCoerce "primUnsafeCoerce" :: a -> b
newFO >>= (\fo ->
makeForeignObj fo (unsafeCoerce delFO))
This code causes an unexpected signal (probably the implementation of
Addr -> IO () is different from C form).
2.
`foreign label' is valid?
foreign import "foo" "newFO" newFO :: IO Addr
foreign label "foo" "delFO" delFO :: Addr
newFO >>= (\fo ->
makeForeignObj fo delFO)
No, it isn't.
3.
Then I try to get the pointer of delFO directly
(Fortunately lcc-win32 3.1 allows internal global variables viewable,
however, I suppose other C compilers do not...).
foreign import "foo" "newFO" newFO :: IO Addr
foreign import "foo" "delFO" delFO :: Addr -> IO ()
foreign import "foo" "getDelFO" getDelFO :: IO Addr
getDelFO >>= (\del ->
newFO >>= (\fo ->
makeForeignObj fo del))
It works as expected.
But I think such description is not appropriate!
Variables in DLL are not always viewable by another program.
How I should use ForeignObj finalizer in Hugs?
-- KAKIHARA Norihiro
[The following code was workable in my environment...]
********** main.c **********
#include
"KAKIHARA" == KAKIHARA Norihiro
writes:
I want to use ForeignObj for large transient data, but Hugs ForeignObj implementation is quite mysterious...
I wonder if you're being confused by the corresponding feature in GHC (also called ForeignObj) which goes a long way beyond what Hugs provides (and is a good deal harder to implement)?
primitive makeForeignObj :: Addr{-x-} -> Addr{-free-} -> IO The latter argument of makeForeignObj is a mystery.
1. I thought it is a pointer of function (with type of [void (*)(void *);] ?).
That's what it is.
foreign import "foo" "newFO" newFO :: IO Addr foreign import "foo" "delFO" delFO :: Addr -> IO ()
newFO >>= (\fo -> makeForeignObj fo (unsafeCoerce delFO))
This code causes an unexpected signal (probably the implementation of Addr -> IO () is different from C form).
You bet it will. It's meant to be a pointer to a C function but foreign import generates Haskell functions. Their calling conventions are incredibly different in Hugs: different address space, different argument passing mechanism, different representation of every data type. The clue here is that you have to use unsafeCoerce. If we meant you to pass something with Haskell type: Addr -> IO () then that would be the type. (It is almost impossible to write a correct Haskell program that uses unsafeCoerce. Anyone using it is almost certainly doing something very wrong.)
2. `foreign label' is valid?
foreign import "foo" "newFO" newFO :: IO Addr foreign label "foo" "delFO" delFO :: Addr
newFO >>= (\fo -> makeForeignObj fo delFO)
No, it isn't.
That ought to work but foreign label hasn't been tested very thoroughly. I'll try to get round to it sometime soon (but no promises).
3. Then I try to get the pointer of delFO directly (Fortunately lcc-win32 3.1 allows internal global variables viewable, however, I suppose other C compilers do not...).
foreign import "foo" "newFO" newFO :: IO Addr foreign import "foo" "delFO" delFO :: Addr -> IO () foreign import "foo" "getDelFO" getDelFO :: IO Addr
getDelFO >>= (\del -> newFO >>= (\fo -> makeForeignObj fo del))
It works as expected.
Sounds like foreign label may be broken. -- Alastair Reid reid@cs.utah.edu http://www.cs.utah.edu/~reid/
Thank you for your detailed response!
I wonder if you're being confused by the corresponding feature in GHC (also called ForeignObj) which goes a long way beyond what Hugs provides (and is a good deal harder to implement)?
Certainly I refered to the ForeignObj section in GHC manual. However, I suppose Hugs current implementation is natural, and practical.
(It is almost impossible to write a correct Haskell program that uses unsafeCoerce. Anyone using it is almost certainly doing something very wrong.)
I see. I will avoid using unsafeCoerce.
That ought to work but foreign label hasn't been tested very thoroughly. I'll try to get round to it sometime soon (but no promises).
I appreciate your intention!
Sounds like foreign label may be broken.
Looking at the file generated by Hugs Green Card, I can find a table of external functions. They are not explicitly exported but correctly working. Though they are declared as external, they are internal for loaders of DLL. My previous words may be the confusion of interprocess communication problem and inconsistent in that point. So I think getDelFO is quite legal.
KAKIHARA Norihiro
That ought to work but foreign label hasn't been tested very thoroughly. I'll try to get round to it sometime soon (but no promises).
I appreciate your intention!
Hi, this turned out to be a bug in the Hugs internals & not how 'foreign label' was implemented per se. A fix has been checked into the CVS repository, so the anonymous CVS should mirror it sometime within the next 24 hours. Many thanks for reporting the problem. --sigbjorn
Hi,
this turned out to be a bug in the Hugs internals & not how 'foreign label' was implemented per se. A fix has been checked into the CVS repository, so the anonymous CVS should mirror it sometime within the next 24 hours.
Many thanks for reporting the problem.
--sigbjorn
I've tried the latest CVS version and make sure! Thanks! But I found that my runhugs seemed to ignore finalizer... ------------------------------- extern void *newObj(void) { void *obj; obj = malloc(1); printf("obj is born.\n"); return obj; } extern void delObj(MyInt obj) { printf("obj dies.\n"); free(obj); } module Main(main) where import Foreign foreign label "ForeignObj" "delObj" delObj :: Addr foreign import "ForeignObj" "newObj" newObj :: IO Addr main = newObj >>= (\obj -> makeForeignObj obj delObj >> putStr "obj is alive.") ------------------------------- Hugs prints: obj is born. obj is alive. obj dies. runhugs prints: obj is born. obj is alive. How does yours work?
"KAKIHARA Norihiro"
...
But I found that my runhugs seemed to ignore finalizer...
-------------------------------
....example code elided...
-------------------------------
Hugs prints: obj is born. obj is alive. obj dies.
runhugs prints: obj is born. obj is alive.
How does yours work?
Hi, you've found another bug / lack of a feature. The runhugs wrapper to the Hugs98 evaluator doesn't clean up after itself when finished & performs a final GC, so stuff like ForeignObjs just die without being finalized. I've checked in a change that forces a final GC, which should eliminate the difference in behaviour you're seeing between 'hugs' and 'runhugs'. Thanks for reporting the problem. --sigbjorn If anyone feels that requiring a GC to be run at the end will be too much of a hit perf-wise, let me know & I'll provide an option for turning this bit on/off.
participants (3)
-
Alastair David Reid -
KAKIHARA Norihiro -
Sigbjorn Finne