#ifndef BOXROOT_H
#define BOXROOT_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#if defined(CAML_INTERNALS) && defined(__cplusplus)
static_assert(false,"!defined(CAML_INTERNALS) || !defined(__cplusplus)");
#endif
#include "ocaml_hooks.h"
#include "platform.h"
#ifdef __cplusplus
extern "C" {
#define _Thread_local thread_local
#endif
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);
bool boxroot_setup(void);
void boxroot_teardown(void);
enum {
BOXROOT_NOT_SETUP,
BOXROOT_RUNNING,
BOXROOT_TORE_DOWN,
BOXROOT_INVALID
};
int boxroot_status(void);
char const * boxroot_error_string(void);
void boxroot_print_stats(void);
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;
int alloc_count;
int domain_id;
int classe;
} bxr_free_list;
#define BXR_CLASS_YOUNG 0
#if OCAML_MULTICORE
extern _Thread_local bxr_free_list **bxr_cached_fl_ptr;
#else
extern bxr_free_list *bxr_current_fl;
#endif
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 BOXROOT_DEBUG
bxr_create_debug(init);
#endif
if (!BXR_MULTITHREAD || BXR_LIKELY(bxr_domain_lock_held())) {
#if OCAML_MULTICORE
bxr_free_list *fl = *bxr_cached_fl_ptr;
#else
bxr_free_list *fl = bxr_current_fl;
#endif
bxr_slot_ref new_root = fl->next;
if (BXR_LIKELY(new_root != (bxr_slot_ref)fl)) {
fl->next = new_root->as_slot_ref;
fl->alloc_count++;
new_root->as_value = init;
return (boxroot)new_root;
}
}
return bxr_create_slow(init);
}
#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;
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_aux(boxroot root, bxr_free_list *fl, bool remote);
inline void boxroot_delete(boxroot root)
{
#if BOXROOT_DEBUG
bxr_delete_debug(root);
#endif
bxr_free_list *fl = Bxr_get_pool_header(root);
bool remote =
BXR_FORCE_REMOTE
|| (BXR_MULTITHREAD
&& (BXR_UNLIKELY(!bxr_domain_lock_held())
#if OCAML_MULTICORE
|| BXR_UNLIKELY(fl->domain_id != Caml_state->id)
#endif
));
if (remote || BXR_UNLIKELY(bxr_free_slot(fl, root)))
bxr_delete_aux(root, fl, 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
bxr_modify_debug(rootp);
#endif
if (BXR_LIKELY(bxr_domain_lock_held())) {
bxr_slot_ref s = (bxr_slot_ref)*rootp;
if (BXR_LIKELY(Bxr_get_pool_header(s)->classe == BXR_CLASS_YOUNG)) {
s->as_value = new_value;
return true;
}
}
return bxr_modify_slow(rootp, new_value);
}
static inline void boxroot_setup_systhreads(void) { boxroot_setup(); }
#ifdef __cplusplus
} #endif
#endif