#include "sys.h"
#include "core/platform.h"
#include <rayforce.h>
#include <string.h>
#include <stdatomic.h>
#define SYS_HDR_SIZE 32
typedef struct {
size_t map_size;
size_t usr_size;
char _pad[SYS_HDR_SIZE - 2 * sizeof(size_t)];
} sys_hdr_t;
_Static_assert(sizeof(sys_hdr_t) == SYS_HDR_SIZE, "sys_hdr_t must be 32 bytes");
static _Atomic(int64_t) g_sys_current = 0;
static _Atomic(int64_t) g_sys_peak = 0;
static _Atomic(int64_t) g_sys_mapped = 0;
static _Atomic(int64_t) g_sys_mapped_peak = 0;
static inline void track_bump(_Atomic(int64_t)* cur_c, _Atomic(int64_t)* peak_c,
int64_t delta) {
int64_t cur = atomic_fetch_add_explicit(cur_c, delta, memory_order_relaxed) + delta;
if (delta <= 0) return;
int64_t pk = atomic_load_explicit(peak_c, memory_order_relaxed);
while (cur > pk) {
if (atomic_compare_exchange_weak_explicit(peak_c, &pk, cur,
memory_order_relaxed,
memory_order_relaxed))
break;
}
}
void ray_sys_track_add(int64_t bytes) { track_bump(&g_sys_current, &g_sys_peak, bytes); }
void ray_sys_track_sub(int64_t bytes) { track_bump(&g_sys_current, &g_sys_peak, -bytes); }
void ray_sys_track_file_add(int64_t bytes) { track_bump(&g_sys_mapped, &g_sys_mapped_peak, bytes); }
void ray_sys_track_file_sub(int64_t bytes) { track_bump(&g_sys_mapped, &g_sys_mapped_peak, -bytes); }
static inline size_t page_round(size_t n) {
return (n + 4095) & ~(size_t)4095;
}
void* ray_sys_alloc(size_t size) {
if (size == 0) size = 1;
if (size > SIZE_MAX - SYS_HDR_SIZE) return NULL;
size_t total = page_round(SYS_HDR_SIZE + size);
void* p = ray_vm_alloc(total);
if (!p) return NULL;
sys_hdr_t* hdr = (sys_hdr_t*)p;
hdr->map_size = total;
hdr->usr_size = size;
return (char*)p + SYS_HDR_SIZE;
}
void ray_sys_free(void* ptr) {
if (!ptr) return;
sys_hdr_t* hdr = (sys_hdr_t*)((char*)ptr - SYS_HDR_SIZE);
ray_vm_free(hdr, hdr->map_size);
}
void* ray_sys_realloc(void* ptr, size_t new_size) {
if (!ptr) return ray_sys_alloc(new_size);
if (new_size == 0) { ray_sys_free(ptr); return NULL; }
if (new_size > SIZE_MAX - SYS_HDR_SIZE) return NULL;
sys_hdr_t* old_hdr = (sys_hdr_t*)((char*)ptr - SYS_HDR_SIZE);
size_t old_usr = old_hdr->usr_size;
size_t new_total = page_round(SYS_HDR_SIZE + new_size);
if (new_total == old_hdr->map_size) {
old_hdr->usr_size = new_size;
return ptr;
}
void* new_ptr = ray_sys_alloc(new_size);
if (!new_ptr) return NULL;
memcpy(new_ptr, ptr, old_usr < new_size ? old_usr : new_size);
ray_sys_free(ptr);
return new_ptr;
}
char* ray_sys_strdup(const char* s) {
if (!s) return NULL;
size_t len = strlen(s);
char* dup = (char*)ray_sys_alloc(len + 1);
if (!dup) return NULL;
memcpy(dup, s, len + 1);
return dup;
}
void ray_sys_get_stat(int64_t* out_current, int64_t* out_peak) {
if (out_current)
*out_current = atomic_load_explicit(&g_sys_current, memory_order_relaxed);
if (out_peak)
*out_peak = atomic_load_explicit(&g_sys_peak, memory_order_relaxed);
}
void ray_sys_get_mapped(int64_t* out_current, int64_t* out_peak) {
if (out_current)
*out_current = atomic_load_explicit(&g_sys_mapped, memory_order_relaxed);
if (out_peak)
*out_peak = atomic_load_explicit(&g_sys_mapped_peak, memory_order_relaxed);
}