Structure Callback
(* Callback -- registering ML values with C, and accessing C values from ML *)
(* Registering ML values for access from C code: *)
val register : string -> 'a -> unit
val unregister : string -> unit
val isRegistered : string -> bool
(* Accessing C variables and functions from ML: *)
type cptr
val getcptr : string -> cptr
val var : cptr -> 'b
val app1 : cptr -> 'a1 -> 'b
val app2 : cptr -> 'a1 -> 'a2 -> 'b
val app3 : cptr -> 'a1 -> 'a2 -> 'a3 -> 'b
val app4 : cptr -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'b
val app5 : cptr -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'b
(*
REGISTERING ML VALUES FOR ACCESS FROM C CODE
--------------------------------------------
This example shows how to register the ML function (fn n => 2*n) so
that it may be called from C code.
(0) The ML side registers the function:
Callback.register "myfun" (fn n => 2*n)
(1) The C side first obtains an ML value pointer:
valueptr mvp = get_valueptr("myfun");
(2) The C side then uses the ML value pointer to obtain an ML
value, and uses it:
callback(get_value(mvp), Val_long(42));
Operation (1) involves a callback to ML, and hence may be slow.
Calling get_valueptr may cause the garbage collector to run; hence
other live ML values must be registered as GC roots. The garbage
collector will never move the ML value pointer; hence it need not
be registered as a GC root in the C code.
Operation (2) is very fast. If the garbage collector is invoked
between the call of get_value() and the use of the ML value, then
the value must be registered as a GC root. However, the idiom
callback(get_value(mvp), arg1);
is safe provided the evaluation of arg1 does not provoke a garbage
collection (e.g. if arg1 is a variable).
The C function get_valueptr returns NULL if nam is not registered.
The C function get_value returns NULL if nam has been unregistered
(and not reregistered) since mvp was obtained; it raises exception
Fail if mvp itself is NULL. Every access to the ML value from C
code should use the ML valueptr and get_valueptr, otherwise the C
code will not know when the value has been unregistered and
possibly deallocated.
The C functions (in mosml/src/runtime/callback.c)
void registervalue(char* nam, value mlval)
void unregistervalue(char* nam)
can be used just as Callback.register and Callback.unregister.
The C functions
value callbackptr (valueptr mvp, value arg1)
value callbackptr2(valueptr mvp, value arg1, value arg2)
value callbackptr3(valueptr mvp, value arg1, value arg2, value arg3)
can be used for callback via an ML value pointer; they will raise
exception Fail if the ML function indicated by mvp has been unregistered.
[register nam v] registers the ML value v, so that it can be
retrieved from C code under the name nam. If nam has previously
been registered and then unregistered, it will be reregistered with
the new value. The new value immediately becomes visible to the C
side, both via get_valueptr(nam) and via any ML value pointer
previously obtained for nam. Raises exception Fail if nam has been
registered and not yet unregistered.
[unregister nam] deletes the registration. This prevents C code
from obtaining an ML value pointer for nam and from using an ML
value pointer already obtained (but does not prevent C from
attempting to use a stored ML value previously obtained with the
help of the ML value pointer, which is unsafe anyway). Does
nothing if nam is already unregistered. Raises exception Fail
if nam has never been registered.
[isRegistered nam] returns true if nam has been registered and not
yet unregistered.
ACCESSING REGISTERED C VARIABLES AND FUNCTIONS FROM ML
------------------------------------------------------
This example shows how to register the C function
value sillycfun(value v)
{ return copy_double(42.42 * Double_val(v)); }
so that it may be called from ML.
(0) The C side registers the function:
registercptr("mycfun", sillycfun);
(1) The ML side obtains a C pointer and defines an ML function
via that pointer:
val sillycfun = app1 (getcptr "mycfun") : real -> real
The type ascription is needed to ensure any type safety whatsoever.
Mistakes in the types will lead to crashes, as usual with C.
(2) To the ML side, the new ML function is indistinguishable from
other ML functions
val result = sillyfun(3.4)
The C function (in mosml/src/runtime/callback.c)
void registercptr(char* nam, void* cptr);
is used to register C pointers for access from ML. Only pointers
to static C variables, and C functions, should be registered. There
is no way to unregister a C pointer.
[cptr] is the type of pointers to C variables and C functions.
[getcptr nam] returns a pointer to the C variable or function
registered (by the C side) under the name nam. Raises exception
Fail if the name nam has not been registered.
[var cptr] returns the value of the C variable associated with cptr.
[app1 cptr arg1] applies the C function associated with cptr to arg1.
[app2 cptr arg1 arg2] applies the C function associated with cptr to
(arg1, arg2).
[app3 cptr arg1 arg2 arg3] applies the C function associated with
cptr to (arg1, arg2, arg3).
[app4 cptr arg1 arg2 arg3 arg4] applies the C function associated
with cptr to (arg1, arg2, arg3, arg4).
[app5 cptr arg1 arg2 arg3 arg4 arg5] applies the C function
associated with cptr to (arg1, arg2, arg3, arg4, arg5).
*)
Moscow ML 2.10