PPP
PPP

Reputation: 1850

Is it posible to pass a C function as callback to OCaml?

I'm studying on how to integrate an OCaml TCP/IP stack into my C++ project. I already know how to call C from OCaml and call OCaml from C thanks to this answer: OCaml as C library, hello world example

The OCaml will be controlled by C++, not the other way around. So, for a TCP/IP stack, I must be able to send and receive packets. I can easily send data to the TCP/IP stack through C++, but how to receive it? I need to pass a C function (a callback) as a parameter to OCaml so it delivers the data when it arrives. Is it possible?

Upvotes: 1

Views: 328

Answers (1)

Guillaume Melquiond
Guillaume Melquiond

Reputation: 1263

You need two C functions for that. The first one (wrap_fun below) is called from C code. It takes a C callback and returns an OCaml value that you can then pass to your OCaml code. The second one (call_wrapped below) is called from the OCaml code. It takes an OCaml value created by the first function and calls the callback stored into it.

You did not specify anything about the signature of your callback, so the code below goes for value(value).

#include <caml/alloc.h>
#include <caml/memory.h>
#include <caml/mlvalues.h>

typedef value (*cb)(value);

value wrap_fun(cb f) {
  value v = caml_alloc_small(1, Abstract_tag);
  Field(v, 0) = (value)f;
  return v;
}

value call_wrapped(value f, value x) {
  CAMLparam2(f, x);
  cb g = (cb)Field(f, 0);
  value z = g(x);
  CAMLreturn(z);
}

On the OCaml side, it looks as follows:

external call_wrapped : ('a, 'b) wrapped_fun -> 'a -> 'b  = "call_wrapped"

let foo f x =
  let y = x + 1 in
  let z = call_wrapped f y in
  z ^ "a"

The CAMLparam2 and CAMLreturn macros in call_wrapped are just there for didactic purpose. They can safely be removed, since the function is just a wrapper to the actual function.

Upvotes: 5

Related Questions