1/* libunwind - a platform-independent unwind library 2 Copyright (C) 2002-2003, 2005 Hewlett-Packard Co 3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 4 Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com> 5 6This file is part of libunwind. 7 8Permission is hereby granted, free of charge, to any person obtaining 9a copy of this software and associated documentation files (the 10"Software"), to deal in the Software without restriction, including 11without limitation the rights to use, copy, modify, merge, publish, 12distribute, sublicense, and/or sell copies of the Software, and to 13permit persons to whom the Software is furnished to do so, subject to 14the following conditions: 15 16The above copyright notice and this permission notice shall be 17included in all copies or substantial portions of the Software. 18 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 26 27#include "libunwind_i.h" 28 29/* From GCC docs: ``Gcc also provides a target specific macro 30 * __BIGGEST_ALIGNMENT__, which is the largest alignment ever used for any data 31 * type on the target machine you are compiling for.'' */ 32#ifdef __BIGGEST_ALIGNMENT__ 33# define MAX_ALIGN __BIGGEST_ALIGNMENT__ 34#else 35/* Crude hack to check that MAX_ALIGN is power-of-two. 36 * sizeof(long double) = 12 on i386. */ 37# define MAX_ALIGN_(n) (n < 8 ? 8 : \ 38 n < 16 ? 16 : n) 39# define MAX_ALIGN MAX_ALIGN_(sizeof (long double)) 40#endif 41 42static char sos_memory[SOS_MEMORY_SIZE] ALIGNED(MAX_ALIGN); 43static size_t sos_memory_freepos; 44static size_t pg_size; 45 46HIDDEN void * 47sos_alloc (size_t size) 48{ 49 size_t pos; 50 51 size = UNW_ALIGN(size, MAX_ALIGN); 52 53#if defined(__GNUC__) && defined(HAVE_FETCH_AND_ADD) 54 /* Assume `sos_memory' is suitably aligned. */ 55 assert(((uintptr_t) &sos_memory[0] & (MAX_ALIGN-1)) == 0); 56 57 pos = fetch_and_add (&sos_memory_freepos, size); 58#else 59 static define_lock (sos_lock); 60 intrmask_t saved_mask; 61 62 lock_acquire (&sos_lock, saved_mask); 63 { 64 /* No assumptions about `sos_memory' alignment. */ 65 if (sos_memory_freepos == 0) 66 { 67 unsigned align = UNW_ALIGN((uintptr_t) &sos_memory[0], MAX_ALIGN) 68 - (uintptr_t) &sos_memory[0]; 69 sos_memory_freepos = align; 70 } 71 pos = sos_memory_freepos; 72 sos_memory_freepos += size; 73 } 74 lock_release (&sos_lock, saved_mask); 75#endif 76 77 assert (((uintptr_t) &sos_memory[pos] & (MAX_ALIGN-1)) == 0); 78 assert ((pos+size) <= SOS_MEMORY_SIZE); 79 80 return &sos_memory[pos]; 81} 82 83/* Must be called while holding the mempool lock. */ 84 85static void 86free_object (struct mempool *pool, void *object) 87{ 88 struct object *obj = object; 89 90 obj->next = pool->free_list; 91 pool->free_list = obj; 92 ++pool->num_free; 93} 94 95static void 96add_memory (struct mempool *pool, char *mem, size_t size, size_t obj_size) 97{ 98 char *obj; 99 100 for (obj = mem; obj <= mem + size - obj_size; obj += obj_size) 101 free_object (pool, obj); 102} 103 104static void 105expand (struct mempool *pool) 106{ 107 size_t size; 108 char *mem; 109 110 size = pool->chunk_size; 111 GET_MEMORY (mem, size); 112 if (!mem) 113 { 114 size = UNW_ALIGN(pool->obj_size, pg_size); 115 GET_MEMORY (mem, size); 116 if (!mem) 117 { 118 /* last chance: try to allocate one object from the SOS memory */ 119 size = pool->obj_size; 120 mem = sos_alloc (size); 121 } 122 } 123 add_memory (pool, mem, size, pool->obj_size); 124} 125 126HIDDEN void 127mempool_init (struct mempool *pool, size_t obj_size, size_t reserve) 128{ 129 if (pg_size == 0) 130 pg_size = getpagesize (); 131 132 memset (pool, 0, sizeof (*pool)); 133 134 lock_init (&pool->lock); 135 136 /* round object-size up to integer multiple of MAX_ALIGN */ 137 obj_size = UNW_ALIGN(obj_size, MAX_ALIGN); 138 139 if (!reserve) 140 { 141 reserve = pg_size / obj_size / 4; 142 if (!reserve) 143 reserve = 16; 144 } 145 146 pool->obj_size = obj_size; 147 pool->reserve = reserve; 148 pool->chunk_size = UNW_ALIGN(2*reserve*obj_size, pg_size); 149 150 expand (pool); 151} 152 153HIDDEN void * 154mempool_alloc (struct mempool *pool) 155{ 156 intrmask_t saved_mask; 157 struct object *obj; 158 159 lock_acquire (&pool->lock, saved_mask); 160 { 161 if (pool->num_free <= pool->reserve) 162 expand (pool); 163 164 assert (pool->num_free > 0); 165 166 --pool->num_free; 167 obj = pool->free_list; 168 pool->free_list = obj->next; 169 } 170 lock_release (&pool->lock, saved_mask); 171 return obj; 172} 173 174HIDDEN void 175mempool_free (struct mempool *pool, void *object) 176{ 177 intrmask_t saved_mask; 178 179 lock_acquire (&pool->lock, saved_mask); 180 { 181 free_object (pool, object); 182 } 183 lock_release (&pool->lock, saved_mask); 184} 185