/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ /* Copyright (C) 2014 Stony Brook University This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* * slab.c * * This file contains implementation of PAL's internal memory allocator. */ #include "pal_internal.h" #include "api.h" #ifndef NO_INTERNAL_ALLOC #include "pal_defs.h" #include "pal_error.h" #include "pal_debug.h" static int slab_alignment; static PAL_LOCK slab_mgr_lock = LOCK_INIT; #define system_lock() _DkInternalLock(&slab_mgr_lock) #define system_unlock() _DkInternalUnlock(&slab_mgr_lock) #if STATIC_SLAB == 1 # define POOL_SIZE 64 * 1024 * 1024 /* 64MB by default */ static char mem_pool[POOL_SIZE]; static void *bump = mem_pool; static void *mem_pool_end = &mem_pool[POOL_SIZE]; #else # define PAGE_SIZE (slab_alignment) #endif #define STARTUP_SIZE 2 /* This function is protected by slab_mgr_lock. */ static inline void * __malloc (int size) { void * addr = NULL; #if STATIC_SLAB == 1 if (bump + size <= mem_pool_end) { addr = bump; bump += size; return addr; } #endif _DkVirtualMemoryAlloc(&addr, size, PAL_ALLOC_INTERNAL, PAL_PROT_READ|PAL_PROT_WRITE); return addr; } #define system_malloc(size) __malloc(size) static inline void __free (void * addr, int size) { #if STATIC_SLAB == 1 if (addr >= (void *)mem_pool && addr < mem_pool_end) return; #endif _DkVirtualMemoryFree(addr, size); } #define system_free(addr, size) __free(addr, size) #include "slabmgr.h" static SLAB_MGR slab_mgr = NULL; void init_slab_mgr (int alignment) { if (slab_mgr) return; #if PROFILING == 1 unsigned long before_slab = _DkSystemTimeQuery(); #endif slab_alignment = alignment; slab_mgr = create_slab_mgr(); if (!slab_mgr) init_fail(PAL_ERROR_NOMEM, "cannot initialize slab manager"); #if PROFILING == 1 pal_state.slab_time += _DkSystemTimeQuery() - before_slab; #endif } void * malloc (size_t size) { #if PROFILING == 1 unsigned long before_slab = _DkSystemTimeQuery(); #endif void * ptr = slab_alloc(slab_mgr, size); #ifdef DEBUG /* In debug builds, try to break code that uses uninitialized heap * memory by explicitly initializing to a non-zero value. */ if (ptr) memset(ptr, 0xa5, size); #endif if (!ptr) { /* * Normally, the PAL should not run out of memory. * If malloc() failed internally, we cannot handle the * condition and must terminate the current process. */ printf("******** Out-of-memory in PAL ********\n"); _DkProcessExit(-1); } #if PROFILING == 1 pal_state.slab_time += _DkSystemTimeQuery() - before_slab; #endif return ptr; } // Copies data from `mem` to a newly allocated buffer of a specified size. void * malloc_copy (const void * mem, size_t size) { void * nmem = malloc(size); if (nmem) memcpy(nmem, mem, size); return nmem; } char * strdup (const char *s) { size_t len = strlen(s) + 1; char *new = malloc(len); if (new) memcpy(new, s, len); return new; } void * calloc (size_t nmem, size_t size) { void * ptr = malloc(nmem * size); if (ptr) memset(ptr, 0, nmem * size); return ptr; } void free (void * ptr) { #if PROFILING == 1 unsigned long before_slab = _DkSystemTimeQuery(); #endif slab_free(slab_mgr, ptr); #if PROFILING == 1 pal_state.slab_time += _DkSystemTimeQuery() - before_slab; #endif } #endif /* !NO_INTERNAL_ALLOC */