"Sigbjorn Finne (Intl Vendor)" <[EMAIL PROTECTED]> wrote,
> To clarify a little - while the arguments to a
> 'foreign import' should at least live for the
> duration of an invocation of a (safe) foreign
> import, there's no guarantee that heap references
> you pass out won't move. Hence, the scheme outlined
> in the code of the original message isn't really going
> to work with or without this extra constraint. [This is
> one good reason why I'm considering restricting the use
> of (Mutable)ByteArrays to unsafe foreign imports only.]
>
> So, why bother with this extra constraint on argument
> lifetimes, if it won't be of any use here? Well, it is
> very useful when working with ForeignObjs.
I completely agree. Why not drop passing
(Mutable)ByteArrays to foreign functions altogether - if a
program wants to pass Haskell data to C land, the Right
Thing is to use a StablePtr. Now there maybe efficiency
considerations when using this for marshaling purposes, but
I think, what we really want here is a kind of Haskell
variant of `alloca'.
We want get a chunk of memory to which we can hand pointers
over to C land - without having to worry whether the memory
area potentially moves during a safe call. Furthermore, we
want the lifetime of this block to be dependent on the live
time of a function activation. The later is problematic due
to tail calls. Actually, when the foreign call is a tail
call, the memory area should live until we return from C
land (in the current activation - not via a callback or so),
but if the foreign call is no tail call, we want the memory
area atually to live longer, as we may use it for out or
inout parameter (like in C, where alloca memory lives as
long as the function, in which it was allocated).
I guess, everybody agrees that it won't be a good idea to
put the burden of this lifetime decision on the compiler.
So what remains are alloc/dealloc brackets for this kind of
memory areas. And to make the implementation easier and
because it doesn't really restrict the intended use, we
should really enforce a stack discipline and use a wrapper
function:
alloca :: Int -> (Addr -> IO a) -> IO a
The example that Sven posted, would then look as follows:
foo = alloca N $ \mem -> do
writeWord32OffAddr mem 0 ...
...
bar mem
<optionally take stuff out of `mem' again>
foreign import ... bar :: Addr ... -> IO ()
This should have a reasonable simple and efficient
implementation and, I think, is exactly what we need for
marshaling.
Maybe I should add that I actually don't like any special
rules for handling (Mutable)ByteArrays in unsafe calls, as
this would mean that marshaling depends on the safety of a
foreign call - which smells kludgey.
Sven, Wish List, Wish List! :-)
Cheers,
Manuel
PS: Sven, the core dumps in `isAlive' that I saw earlier are
not by any chance caused by (Mutable)ByteArrays that
moved during a callback?