CAMLprim value hh_shared_init()

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);
}