[ocaml-ctypes] Finalising data
Florian Pichlmeier
florian.pichlmeier at mytum.de
Mon May 19 15:20:25 BST 2014
Dear Jeremy,
thanks a lot for your comprehensive response.
I will change my api to include explicit destroy
functions for messages.
But now i have encountered a new problem.
Zeromq uses incomplete types for many data types,
like the frame type
typedef struct _zframe_t zframe_t;
On the OCaml side i use void pointer to represent
these data types, and thats where the problem arose.
The frame destroy function call for example is that
zframe_destroy (zframe_t **self_p);
with the corresponding ocaml function
let destroy (msg : t) =
let stub = foreign "zframe_destroy" (ptr void @-> returning int) in
stub (msg +@ 0)
The problem is the msg +@ 0 part.
Do you know a way around this problem?
Thanks again for your efforts,
Florian
Jeremy Yallop <yallop at gmail.com> wrote:
> Dear Florian,
>
> On 30/04/2014, Florian Pichlmeier <florian.pichlmeier at mytum.de> wrote:
>
> > i have this create function
> >
> > type t = unit ptr
> > let zframe : t typ = ptr void
> > let zframe_opt : t option typ = ptr_opt void
> >
> > let create msg =
> > let stub = foreign "zframe_new"
> > (string @-> size_t @-> returning zframe_opt)
> > in
> > let msg_size = Size_t.of_int (String.length msg) in
> > match stub msg msg_size with
> > | None -> raise Frame_creation
> > | Some x -> x
> >
> > How can i tell the garbage collector to call my specific
> > destroy function?
> >
> >
>
> You can attach a finaliser, either to the zframe value itself, or to
> another object which has the same lifetime as the zframe. The
> drawback of attaching the finaliser directly to the zframe is that a
> number of ctypes functions (e.g. the functions for pointer arithmetic)
> create new ptr values, so you may end up destroying the object while
> you still have a pointer to it. For example:
>
> let zf = create msg in
> let () = Gc.finalise destroy_zframe zf in
> (zf +@ 0)
> (* At this point you still have a pointer to the zframe you
> created, but the original Ctypes.ptr value has gone, so the
> GC is free to run the finaliser attached to it. *)
>
> If you're already wrapping the zframe in a larger OCaml value, such as
> a record, it would probably be wiser to attach the finaliser to that
> value instead, since you can see more easily in your own code exactly
> when copies are made. If you want even stronger guarantees, you
> should make sure that the type you use to wrap the zframe has a
> mutable field, since the runtime is free to make copies of immutable
> values.
>
> It may be more advisable to consider an alternative interface that
> makes the lifetime of your zframes deterministic and explicit. One
> simple approach is to follow the design of the channel interfaces in
> the standard library, and expose a pair of functions
>
> val create : string -> t
> val destroy : t -> unit
>
> then leave it up to the user to ensure that destroy_zframe is closed
> at an appropriate moment (but perhaps catching other errors, such as
> double closes).
>
> An alternative approach is to follow the design often used in Scheme,
> and expose a single higher-order function that manages the lifetime of
> the frame. For example, if you have a function with the following
> interface
>
> val with_zframe : string -> (t -> 'a) -> 'a
>
> then you might call it as follows
>
> with_zframe msg
> (fun zframe ->
> (* body: the zframe value is "live" here *)
> )
>
> and the user can be confident that -- whether the body finishes
> normally or with an exception -- with_zframe will destroy the value in
> a timely way. This approach is used in the Batteries library to
> manage files: see with_file_in and with_file_out, for example:
>
> http://ocaml-batteries-team.github.io/batteries-included/hdoc2/BatFile.html#VALwith_file_in
> http://ocaml-batteries-team.github.io/batteries-included/hdoc2/BatFile.html#VALwith_file_out
>
> I hope that helps,
>
> Jeremy.
>
>
>
More information about the Ctypes
mailing list