Calling Unix libraries from OCaml

(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
  • The stub file 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\n" (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.

About Gaius

Jus' a good ol' boy, never meanin' no harm
This entry was posted in Linux, Ocaml, Shareplex. Bookmark the permalink.

2 Responses to Calling Unix libraries from OCaml

  1. You should add this to the ExtUnix library: http://extunix.forge.ocamlcore.org/

Leave a comment