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