/* One process: the Flan program on the main thread, the OCaml compiler beside * it on a domain of its own. * * This is the shape item 11 settles on, and the reason it is written this way * round rather than the other: on macOS the window has to be on the main * thread, so the game keeps main() and the compiler moves to the side -- * beside the listener vendor/agent/flan_agent.c already starts there. * * The program and the compiler do not talk to each other here. Wiring them up * is the real work; this only shows they can share an address space, a link, * and a process, with clang doing the final link. */ #include #include #include #include #include #include #include #include /* The Flan program's entry point, renamed out of main's way by merged.sh. */ extern int flan_program_main(int argc, char **argv); static char **g_argv; static const char *g_src; /* The Flan program's main calls exit(), so the compiler has to be up before it * starts -- which is the honest ordering anyway: the image comes up and serves, * then the program runs, the way starting an SBCL image does. */ static atomic_int compiler_ready = 0; static double ms_since(struct timespec a) { struct timespec b; clock_gettime(CLOCK_MONOTONIC, &b); return (b.tv_sec - a.tv_sec) * 1e3 + (b.tv_nsec - a.tv_nsec) / 1e6; } static void *compiler_side(void *unused) { struct timespec t0; const value *f; (void)unused; clock_gettime(CLOCK_MONOTONIC, &t0); caml_startup(g_argv); printf("[compiler] up on a side thread in %.3f ms\n", ms_since(t0)); f = caml_named_value("spike_thread_compile"); if (f) { clock_gettime(CLOCK_MONOTONIC, &t0); printf("[compiler] %s\n", String_val(caml_callback(*f, caml_copy_string(g_src)))); printf("[compiler] compiled the running program from inside it, in %.3f ms\n", ms_since(t0)); } caml_release_runtime_system(); atomic_store(&compiler_ready, 1); return NULL; } int main(int argc, char **argv) { pthread_t comp; int rc; g_argv = argv; g_src = argc > 1 ? argv[1] : "test/programs/edn.flan"; if (pthread_create(&comp, NULL, compiler_side, NULL) != 0) return 1; while (!atomic_load(&compiler_ready)) { struct timespec t = { 0, 2000000L }; nanosleep(&t, NULL); } /* The main thread is the program's, and it never enters OCaml. */ printf("[program] running on the main thread\n"); rc = flan_program_main(argc, argv); printf("[program] returned %d\n", rc); pthread_join(comp, NULL); printf("one process: a Flan program and the OCaml compiler, same binary\n"); return 0; }