#ifndef BOXROOT_H
#define BOXROOT_H
#include <stdbool.h>
#include "ocaml_hooks.h"
#include "platform.h"
typedef struct bxr_private* boxroot;
inline boxroot boxroot_create(value);
inline value boxroot_get(boxroot r) { return *(value *)r; }
inline value const * boxroot_get_ref(boxroot r) { return (value *)r; }
inline void boxroot_delete(boxroot);
inline bool boxroot_modify(boxroot *, value);
void boxroot_teardown();
enum {
BOXROOT_NOT_SETUP,
BOXROOT_RUNNING,
BOXROOT_TORE_DOWN,
BOXROOT_INVALID
};
int boxroot_status();
void boxroot_print_stats();
bool boxroot_setup();
typedef union bxr_slot *bxr_slot_ref;
typedef union bxr_slot {
bxr_slot_ref as_slot_ref;
value as_value;
} bxr_slot;
typedef struct bxr_free_list {
bxr_slot_ref next;
bxr_slot_ref end;
int alloc_count;
int domain_id;
int class;
} bxr_free_list;
#define BXR_CLASS_YOUNG 0
extern _Thread_local ptrdiff_t bxr_cached_dom_id;
extern bxr_free_list *bxr_current_free_list[];
void bxr_create_debug(value v);
boxroot bxr_create_slow(value v);
#define BXR_MULTITHREAD true
#define BXR_FORCE_REMOTE false
inline boxroot boxroot_create(value init)
{
#if defined(BOXROOT_DEBUG) && (BOXROOT_DEBUG == 1)
bxr_create_debug(init);
#endif
ptrdiff_t dom_id =
(OCAML_MULTICORE && BXR_MULTITHREAD) ? bxr_cached_dom_id : 0;
bxr_free_list *fl = bxr_current_free_list[dom_id + 1];
bxr_slot_ref new_root = fl->next;
if (BXR_UNLIKELY(!bxr_domain_lock_held())
|| BXR_UNLIKELY(new_root == (bxr_slot_ref)fl))
return bxr_create_slow(init);
fl->next = new_root->as_slot_ref;
fl->alloc_count++;
new_root->as_value = init;
return (boxroot)new_root;
}
#define BXR_POOL_LOG_SIZE 14
#define BXR_POOL_SIZE ((size_t)1 << BXR_POOL_LOG_SIZE)
#define BXR_DEALLOC_THRESHOLD ((int)BXR_POOL_SIZE / 2)
#define Bxr_get_pool_header(s) \
((bxr_free_list *)((uintptr_t)(s) & ~((uintptr_t)BXR_POOL_SIZE - 1)))
inline bool bxr_free_slot(bxr_free_list *fl, boxroot root)
{
bxr_slot_ref s = (bxr_slot_ref)root;
bxr_slot_ref next = fl->next;
s->as_slot_ref = next;
if (BXR_MULTITHREAD && BXR_UNLIKELY(next == (bxr_slot_ref)fl))
fl->end = s;
fl->next = s;
int alloc_count = --fl->alloc_count;
return (alloc_count & (BXR_DEALLOC_THRESHOLD - 1)) == 0;
}
void bxr_delete_debug(boxroot root);
void bxr_delete_slow(bxr_free_list *fl, boxroot root, bool remote);
inline void boxroot_delete(boxroot root)
{
#if defined(BOXROOT_DEBUG) && (BOXROOT_DEBUG == 1)
bxr_delete_debug(root);
#endif
bxr_free_list *fl = Bxr_get_pool_header(root);
bool remote_dom_id =
OCAML_MULTICORE ? fl->domain_id != bxr_cached_dom_id : false;
bool remote =
BXR_FORCE_REMOTE
|| (BXR_MULTITHREAD
&& (BXR_UNLIKELY(remote_dom_id) || !bxr_domain_lock_held()));
if (remote || BXR_UNLIKELY(bxr_free_slot(fl, root)))
bxr_delete_slow(fl, root, remote);
}
void bxr_modify_debug(boxroot *rootp);
bool bxr_modify_slow(boxroot *rootp, value new_value);
inline bool boxroot_modify(boxroot *rootp, value new_value)
{
#if defined(BOXROOT_DEBUG) && (BOXROOT_DEBUG == 1)
bxr_modify_debug(rootp);
#endif
if (BXR_UNLIKELY(!bxr_domain_lock_held())) return 0;
bxr_slot_ref s = (bxr_slot_ref)*rootp;
bxr_free_list *fl = Bxr_get_pool_header(s);
if (BXR_LIKELY(fl->class == BXR_CLASS_YOUNG)) {
s->as_value = new_value;
return 1;
} else {
return bxr_modify_slow(rootp, new_value);
}
}
#endif