8000
Skip to content

caml_remove_global_root in finalizer spins on roots_mutex #11865

@tbrk

Description

@tbrk

I'm testing the Sundials/ML library against OCaml 5.0.0. One of the examples spins forever after the following sequence:

  1. The GC is triggered and caml_scan_global_young_roots locks roots_mutex.
  2. During the subsequent scan, one of my finalizers in C is called and it invokes caml_remove_global_root.
  3. 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...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0