// Copyright (c) 2025, Zak Fenton // Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this // software according to the terms and conditions of the Mulan PSL v2. // You may obtain a copy of Mulan PSL v2 at: // http://license.coscl.org.cn/MulanPSL2 // THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of // any kind, either express or implied, including but not limited to // non-infringement, merchantability or fit for a particular purpose. // See the Mulan PSL v2 for more details. #include #include #include #include #include "elmalloc.h" #include "internal.h" elmm_t _libc_mm; elmm_sbrk_data_t _libc_sbrkdata; #define SIMGC_SYSMALLOC(x) elmm_malloc(&_libc_mm, x) #define SIMGC_FREE(x) elmm_free(&_libc_mm, x) #define SIMGC_IMPLEMENTATION #include "simgc.h" simgc_t _libc_gc; simgc_thread_t* _libc_gcmainthread; void _libc_malloc_init(void* stackptr) { // Initialising the memory manager is currently a bit of work, but in // theory should pay off as the memory manager code is easy to fine // tune and adapt for more specialised allocators. _libc_sbrkdata.func = (void*)(&sbrk); // Hooking it straight to the syscall should work, the userdata argument will be ignored _libc_sbrkdata.max = 1024 * 1024 * 8; _libc_sbrkdata.onlyChunk = NULL; _libc_sbrkdata.udata = NULL; _libc_mm.bigchunkMinimum = 1024 * 1024; _libc_mm.bigchunkGranularity = 1024; _libc_mm.initialised = false; _libc_mm.lockFunction = NULL; _libc_mm.bigchunkData = &_libc_sbrkdata; _libc_mm.bigchunkFunction = &elmm_bigchunk_sbrk; if (!elmm_init(&_libc_mm)) { const char* err = "ERROR: Failed to initialise memory manager!\n"; write(2, err, strlen(err)); exit(-1); } if (!elmm_growheap(&_libc_mm, 1024*1024*4)) { printf("Growheap failed.\n"); } else { printf("Growheap success!\n"); } simgc_init(&_libc_gc); _libc_gcmainthread = simgc_begin_inner(&_libc_gc, stackptr); } void _libc_malloc_finish() { simgc_end_inner(_libc_gcmainthread); simgc_reclaim(&_libc_gc); } void* _libc_gcalloc(size_t sz) { return simgc_alloc(&_libc_gc, sz); } void* malloc(size_t sz) { return elmm_malloc(&_libc_mm, sz); } void free(void* mem) { return elmm_free(&_libc_mm, mem); } void* calloc(size_t n, size_t sz) { /* TODO: check for overflow of n * sz? Probably not a problem IRL (may * have been more of a thing back in the 16-bit era but I guess math * overflow is not an important issue on 64-bit or even 32-bit memory * allocator calls) */ return elmm_calloc(&_libc_mm, n, sz); } void* realloc(void* mem, size_t sz) { return elmm_realloc(&_libc_mm, mem, sz); }