Ctypes: what's the most idiomatic way to anchor an OCaml value so that it's not garbage collected?

Say I have some CArray, and I want to pass it’s start pointer to some asynchronous C function, and I want to make sure my CArray persists until async function completes?
RWO suggests the following: “achieve this via a global array of values on the OCaml side that would keep them live until they’re no longer needed”, but it lacks an example on how this can be done, probably with some Obj.magic to put various stuff into one global array? And how can one remove certain item from that array?
So far I’m using Ctypes.Root.create my_value, and save the integer value where appropriate so that I can later do Ctypes.Root.release my_saved_root, but I have suspicion that this is sort of abuse of ctypes roots, which are intended for passing OCaml values to C layer via those integer values? Yet they also exist to protect the values from premature gargabe collection, so does not sound too awful?

I found this email which describes what are Ctypes roots for: http://lists.ocaml.org/pipermail/ctypes/2015-September/000191.html

Any hints at how this problem is best solved are appreciated!

3 Likes

I agree: using roots isn’t too bad.

This is another reasonable approach, but you don’t need Obj.magic; it’s sufficient to use existential types. Here’s an illustration:

module Store :
sig
  type ticket 
  val retain : 'a -> ticket
  val is_live : ticket -> bool
  val release : ticket -> unit
end =
struct
  type ticket = int
  type element = E : _ -> element
  let counter = ref 0
  let store = Hashtbl.create 10
  let retain v =
    let ticket = !counter in
    incr counter;
    Hashtbl.add store ticket (E v);
    ticket
  let is_live = Hashtbl.mem store
  let release = Hashtbl.remove store
end

This code also shows how to remove items: generate an identifier for each saved value, and use the identifier as a key into an associative structure so that it can be used to release the value when it’s no longer in use by C.

8 Likes

Thanks @yallop! Shouldn’t Ctypes include some variation of Store module for the purpose of GC retention and promote that as recommended way to solve this for bindings that use Ctypes?