(This is something I did in December but have only just gotten round to posting about)

The OCaml Unix module provides many of the system calls needed for day-to-day work, but occasionally there is one that is only available in C. In a recent project, I needed to find a PID from a semaphore ID when parsing the output of:

$ ipcs -s ------ Semaphore Arrays -------- key semid owner perms nsems 0xd69fd280 1638401 oracle 660 504 <snip>

To interface a C library with an OCaml program there are three elements:

The interface file which maps between C and OCaml function names

which maps between C and OCaml function names The stub file which wraps C functions in OCaml datatypes

which wraps C functions in OCaml datatypes The actual OCaml program itself that does the work

Here I will show a stripped down example of doing this for semctl() . First the interface file semctl.mli :

external semctl: int -> int = "caml_semctl"

This is very simple, as in this example we are only using the one function. It takes an int as an argument and returns another int . Next the stub file semctl_stub.c :

#include <sys/sem.h> #include <caml/mlvalues.h> #include <caml/memory.h> #include <caml/alloc.h> #include <caml/custom.h> value caml_semctl(value semid) { CAMLparam1(semid); CAMLreturn(Val_int(semctl(Int_val(semid), 0, GETPID))); }

Notice the name from the interface file is prefixed caml_ to avoid clashing with the actual C function, because I still want to call it by its C name in the main OCaml program. The parameter is cast from OCaml→C type and the return value cast back again (all on the stack). Finally the main OCaml program semctl_getpid.ml :

open Semctl open Unix open Printf let () = match (Array.length Sys.argv) with | 2 -> print_endline (sprintf "%d

" (semctl (int_of_string Sys.argv.(1)))) | _ -> prerr_endline (sprintf "Usage: %s <semid> " Sys.argv.(0))

To compile and link these three components:

$ ocamlc -c semctl.mli $ ocamlc -c semctl_stub.c $ ocamlc -custom -o semctl_getpid unix.cma semctl_getpid.ml semctl_stub.o

Then running it:

$ ./semctl_getpid 1638401 9022 $ ps -e|grep 9022 9022 ? 00:00:03 sp_cop

Exactly as expected, one of the components of Shareplex. Anyway, knowing this technique moves me a little closer to my eventual goal of maintaining my own native Oracle bindings.