/* * Copyright (C) 2025 dwlr * * BSD 3-Clause License (BSD-3-Clause) * See LICENSE for details */ typedef struct { u8* base; u8* cursor; usize size; } arena; typedef struct { u8* base; ssize pages; } do_pagefault_args; void* do_pagefault(void* arg) { ssize i = 0; ssize p = mm_pagesize(); do_pagefault_args* args = (do_pagefault_args*)arg; if(!args) { report(ERR, "do_pagefault() with NULL args!\n"); return NULL; } for(i = 0; i < args->pages; i++) args->base[p * i] = 0; return NULL; } bool ar_create(usize size, bool prefault, arena* ar) { ssize p = mm_pagesize(); if(!ar) return false; if(size <= 0) return false; size += (size % p) ? (p - (size % p)) : 0; ar->base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if(ar->base == MAP_FAILED) return false; ar->size = size; ar->cursor = ar->base; if(prefault) { ssize i = 0; ssize cpus = cpu_count(); pthread_t* t = NULL; do_pagefault_args* args = NULL; t = calloc(cpus, sizeof(t[0])); if(!t) report(FATAL, "ar_create()/prefault/calloc(t) failed!\n"); else { args = calloc(cpus, sizeof(args[0])); if(!args) { free(t); report(FATAL, "ar_create()/prefault/calloc(args) failed!\n"); } } for(i = 1; i < cpus; i++) { args[i].base = ar->base + ((size / cpus) * i); args[i].pages = ((size / p) / cpus); pthread_create(&t[i], NULL, do_pagefault, &args[i]); } args[0].base = ar->base; args[0].pages = ((size / p) / cpus); do_pagefault(&args[0]); for(i = 1; i < cpus; i++) pthread_join(t[i], NULL); free(args); free(t); } return true; } #define ar_push(ar, sz) ar_pusha((ar), (sz), sizeof(int), true) void* ar_pusha(arena* ar, usize size, usize alignment, bool zero) { usize cur, ovfl; if(!ar) return NULL; else { cur = align((usize)ar->cursor, alignment); ovfl = (cur + size); if(ovfl < cur) return NULL; if(ovfl <= (usize)(ar->base + ar->size)) { ar->cursor = (u8*)ovfl; if(zero) memset((u8*)cur, 0, size); return (u8*)cur; } else { report(ERR, "arena(%P): overflow @ %P x %llu\n", ar, cur, size); return NULL; } } } void ar_pop(arena* ar, usize size) { if(!ar) return; else ar->cursor = min(ar->base, ar->cursor - size); } void ar_clear(arena* ar) { if(ar) ar->cursor = ar->base; } void ar_destroy(arena* ar) { if(!ar) return; munmap(ar->base, ar->size); ar->base = ar->cursor = NULL; ar->size = 0; }