1 1.1 haad /* $NetBSD: pool-fast.c,v 1.1.1.2 2009/12/02 00:26:09 haad Exp $ */ 2 1.1 haad 3 1.1 haad /* 4 1.1 haad * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 1.1 haad * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. 6 1.1 haad * 7 1.1 haad * This file is part of the device-mapper userspace tools. 8 1.1 haad * 9 1.1 haad * This copyrighted material is made available to anyone wishing to use, 10 1.1 haad * modify, copy, or redistribute it subject to the terms and conditions 11 1.1 haad * of the GNU Lesser General Public License v.2.1. 12 1.1 haad * 13 1.1 haad * You should have received a copy of the GNU Lesser General Public License 14 1.1 haad * along with this program; if not, write to the Free Software Foundation, 15 1.1 haad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 1.1 haad */ 17 1.1 haad 18 1.1 haad #include "dmlib.h" 19 1.1 haad 20 1.1 haad struct chunk { 21 1.1 haad char *begin, *end; 22 1.1 haad struct chunk *prev; 23 1.1 haad }; 24 1.1 haad 25 1.1 haad struct dm_pool { 26 1.1.1.2 haad struct dm_list list; 27 1.1 haad struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free 28 1.1 haad list to stop 'bobbling' */ 29 1.1 haad size_t chunk_size; 30 1.1 haad size_t object_len; 31 1.1 haad unsigned object_alignment; 32 1.1 haad }; 33 1.1 haad 34 1.1 haad void _align_chunk(struct chunk *c, unsigned alignment); 35 1.1 haad struct chunk *_new_chunk(struct dm_pool *p, size_t s); 36 1.1 haad 37 1.1 haad /* by default things come out aligned for doubles */ 38 1.1 haad #define DEFAULT_ALIGNMENT __alignof__ (double) 39 1.1 haad 40 1.1 haad struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint) 41 1.1 haad { 42 1.1 haad size_t new_size = 1024; 43 1.1 haad struct dm_pool *p = dm_malloc(sizeof(*p)); 44 1.1 haad 45 1.1 haad if (!p) { 46 1.1 haad log_error("Couldn't create memory pool %s (size %" 47 1.1 haad PRIsize_t ")", name, sizeof(*p)); 48 1.1 haad return 0; 49 1.1 haad } 50 1.1 haad memset(p, 0, sizeof(*p)); 51 1.1 haad 52 1.1 haad /* round chunk_hint up to the next power of 2 */ 53 1.1 haad p->chunk_size = chunk_hint + sizeof(struct chunk); 54 1.1 haad while (new_size < p->chunk_size) 55 1.1 haad new_size <<= 1; 56 1.1 haad p->chunk_size = new_size; 57 1.1.1.2 haad dm_list_add(&_dm_pools, &p->list); 58 1.1 haad return p; 59 1.1 haad } 60 1.1 haad 61 1.1 haad void dm_pool_destroy(struct dm_pool *p) 62 1.1 haad { 63 1.1 haad struct chunk *c, *pr; 64 1.1 haad dm_free(p->spare_chunk); 65 1.1 haad c = p->chunk; 66 1.1 haad while (c) { 67 1.1 haad pr = c->prev; 68 1.1 haad dm_free(c); 69 1.1 haad c = pr; 70 1.1 haad } 71 1.1 haad 72 1.1.1.2 haad dm_list_del(&p->list); 73 1.1 haad dm_free(p); 74 1.1 haad } 75 1.1 haad 76 1.1 haad void *dm_pool_alloc(struct dm_pool *p, size_t s) 77 1.1 haad { 78 1.1 haad return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT); 79 1.1 haad } 80 1.1 haad 81 1.1 haad void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment) 82 1.1 haad { 83 1.1 haad struct chunk *c = p->chunk; 84 1.1 haad void *r; 85 1.1 haad 86 1.1 haad /* realign begin */ 87 1.1 haad if (c) 88 1.1 haad _align_chunk(c, alignment); 89 1.1 haad 90 1.1 haad /* have we got room ? */ 91 1.1 haad if (!c || (c->begin > c->end) || (c->end - c->begin < s)) { 92 1.1 haad /* allocate new chunk */ 93 1.1 haad size_t needed = s + alignment + sizeof(struct chunk); 94 1.1 haad c = _new_chunk(p, (needed > p->chunk_size) ? 95 1.1 haad needed : p->chunk_size); 96 1.1 haad 97 1.1 haad if (!c) 98 1.1 haad return NULL; 99 1.1 haad 100 1.1 haad _align_chunk(c, alignment); 101 1.1 haad } 102 1.1 haad 103 1.1 haad r = c->begin; 104 1.1 haad c->begin += s; 105 1.1 haad return r; 106 1.1 haad } 107 1.1 haad 108 1.1 haad void dm_pool_empty(struct dm_pool *p) 109 1.1 haad { 110 1.1 haad struct chunk *c; 111 1.1 haad 112 1.1 haad for (c = p->chunk; c && c->prev; c = c->prev) 113 1.1 haad ; 114 1.1 haad 115 1.1 haad if (c) 116 1.1 haad dm_pool_free(p, (char *) (c + 1)); 117 1.1 haad } 118 1.1 haad 119 1.1 haad void dm_pool_free(struct dm_pool *p, void *ptr) 120 1.1 haad { 121 1.1 haad struct chunk *c = p->chunk; 122 1.1 haad 123 1.1 haad while (c) { 124 1.1 haad if (((char *) c < (char *) ptr) && 125 1.1 haad ((char *) c->end > (char *) ptr)) { 126 1.1 haad c->begin = ptr; 127 1.1 haad break; 128 1.1 haad } 129 1.1 haad 130 1.1 haad if (p->spare_chunk) 131 1.1 haad dm_free(p->spare_chunk); 132 1.1 haad p->spare_chunk = c; 133 1.1 haad c = c->prev; 134 1.1 haad } 135 1.1 haad 136 1.1 haad if (!c) 137 1.1 haad log_error("Internal error: pool_free asked to free pointer " 138 1.1 haad "not in pool"); 139 1.1 haad else 140 1.1 haad p->chunk = c; 141 1.1 haad } 142 1.1 haad 143 1.1 haad int dm_pool_begin_object(struct dm_pool *p, size_t hint) 144 1.1 haad { 145 1.1 haad struct chunk *c = p->chunk; 146 1.1 haad const size_t align = DEFAULT_ALIGNMENT; 147 1.1 haad 148 1.1 haad p->object_len = 0; 149 1.1 haad p->object_alignment = align; 150 1.1 haad 151 1.1 haad if (c) 152 1.1 haad _align_chunk(c, align); 153 1.1 haad 154 1.1 haad if (!c || (c->begin > c->end) || (c->end - c->begin < hint)) { 155 1.1 haad /* allocate a new chunk */ 156 1.1 haad c = _new_chunk(p, 157 1.1 haad hint > (p->chunk_size - sizeof(struct chunk)) ? 158 1.1 haad hint + sizeof(struct chunk) + align : 159 1.1 haad p->chunk_size); 160 1.1 haad 161 1.1 haad if (!c) 162 1.1 haad return 0; 163 1.1 haad 164 1.1 haad _align_chunk(c, align); 165 1.1 haad } 166 1.1 haad 167 1.1 haad return 1; 168 1.1 haad } 169 1.1 haad 170 1.1 haad int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta) 171 1.1 haad { 172 1.1 haad struct chunk *c = p->chunk, *nc; 173 1.1 haad 174 1.1 haad if (!delta) 175 1.1 haad delta = strlen(extra); 176 1.1 haad 177 1.1 haad if (c->end - (c->begin + p->object_len) < delta) { 178 1.1 haad /* move into a new chunk */ 179 1.1 haad if (p->object_len + delta > (p->chunk_size / 2)) 180 1.1 haad nc = _new_chunk(p, (p->object_len + delta) * 2); 181 1.1 haad else 182 1.1 haad nc = _new_chunk(p, p->chunk_size); 183 1.1 haad 184 1.1 haad if (!nc) 185 1.1 haad return 0; 186 1.1 haad 187 1.1 haad _align_chunk(p->chunk, p->object_alignment); 188 1.1 haad memcpy(p->chunk->begin, c->begin, p->object_len); 189 1.1 haad c = p->chunk; 190 1.1 haad } 191 1.1 haad 192 1.1 haad memcpy(c->begin + p->object_len, extra, delta); 193 1.1 haad p->object_len += delta; 194 1.1 haad return 1; 195 1.1 haad } 196 1.1 haad 197 1.1 haad void *dm_pool_end_object(struct dm_pool *p) 198 1.1 haad { 199 1.1 haad struct chunk *c = p->chunk; 200 1.1 haad void *r = c->begin; 201 1.1 haad c->begin += p->object_len; 202 1.1 haad p->object_len = 0u; 203 1.1 haad p->object_alignment = DEFAULT_ALIGNMENT; 204 1.1 haad return r; 205 1.1 haad } 206 1.1 haad 207 1.1 haad void dm_pool_abandon_object(struct dm_pool *p) 208 1.1 haad { 209 1.1 haad p->object_len = 0; 210 1.1 haad p->object_alignment = DEFAULT_ALIGNMENT; 211 1.1 haad } 212 1.1 haad 213 1.1 haad void _align_chunk(struct chunk *c, unsigned alignment) 214 1.1 haad { 215 1.1 haad c->begin += alignment - ((unsigned long) c->begin & (alignment - 1)); 216 1.1 haad } 217 1.1 haad 218 1.1 haad struct chunk *_new_chunk(struct dm_pool *p, size_t s) 219 1.1 haad { 220 1.1 haad struct chunk *c; 221 1.1 haad 222 1.1 haad if (p->spare_chunk && 223 1.1 haad ((p->spare_chunk->end - (char *) p->spare_chunk) >= s)) { 224 1.1 haad /* reuse old chunk */ 225 1.1 haad c = p->spare_chunk; 226 1.1 haad p->spare_chunk = 0; 227 1.1 haad } else { 228 1.1 haad if (!(c = dm_malloc(s))) { 229 1.1 haad log_error("Out of memory. Requested %" PRIsize_t 230 1.1 haad " bytes.", s); 231 1.1 haad return NULL; 232 1.1 haad } 233 1.1 haad 234 1.1 haad c->end = (char *) c + s; 235 1.1 haad } 236 1.1 haad 237 1.1 haad c->prev = p->chunk; 238 1.1 haad c->begin = (char *) (c + 1); 239 1.1 haad p->chunk = c; 240 1.1 haad 241 1.1 haad return c; 242 1.1 haad } 243