flan/spike/embed/thread_ml.ml
Joseph Ferano d272a5b1e5 Six probes for whether the OCaml compiler can live in the game's process
Item 12 asks five questions and says to answer them with a spike rather than a
rewrite. spike/embed/ is that spike: one script, six binaries, each one built to
fail loudly at the thing it is asking about. It is deliberately not a dune
target -- the root dune only excludes old-ocaml/, so a dune file here would land
in @default and make the spike part of the build. It drives ocamlfind and clang
by hand against the flan.cmxa dune already produces.

The probes, in the order they would kill the idea: the smallest possible link, a
C main() reaching one OCaml function; the whole compiler linked in and doing
real work; the same again with lib/dynload_stubs.c from the unmerged dlopen
branch, because that is the only C the compiler itself is built from; the game
keeping the main thread while caml_startup happens on a pthread beside it; the
SIGSEGV disposition read on both sides of caml_startup; and an 8 MiB arena
checked byte for byte across a compaction.

No result is written down yet. This is the apparatus.
2026-09-12 20:27:45 +07:00

33 lines
1.5 KiB
OCaml

(* Step 4: the macOS shape. The game owns the main thread; the compiler and the
listener run beside it.
The question is NOT "can OCaml use threads" -- it is whether caml_startup can
be called from a pthread that C spawned, while main() goes on to run a
window loop it never returns from. That is the inversion item 11 settles on,
and it is the one that has to be measured rather than assumed. *)
let compile file =
let l = Flan.Load.program ~file (Flan.Parse.program (Flan.Reader.read_file file)) in
let p = Flan.Check.program l.Flan.Load.decls in
String.length (Flan.Emit.program ~dev:true p)
let () =
Callback.register "spike_thread_compile" (fun (file : string) ->
let tid = Thread.id (Thread.self ()) in
match compile file with
| n ->
Printf.sprintf "compiled on OCaml thread %d: %d bytes of LLVM IR" tid n
| exception e -> Printf.sprintf "FAILED: %s" (Printexc.to_string e));
Callback.register "spike_domains" (fun () ->
(* A second domain doing real work while the main thread is elsewhere --
5.2's multicore runtime, which is the objection item 12 says has gone
away. Confirmed rather than assumed. *)
let d = Domain.spawn (fun () ->
let s = ref 0 in
for i = 1 to 5_000_000 do s := !s + i done;
(Domain.self () :> int), !s)
in
let id, s = Domain.join d in
Printf.sprintf "domain %d summed to %d; recommended_domain_count = %d"
id s (Domain.recommended_domain_count ()))