<div dir="ltr">Thank you, Jeremy.  This is exactly what I needed.<div><br></div><div>Thank you as well for Ctypes, from my brief use so far it seems great.</div><div><br></div><div>Travis</div></div><div class="gmail_extra">
<br><br><div class="gmail_quote">On Tue, Dec 17, 2013 at 5:33 PM, Jeremy Yallop <span dir="ltr"><<a href="mailto:yallop@gmail.com" target="_blank">yallop@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On 17 December 2013 04:46, Travis Brady <<a href="mailto:travis.brady@gmail.com">travis.brady@gmail.com</a>> wrote:<br>
> I'm wrapping a simple library that contains a few functions that call malloc<br>
> or realloc internally to allocate a few struct members and I'm wondering how<br>
> to make those behave with Ctypes and the GC.<br>
><br>
> The library exposes structname_free functions where applicable, but I'm not<br>
> certain how to tell Ctypes how to use them or if I even need to at all.<br>
<br>
</div>There are several possible approaches to consider.  One approach is to<br>
simply write C-style code in OCaml, binding the structname_free<br>
functions and explicitly calling them when you know that it's safe to<br>
do so.  This will probably work best if the lifetime of the struct is<br>
easy to predict -- for example, if it's associated with a file<br>
descriptor or other resource that also needs to be explicitly<br>
released.<br>
<br>
Another approach is to register the destructor functions with the GC<br>
so that they're called automatically when ctypes no longer has a<br>
reference to the memory.  This approach should work well where you're<br>
allocating the memory from ctypes, since the hooks for registering<br>
destructor functions are currently associated with the ctypes<br>
allocation functions such as make<br>
(<a href="http://ocamllabs.github.io/ocaml-ctypes/Ctypes.html#VALmake" target="_blank">http://ocamllabs.github.io/ocaml-ctypes/Ctypes.html#VALmake</a>).<br>
<br>
Here's a simple example with a struct whose fields point to memory<br>
dynamically allocated by C code.  The unmanaged_person function shows<br>
the C-style approach, with explicit deallocation; the managed_person<br>
function shows the GC-based approach, using the finaliser argument to<br>
the make function to register the destructor:<br>
<br>
   $ cat example_stubs.c<br>
   #include <stdlib.h><br>
   #include <string.h><br>
   #include <stdio.h><br>
<br>
   struct person { char *name; int age; };<br>
<br>
   void initialize_person(struct person *p, const char *name, int age)<br>
   {<br>
     p->name = malloc(strlen(name) + 1);<br>
     strcpy(p->name, name);<br>
     p->age = age;<br>
   }<br>
<br>
   void destroy_person(struct person *p)<br>
   {<br>
     printf("goodbye %s (age %d)\n", p->name, p->age);<br>
     free(p->name);<br>
   }<br>
   $ cat <a href="http://example.ml" target="_blank">example.ml</a><br>
   open Ctypes<br>
   open Foreign<br>
<br>
   type person<br>
   let person : person structure typ = structure "person"<br>
   let name = field person "name" string<br>
   let age = field person "age" int<br>
   let () = seal person<br>
<br>
   let initialize_person = foreign "initialize_person"<br>
     (ptr person @-> string @-> int @-> returning void)<br>
<br>
   let destroy_person = foreign "destroy_person"<br>
     (ptr person @-> returning void)<br>
<br>
   (* Allocate a `person' value, registering the destructor function<br>
with the GC *)<br>
   let managed_person ~name ~age =<br>
     let p = make ~finalise:(fun p -> destroy_person (addr p)) person in<br>
     initialize_person (addr p) name age;<br>
     p<br>
<br>
   (* Allocate a `person' value that must be explicitly deallocated *)<br>
   let unmanaged_person ~name ~age =<br>
     let p = make person in<br>
     initialize_person (addr p) name age;<br>
     p<br>
   $ ocamlfind ocamlc -c -package ctypes example_stubs.c <a href="http://example.ml" target="_blank">example.ml</a><br>
   $ ocamlmklib -o example example_stubs.o example.cmo<br>
   $ ocaml<br>
           OCaml version 4.01.0<br>
<br>
   # #use "topfind";;<br>
   [...]<br>
   # #require "ctypes.foreign";;<br>
   [...]<br>
   # #load "example.cma";;<br>
   # open Example;;<br>
   # let mcc = unmanaged_person "Mrs McCave" 40;;<br>
   val mcc : (Example.person, [ `Struct ]) Ctypes.structured = <abstr><br>
   # let () = for i = 1 to 23 do ignore (managed_person ~name:"Dave"<br>
~age:i) done;;<br>
   # Gc.full_major ();;<br>
   goodbye Dave (age 23)<br>
   goodbye Dave (age 22)<br>
   goodbye Dave (age 21)<br>
   goodbye Dave (age 20)<br>
   goodbye Dave (age 19)<br>
   goodbye Dave (age 18)<br>
   goodbye Dave (age 17)<br>
   goodbye Dave (age 16)<br>
   goodbye Dave (age 15)<br>
   goodbye Dave (age 14)<br>
   goodbye Dave (age 13)<br>
   goodbye Dave (age 12)<br>
   goodbye Dave (age 11)<br>
   goodbye Dave (age 10)<br>
   goodbye Dave (age 9)<br>
   goodbye Dave (age 8)<br>
   goodbye Dave (age 7)<br>
   goodbye Dave (age 6)<br>
   goodbye Dave (age 5)<br>
   goodbye Dave (age 4)<br>
   goodbye Dave (age 3)<br>
   goodbye Dave (age 2)<br>
   goodbye Dave (age 1)<br>
   - : unit = ()<br>
   # destroy_person (Ctypes.addr mcc);;<br>
   goodbye Mrs McCave (age 40)<br>
   - : unit = ()<br>
</blockquote></div><br></div>