[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