mempool.c revision 58badbb3393efc20f87a0ca462c5ba463eb3e8ba
165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm/* libunwind - a platform-independent unwind library 265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm Copyright (C) 2002-2003 Hewlett-Packard Co 365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmThis file is part of libunwind. 665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmPermission is hereby granted, free of charge, to any person obtaining 865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidma copy of this software and associated documentation files (the 965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm"Software"), to deal in the Software without restriction, including 1065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmwithout limitation the rights to use, copy, modify, merge, publish, 1165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmdistribute, sublicense, and/or sell copies of the Software, and to 1265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmpermit persons to whom the Software is furnished to do so, subject to 1365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmthe following conditions: 1465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 1565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmThe above copyright notice and this permission notice shall be 1665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmincluded in all copies or substantial portions of the Software. 1765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 1865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 2265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 2365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 2565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 2665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#include <assert.h> 2765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#include <stdlib.h> 2865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#include <string.h> 2965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#include <unistd.h> 3065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 3165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#include <sys/mman.h> 3265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 3365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#include "libunwind.h" 3465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#include "mempool.h" 3565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 3665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#define MAX_ALIGN (sizeof (long double)) 3765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#define SOS_MEMORY_SIZE 16384 3865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 3965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic char sos_memory[SOS_MEMORY_SIZE]; 4065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic char *sos_memp; 4165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic size_t pg_size; 4265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 4365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmHIDDEN void * 4465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmsos_alloc (size_t size) 4565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{ 4665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm char *mem; 4765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 4865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#ifdef HAVE_CMPXCHG 4965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm char *old_mem; 5065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 5165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm size = (size + MAX_ALIGN - 1) & -MAX_ALIGN; 5265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (!sos_memp) 5365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm cmpxchg_ptr (&sos_memp, 0, sos_memory); 5465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm do 5565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm { 5665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm old_mem = sos_memp; 5765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 5865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mem = (char *) (((unsigned long) old_mem + MAX_ALIGN - 1) & -MAX_ALIGN); 5965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mem += size; 6065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (mem >= sos_memory + sizeof (sos_memory)) 6165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm abort (); 6265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm } 6365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm while (!cmpxchg_ptr (&sos_memp, old_mem, mem)); 6465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#else 6565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm static pthread_mutex_t sos_lock = PTHREAD_MUTEX_INITIALIZER; 6665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sigset_t saved_sigmask; 6765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 6865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm size = (size + MAX_ALIGN - 1) & -MAX_ALIGN; 6965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 7065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sigprocmask (SIG_SETMASK, &unwi_full_sigmask, &saved_sigmask); 7165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mutex_lock(&sos_lock); 7265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm { 7365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (!sos_memp) 7465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sos_memp = sos_memory; 7565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 7665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mem = (char *) (((unsigned long) sos_memp + MAX_ALIGN - 1) & -MAX_ALIGN); 7765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mem += size; 7865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (mem >= sos_memory + sizeof (sos_memory)) 7965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm abort (); 8065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sos_memp = mem; 8165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm } 8265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mutex_unlock(&sos_lock); 8365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sigprocmask (SIG_SETMASK, &saved_sigmask, NULL); 8465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#endif 8565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm return mem; 8665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm} 8765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 8865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic void * 8965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmalloc_memory (size_t size) 9065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{ 9165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm /* Hopefully, mmap() goes straight through to a system call stub... */ 9265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm void *mem = mmap (0, size, PROT_READ | PROT_WRITE, 9365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 9465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (mem == MAP_FAILED) 9565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm return NULL; 9665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 9765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm return mem; 9865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm} 9965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 10065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm/* Must be called while holding the mempool lock. */ 10165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 10265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic void 10365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmfree_object (struct mempool *pool, void *object) 10465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{ 10565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm struct object *obj = object; 10665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 10765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm obj->next = pool->free_list; 10865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm pool->free_list = obj; 10965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm ++pool->num_free; 11065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm} 11165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 11265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic void 11365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmadd_memory (struct mempool *pool, char *mem, size_t size, size_t obj_size) 11465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{ 11565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm char *obj; 11665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 11758badbb3393efc20f87a0ca462c5ba463eb3e8bamostang.com!davidm for (obj = mem; obj <= mem + size - obj_size; obj += obj_size) 11865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm free_object (pool, obj); 11965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm} 12065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 12165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic void 12265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmexpand (struct mempool *pool) 12365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{ 12465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm size_t size; 12565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm char *mem; 12665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 12765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm size = pool->chunk_size; 12865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mem = alloc_memory (size); 12965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (!mem) 13065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm { 13165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm size = (pool->obj_size + pg_size - 1) & -pg_size; 13265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mem = alloc_memory (size); 13365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (!mem) 13465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm { 13565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm /* last chance: try to allocate one object from the SOS memory */ 13665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm size = pool->obj_size; 13765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mem = sos_alloc (size); 13865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm } 13965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm } 14065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm add_memory (pool, mem, size, pool->obj_size); 14165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm} 14265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 14365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmHIDDEN void 14465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmmempool_init (struct mempool *pool, size_t obj_size, size_t reserve) 14565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{ 14665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (pg_size == 0) 14765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm pg_size = getpagesize (); 14865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 14965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm memset (pool, 0, sizeof (*pool)); 15065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 15165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mutex_init (&pool->lock); 15265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 15365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm /* round object-size up to integer multiple of MAX_ALIGN */ 15465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm obj_size = (obj_size + MAX_ALIGN - 1) & -MAX_ALIGN; 15565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 15665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (!reserve) 15765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm { 15865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm reserve = pg_size / obj_size / 2; 15965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (!reserve) 16065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm reserve = 16; 16165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm } 16265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 16365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm pool->obj_size = obj_size; 16465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm pool->reserve = reserve; 16565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm pool->chunk_size = (2*reserve*obj_size + pg_size - 1) & -pg_size; 16665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 16765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm expand (pool); 16865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm} 16965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 17065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmHIDDEN void * 17165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmmempool_alloc (struct mempool *pool) 17265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{ 17365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sigset_t saved_sigmask; 17465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm struct object *obj; 17565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 17665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sigprocmask (SIG_SETMASK, &unwi_full_sigmask, &saved_sigmask); 17765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mutex_lock(&pool->lock); 17865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm { 17965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm if (pool->num_free <= pool->reserve) 18065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm expand (pool); 18165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 18265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm assert (pool->num_free > 0); 18365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 18465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm --pool->num_free; 18565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm obj = pool->free_list; 18665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm pool->free_list = obj->next; 18765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm } 18865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mutex_unlock(&pool->lock); 18965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sigprocmask (SIG_SETMASK, &saved_sigmask, NULL); 19065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm return obj; 19165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm} 19265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 19365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmHIDDEN void 19465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmmempool_free (struct mempool *pool, void *object) 19565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{ 19665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sigset_t saved_sigmask; 19765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm 19865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sigprocmask (SIG_SETMASK, &unwi_full_sigmask, &saved_sigmask); 19965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mutex_lock(&pool->lock); 20065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm { 20165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm free_object (pool, object); 20265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm } 20365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm mutex_unlock(&pool->lock); 20465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm sigprocmask (SIG_SETMASK, &saved_sigmask, NULL); 20565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm} 206