Pass haskell GC allocated data to C by pointer

Viewed 259

After reading several wiki's and stackoverflow QA i'm left with the question how to pass mark/pass regions of memory allocated by the GC to the C library. Most of the libraries handling FFI seem to allocate memory first, copy the value into it and wrap it in a Ptr type. The problem is to get a guarantee that the memory won't be moved or deallocated while spending time in the C library.

Suppose i have a value myInput that is of type Text and i want to do zero-copy FFI with C. What are my options?

So far i've found the following:

https://wiki.haskell.org/Foreign_Function_Interface#Pointers_to_Haskell_data

In some cases, you may want to give to the foreign code an opaque reference to a Haskell value that you will retrieve later on. You need to be sure that the value is not collected between the time you give it and the time you retrieve it. Stable pointers have been created exactly to do this. You can wrap a value into a StablePtr and give it to the foreign code (StablePtr is one of the marshallable foreign types).

After talking to some people. They tell me that the StablePtr is not supposed to be dereferenced. And is mainly used for passing void* around. On the other hand the wiki says it's suitable for this purpose and also this answer indicates the same https://stackoverflow.com/a/10900699/1833322

More information on StablePtr:

https://www.well-typed.com/blog/2018/05/ghc-special-gc-objects/

after every GC stable pointers are updated to point to new locations of the Haskell objects that they were pointing to before the GC

https://hackage.haskell.org/package/base-4.11.1.0/docs/Foreign-StablePtr.html#t:StablePtr

A stable pointer is a reference to a Haskell expression that is guaranteed not to be affected by garbage collection, i.e., it will neither be deallocated nor will the value of the stable pointer itself change during garbage collection (ordinary references may be relocated during garbage collection). Consequently, stable pointers can be passed to foreign code, which can treat it as an opaque reference to a Haskell value.

I thought i could just wrap my Text with newStablePtr http://hackage.haskell.org/package/base-4.12.0.0/docs/Foreign-StablePtr.html#v:newStablePtr and be done with it. I don't understand what is now the situation with StablePtr. If i can use it for this purpose or not. And if not what is it actually used for.

Then there is pinned memory https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/GC/Pinned with ByteString

There are also pinned ByteArray http://hackage.haskell.org/package/primitive-0.6.2.0/docs/Data-Primitive-ByteArray.html#g:2

Just the thing with ByteString and ByteArray is that often IO libraries provide their own data structures and data would have to be copied first INTO ByteString/ByteArray which is what i'm trying to avoid in the first place.

Maybe there are some (unsafe ?) casting functions?

It seems to be a simple problem since the GC already seems to be able to mark portions of the memory to "don't move" (pinning). Is there a function i can call on a structure to toggle this flag? Or are there any other suitable functions for this use case?

0 Answers
Related