[ocaml-ctypes] Less copying, a hybrid approach

Daniel Bünzli daniel.buenzli at erratique.ch
Thu Dec 19 15:21:53 GMT 2013


Hello, 

In certain cases I would really like to avoid copying the data passed to C (see [1]). Main uses cases are strings and arrays and records of unboxed floats (on architectures that have ARCH_ALIGN_DOUBLE undefined, see [2]). Since I don't want to wait on the promise of stub generation I have devised the following approach.

The idea is to use ctypes to get the function pointer and pass it to a regular stub just to apply the function. What's the point will you tell me ? Why don't you immediately make a stub for the function then ? 

First I'm still using "regular" ctypes for other parts of the binding. Second, I'm also using ctypes for the dll functionality, this means that I don't need to handle that in the C part will all the configure business it would entail; I piggyback on a correct install of ctypes for handling that and for the rest of the C that is needed I just need a correct install of ocaml. 

I would like to get feedback on this approach, I think it should work on both 32 bits and 64 bits platform. To make it more easy to implement the only thing that is missing in ctypes now is `val ptr_to_raw_address : unit ptr -> int64`. In my example below I bypassed that by directly using the "ctypes_dlsym" stub.

Below I show the approach on unsetenv(3) at the end of the ml file. Note that you need only one stub per function *type*.

Any thoughts ? 

Daniel


[1] https://github.com/ocamllabs/ocaml-ctypes/issues/106
[2] http://caml.inria.fr/pub/ml-archives/caml-list/2006/01/a8a5a8a9ee7fd2b71cc74835c2f7b924.en.html

The ml file:

------test.ml---------
open Ctypes;;
open Foreign;;

type fun_ptr = int64

external app_str_int : fun_ptr -> string -> int = "mlapp_str_int" "noalloc"

external dlsym : ?handle:Dl.library -> symbol:string -> int64 option = 
  "ctypes_dlsym"

let unsetenv_fun_ptr : fun_ptr = match dlsym "unsetenv" with 
| None -> assert false 
| Some addr -> addr

let unsetenv : string -> int = fun s -> app_str_int unsetenv_fun_ptr s 

let () = 
  assert (try ignore (Sys.getenv "HOME"); true with Not_found -> false);
  assert (unsetenv "HOME" = 0); 
  assert (try ignore (Sys.getenv "HOME"); false with Not_found -> true);
  ()

-------------

The C stub:

------test_stub.c---------
#include <caml/mlvalues.h>

typedef int (*str_int)(char *);

value mlapp_str_int (value *fun_ptr, value *str)
{  
  str_int f = *(str_int)(Int64_val(fun_ptr)); 
  char *s = String_val(str);
  return Val_int(f (s));
}

------------------------------





More information about the Ctypes mailing list