175 lines
4.9 KiB
C
175 lines
4.9 KiB
C
|
|
// tiny_c7_ultra.c - UF-2: C7 ULTRA TLS freelist (coldは既存 v3 を使用)
|
|||
|
|
|
|||
|
|
#include <stddef.h>
|
|||
|
|
#include <stdint.h>
|
|||
|
|
#include <stdbool.h>
|
|||
|
|
#include "box/tiny_c7_ultra_box.h"
|
|||
|
|
#include "box/smallobject_hotbox_v3_box.h"
|
|||
|
|
#include "box/tiny_geometry_box.h"
|
|||
|
|
#include "tiny_region_id.h"
|
|||
|
|
#include "box/tiny_c7_ultra_segment_box.h"
|
|||
|
|
|
|||
|
|
static __thread tiny_c7_ultra_tls_t g_tiny_c7_ultra_tls;
|
|||
|
|
|
|||
|
|
static inline void tiny_c7_ultra_clear(tiny_c7_ultra_tls_t* tls) {
|
|||
|
|
tls->page_base = NULL;
|
|||
|
|
tls->block_size = 0;
|
|||
|
|
tls->capacity = 0;
|
|||
|
|
tls->used = 0;
|
|||
|
|
tls->freelist = NULL;
|
|||
|
|
tls->page_idx = 0;
|
|||
|
|
tls->page_meta = NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tiny_c7_ultra_tls_t* tiny_c7_ultra_tls_get(void) {
|
|||
|
|
return &g_tiny_c7_ultra_tls;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// セグメントから C7 ページを 1 枚借りて自前で carve する
|
|||
|
|
static bool tiny_c7_ultra_lease_page(tiny_c7_ultra_tls_t* tls) {
|
|||
|
|
tiny_c7_ultra_segment_t* seg = tls->seg;
|
|||
|
|
if (!seg) {
|
|||
|
|
seg = tiny_c7_ultra_segment_acquire();
|
|||
|
|
if (!seg) return false;
|
|||
|
|
tls->seg = seg;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
size_t block_sz = tls->block_size ? tls->block_size
|
|||
|
|
: (size_t)tiny_stride_for_class(7);
|
|||
|
|
if (block_sz == 0) return false;
|
|||
|
|
uint32_t capacity = (uint32_t)(seg->page_size / block_sz);
|
|||
|
|
if (capacity == 0) return false;
|
|||
|
|
|
|||
|
|
// 空きページを 1 枚だけ拾う(UF-3 では最初の空きを線形探索)
|
|||
|
|
uint32_t chosen = seg->num_pages;
|
|||
|
|
for (uint32_t i = 0; i < seg->num_pages; i++) {
|
|||
|
|
tiny_c7_ultra_page_meta_t* pm = &seg->pages[i];
|
|||
|
|
if (pm->capacity == 0 || pm->used == 0) {
|
|||
|
|
chosen = i;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (chosen == seg->num_pages) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tiny_c7_ultra_page_meta_t* page = &seg->pages[chosen];
|
|||
|
|
uint8_t* base = (uint8_t*)seg->base + ((size_t)chosen * seg->page_size);
|
|||
|
|
|
|||
|
|
// freelist を自前で carve
|
|||
|
|
void* head = NULL;
|
|||
|
|
for (int i = (int)capacity - 1; i >= 0; i--) {
|
|||
|
|
uint8_t* blk = base + ((size_t)i * block_sz);
|
|||
|
|
*(void**)blk = head;
|
|||
|
|
head = blk;
|
|||
|
|
}
|
|||
|
|
if (!head) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
page->freelist = head;
|
|||
|
|
page->capacity = capacity;
|
|||
|
|
page->used = 0;
|
|||
|
|
|
|||
|
|
tls->page_base = base;
|
|||
|
|
tls->block_size = block_sz;
|
|||
|
|
tls->capacity = capacity;
|
|||
|
|
tls->used = 0;
|
|||
|
|
tls->freelist = head;
|
|||
|
|
tls->page_idx = chosen;
|
|||
|
|
tls->page_meta = page;
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void* tiny_c7_ultra_alloc(size_t size) {
|
|||
|
|
(void)size; // C7 専用のため未使用
|
|||
|
|
tiny_c7_ultra_tls_t* tls = tiny_c7_ultra_tls_get();
|
|||
|
|
|
|||
|
|
// 1) freelist hit
|
|||
|
|
void* p = tls->freelist;
|
|||
|
|
if (__builtin_expect(p != NULL, 1)) {
|
|||
|
|
void* next = *(void**)p;
|
|||
|
|
tls->freelist = next;
|
|||
|
|
if (tls->page_meta) {
|
|||
|
|
tls->page_meta->freelist = next;
|
|||
|
|
if (tls->page_meta->used < tls->page_meta->capacity) {
|
|||
|
|
tls->page_meta->used++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (tls->used < tls->capacity) {
|
|||
|
|
tls->used++;
|
|||
|
|
}
|
|||
|
|
return tiny_region_id_write_header(p, 7);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2) lease page from existing v3 cold path
|
|||
|
|
if (!tiny_c7_ultra_lease_page(tls)) {
|
|||
|
|
// safety fallback to v3
|
|||
|
|
return so_alloc(7);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
p = tls->freelist;
|
|||
|
|
if (__builtin_expect(p == NULL, 0)) {
|
|||
|
|
return so_alloc(7);
|
|||
|
|
}
|
|||
|
|
void* next = *(void**)p;
|
|||
|
|
tls->freelist = next;
|
|||
|
|
if (tls->page_meta) {
|
|||
|
|
tls->page_meta->freelist = next;
|
|||
|
|
if (tls->page_meta->used < tls->page_meta->capacity) {
|
|||
|
|
tls->page_meta->used++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (tls->used < tls->capacity) {
|
|||
|
|
tls->used++;
|
|||
|
|
}
|
|||
|
|
return tiny_region_id_write_header(p, 7);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void tiny_c7_ultra_free(void* ptr) {
|
|||
|
|
tiny_c7_ultra_tls_t* tls = tiny_c7_ultra_tls_get();
|
|||
|
|
if (!ptr) {
|
|||
|
|
so_free(7, ptr);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tiny_c7_ultra_segment_t* seg = tiny_c7_ultra_segment_from_ptr(ptr);
|
|||
|
|
if (!seg) {
|
|||
|
|
so_free(7, ptr);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint32_t page_idx = 0;
|
|||
|
|
tiny_c7_ultra_page_meta_t* page = tiny_c7_ultra_page_of(ptr, &seg, &page_idx);
|
|||
|
|
if (!page) {
|
|||
|
|
so_free(7, ptr);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const size_t block_sz = tls->block_size ? tls->block_size
|
|||
|
|
: (size_t)tiny_stride_for_class(7);
|
|||
|
|
const uint32_t cap = page->capacity ? page->capacity
|
|||
|
|
: (uint32_t)(seg->page_size / block_sz);
|
|||
|
|
uintptr_t base = (uintptr_t)seg->base + ((size_t)page_idx * seg->page_size);
|
|||
|
|
uintptr_t paddr = (uintptr_t)ptr;
|
|||
|
|
size_t span = block_sz * (size_t)cap;
|
|||
|
|
if (paddr < base || paddr >= base + span || ((paddr - base) % block_sz) != 0) {
|
|||
|
|
so_free(7, ptr);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
*(void**)ptr = page->freelist;
|
|||
|
|
page->freelist = ptr;
|
|||
|
|
if (page->used > 0) {
|
|||
|
|
page->used--;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tls->page_meta = page;
|
|||
|
|
tls->page_idx = page_idx;
|
|||
|
|
tls->page_base = (void*)base;
|
|||
|
|
tls->capacity = cap;
|
|||
|
|
tls->block_size = block_sz;
|
|||
|
|
tls->freelist = page->freelist;
|
|||
|
|
tls->used = page->used;
|
|||
|
|
}
|