I'm testing the Sundials/ML library against OCaml 5.0.0. One of the examples spins forever after the following sequence:
- The GC is triggered and
caml_scan_global_young_roots locks roots_mutex.
- During the subsequent scan, one of my finalizers in C is called and it invokes
caml_remove_global_root.
- The resulting call to
caml_delete_global_root requests roots_mutex and spins until ^C.
The smallest failing example that I have been able to produce is as follows. Sorry it's not simpler.
block_ml.c:
#include <caml/alloc.h>
#include <caml/memory.h>
typedef struct cdata { value backlink; } *pcdata;
#define PCDATA(v) (*(pcdata *)Data_custom_val(v))
void mlfinalize(value val)
{
pcdata v = PCDATA (val);
caml_remove_global_root(&(v->backlink));
free(v);
}
CAMLprim value mlwrap(value payload)
{
CAMLparam1(payload);
CAMLlocal1(vcptr);
pcdata v = calloc(1, sizeof(struct cdata));
v->backlink = payload;
caml_register_global_root(&(v->backlink));
vcptr = caml_alloc_final(1, mlfinalize, 1, 30);
PCDATA(vcptr) = v;
CAMLreturn(vcptr);
}
block.ml:
type ptr
type 'data t = { payload: 'data; cptr: ptr }
external c_wrap : 'a -> ptr = "mlwrap"
let make v = { payload = v; cptr = c_wrap v }
type gdata = ..
type gdata += RA of int
type gdata += VV of gdata t
let rec make_ra v = make (RA v)
and make_vv v = make (VV v)
and clone { payload; _ } =
match payload with
| RA v -> make_ra v
| VV nv -> make_vv (clone nv)
| _ -> assert false
let _ =
let y = make_ra 7 in
let x = make_vv y in
let _ = clone x in
Gc.major ();
Gc.full_major ();
let _ = clone y in
Gc.minor ()
To reproduce, compile with ocamlopt -o block block_ml.c block.ml, run block, and terminate it with Ctrl-C. The description above summarizes the back trace generated by valgrind or gdb.
It's always possible that the C interface code is not correct, but I can't see the problem...
I'm testing the Sundials/ML library against OCaml 5.0.0. One of the examples spins forever after the following sequence:
caml_scan_global_young_rootslocksroots_mutex.caml_remove_global_root.caml_delete_global_rootrequestsroots_mutexand spins until ^C.The smallest failing example that I have been able to produce is as follows. Sorry it's not simpler.
block_ml.c:block.ml:To reproduce, compile with
ocamlopt -o block block_ml.c block.ml, runblock, and terminate it with Ctrl-C. The description above summarizes the back trace generated by valgrind or gdb.It's always possible that the C interface code is not correct, but I can't see the problem...