#include "../range.h" #include "memory.h" static void ensure_allocated(struct cch_backing_memory *mem, off_t amount) { if (amount > mem->expanse) mem->expanse = amount; if (amount > mem->alloc) { mem->alloc = al_next_power_of_two(amount); mem->data = (u8 *)al_realloc(mem->data, mem->alloc); } } static void memory_backing_lock(struct cch_backing *backing) { struct cch_backing_memory *mem = (struct cch_backing_memory *)backing; nn_mutex_lock(&mem->mutex); } static void memory_backing_write(struct cch_backing *backing, u8 *buf, off_t index, size_t *count) { struct cch_backing_memory *mem = (struct cch_backing_memory *)backing; off_t n = (off_t)*count; nn_mutex_lock(&mem->mutex); off_t size = mem->backing.size; if (size > 0 && index + n >= size) { n = MAX(size - index, (off_t)0); } if (n > 0) { ensure_allocated(mem, index + n); al_memcpy(mem->data + index, buf, n); cch_backing_fill_range(&mem->backing, index, n); } *count = (size_t)n; nn_mutex_unlock(&mem->mutex); } static u8 *memory_backing_get_ptr(struct cch_backing *backing, off_t index, size_t *count) { struct cch_backing_memory *mem = (struct cch_backing_memory *)backing; off_t n = (off_t)*count; nn_mutex_lock(&mem->mutex); off_t size = mem->backing.size; if (size > 0 && index + n >= size) { n = MAX(size - index, (off_t)0); } *count = (size_t)n; al_assert(mem->alloc >= index + n); return (u8 *)(mem->data + index); } static void memory_backing_unlock(struct cch_backing *backing) { struct cch_backing_memory *mem = (struct cch_backing_memory *)backing; nn_mutex_unlock(&mem->mutex); } static void memory_backing_set_size(struct cch_backing *backing, off_t size, bool expand_to_size) { struct cch_backing_memory *mem = (struct cch_backing_memory *)backing; nn_mutex_lock(&mem->mutex); mem->backing.size = size; if (expand_to_size) { al_assert(size > 0); ensure_allocated(mem, size); } nn_mutex_unlock(&mem->mutex); } static off_t memory_backing_get_size_if_known(struct cch_backing *backing) { struct cch_backing_memory *mem = (struct cch_backing_memory *)backing; nn_mutex_lock(&mem->mutex); off_t size = mem->backing.size; nn_mutex_unlock(&mem->mutex); return size; } static void memory_backing_finalize(struct cch_backing *backing) { struct cch_backing_memory *mem = (struct cch_backing_memory *)backing; nn_mutex_lock(&mem->mutex); mem->backing.size = mem->expanse; nn_mutex_unlock(&mem->mutex); } static void memory_backing_free(struct cch_backing **backing) { struct cch_backing_memory *mem = (struct cch_backing_memory *)*backing; al_free(mem->data); nn_mutex_destroy(&mem->mutex); al_array_free(mem->backing.available); al_free(mem); *backing = NULL; } struct cch_backing *cch_backing_memory_create(size_t size) { struct cch_backing_memory *mem = al_alloc_object(struct cch_backing_memory); mem->backing.mode = CACHE_BACKING_MAPPED; mem->backing.size = -1; mem->backing.lock = memory_backing_lock; mem->backing.write = memory_backing_write; mem->backing.get_ptr = memory_backing_get_ptr; mem->backing.unlock = memory_backing_unlock; mem->backing.set_size = memory_backing_set_size; mem->backing.get_size_if_known = memory_backing_get_size_if_known; mem->backing.finalize = memory_backing_finalize; mem->backing.free = memory_backing_free; if (size > 0) mem->data = (u8 *)al_malloc(size); else mem->data = NULL; mem->alloc = size; nn_mutex_init(&mem->mutex); al_array_init(mem->backing.available); return (struct cch_backing *)mem; }