in src/heap/hh_shared.c [776:849]
CAMLprim value hh_shared_init(value config_val, value num_workers_val) {
CAMLparam2(config_val, num_workers_val);
CAMLlocal1(result);
int page_bsize = getpagesize();
/* Calculate layout information. We need to figure out how big the shared file
* needs to be in order to create the file. We will also store enough of the
* layout information in the first page of the shared file so that workers can
* create mappings for the rest of the shared data. */
size_t num_workers = Long_val(num_workers_val);
size_t locals_bsize = CACHE_ALIGN((1 + num_workers) * sizeof(local_t));
size_t hashtbl_slots = 1ul << Long_val(Field(config_val, 1));
size_t hashtbl_bsize = CACHE_ALIGN(hashtbl_slots * sizeof(helt_t));
size_t heap_bsize = Long_val(Field(config_val, 0));
/* The total size of the shared file must have space for the info page, local
* data, the hash table, and the heap. */
size_t shared_mem_bsize =
page_bsize + locals_bsize + hashtbl_bsize + heap_bsize;
memfd_init(shared_mem_bsize);
/* The info page contains (1) size information describing the layout of the
* rest of the shared file; (2) values which are atomically updated by
* workers, like the heap pointer; and (3) various configuration which is
* conventient to stick here, like the log level. */
map_info_page(page_bsize);
info->locals_bsize = locals_bsize;
info->hashtbl_bsize = hashtbl_bsize;
info->heap_bsize = heap_bsize;
info->shared_mem_bsize = shared_mem_bsize;
info->hashtbl_slots = hashtbl_slots;
info->heap_init = hashtbl_bsize;
info->heap_max = info->heap_init + heap_bsize;
info->gc_phase = Phase_idle;
info->log_level = Long_val(Field(config_val, 2));
// Ensure the global counter starts on a COUNTER_RANGE boundary
info->counter = ALIGN(early_counter + 1, COUNTER_RANGE);
// Initialize top heap pointers
info->heap = info->heap_init;
define_mappings(page_bsize);
mark_stack_size = MARK_STACK_INIT_SIZE;
mark_stack_init = malloc(MARK_STACK_INIT_SIZE * sizeof(addr_t));
mark_stack = mark_stack_init;
mark_stack_ptr = mark_stack;
mark_stack_end = mark_stack + MARK_STACK_INIT_SIZE;
// Invariant: info->heap_init <= gc_end <= info->heap
// See declaration of gc_end
gc_end = info->heap;
#ifndef _WIN32
// Uninstall ocaml's segfault handler. It's supposed to throw an exception on
// stack overflow, but we don't actually handle that exception, so what
// happens in practice is we terminate at toplevel with an unhandled exception
// and a useless ocaml backtrace. A core dump is actually more useful. Sigh.
struct sigaction sigact = {0};
sigact.sa_handler = SIG_DFL;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGSEGV, &sigact, NULL);
#endif
result = caml_alloc_tuple(2);
Store_field(result, 0, alloc_heap_bigarray());
Store_field(result, 1, Val_handle(memfd));
CAMLreturn(result);
}