Commit | Line | Data |
---|---|---|
d94be366 | 1 | /* -*-c-*- |
2 | * | |
d94be366 | 3 | * Resource pool handling |
4 | * | |
5 | * (c) 2000 Straylight/Edgeware | |
6 | */ | |
7 | ||
d4efbcd9 | 8 | /*----- Licensing notice --------------------------------------------------* |
d94be366 | 9 | * |
10 | * This file is part of the mLib utilities library. | |
11 | * | |
12 | * mLib is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU Library General Public License as | |
14 | * published by the Free Software Foundation; either version 2 of the | |
15 | * License, or (at your option) any later version. | |
d4efbcd9 | 16 | * |
d94be366 | 17 | * mLib is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU Library General Public License for more details. | |
d4efbcd9 | 21 | * |
d94be366 | 22 | * You should have received a copy of the GNU Library General Public |
23 | * License along with mLib; if not, write to the Free | |
24 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
25 | * MA 02111-1307, USA. | |
26 | */ | |
27 | ||
d94be366 | 28 | /*----- Header files ------------------------------------------------------*/ |
29 | ||
b1a20bee MW |
30 | #include "config.h" |
31 | ||
eae919b5 | 32 | #include <string.h> |
33 | ||
b1a20bee MW |
34 | #ifdef HAVE_VALGRIND_VALGRIND_H |
35 | # include <valgrind/valgrind.h> | |
36 | # include <valgrind/memcheck.h> | |
37 | # define VG(x) x | |
38 | #else | |
39 | # define VG(x) | |
40 | #endif | |
41 | ||
c5775f49 | 42 | #include "align.h" |
d94be366 | 43 | #include "alloc.h" |
44 | #include "arena.h" | |
45 | #include "pool.h" | |
46 | ||
b1a20bee MW |
47 | /*----- Constants ---------------------------------------------------------*/ |
48 | ||
49 | #define REDZONE_SIZE (2*ALIGNOF(union align)) | |
50 | ||
d94be366 | 51 | /*----- Main code ---------------------------------------------------------*/ |
52 | ||
53 | /* --- @doalloc@ --- * | |
54 | * | |
55 | * Arguments: @arena *a@ = pointer to arena to allocate memory from | |
56 | * @pool_chunk **cc@ = pointer to chunk list | |
57 | * @size_t sz@ = size of memory wanted | |
b1a20bee | 58 | * @unsigned f@ = flags (@PF_...@) |
d94be366 | 59 | * |
60 | * Returns: Pointer to the allocated block. | |
61 | * | |
62 | * Use: The basic allocator for resource pools. This is also used | |
63 | * during pool creation, hence the slightly bizarre interface. | |
64 | */ | |
65 | ||
b1a20bee | 66 | static void *doalloc(arena *a, pool_chunk **cc, size_t sz, unsigned f) |
d94be366 | 67 | { |
68 | pool_chunk *c; | |
69 | void *p; | |
70 | size_t csz, ssz; | |
b1a20bee MW |
71 | size_t redsz = VG( f&PF_VALGRIND ? REDZONE_SIZE : ) 0; |
72 | VG( size_t sz0 = sz; ) | |
d94be366 | 73 | |
d94be366 | 74 | /* --- See if there's enough space --- * |
75 | * | |
76 | * The chunks are sorted by available space, so if there's not enough space | |
77 | * in the first chunk there isn't enough space anywhere. | |
78 | */ | |
79 | ||
b1a20bee | 80 | ALIGN(sz); sz += redsz; |
d94be366 | 81 | c = *cc; |
82 | if (c && c->left >= sz) { | |
b1a20bee MW |
83 | p = c->p; VG( if (f&PF_VALGRIND) VALGRIND_MEMPOOL_ALLOC(c, p, sz0); ) |
84 | c->p += sz; c->left -= sz; | |
d94be366 | 85 | *cc = c->next; |
86 | } | |
87 | ||
88 | /* --- Failed to find anything --- * | |
89 | * | |
90 | * I must allocate a new block from the arena, then. | |
91 | */ | |
92 | ||
93 | else { | |
c5775f49 | 94 | ssz = sizeof(pool_chunk); |
95 | ALIGN(ssz); | |
b1a20bee | 96 | csz = (ssz + redsz + sz + POOL_CHUNKSZ - 1); csz -= csz % POOL_CHUNKSZ; |
c5775f49 | 97 | c = x_alloc(a, csz); |
b1a20bee MW |
98 | p = (unsigned char *)c + ssz + redsz; |
99 | VG( if (f&PF_VALGRIND) { | |
100 | VALGRIND_CREATE_MEMPOOL(c, REDZONE_SIZE, 0); | |
101 | VALGRIND_MEMPOOL_ALLOC(c, p, sz0); | |
102 | } ) | |
103 | c->p = (unsigned char *)p + sz; | |
104 | c->left = csz - ssz - redsz - sz; | |
d94be366 | 105 | } |
106 | ||
107 | /* --- Move this chunk in the list so that it's sorted --- */ | |
108 | ||
b1a20bee MW |
109 | while (*cc && (*cc)->left > c->left) cc = &(*cc)->next; |
110 | c->next = *cc; *cc = c; | |
d94be366 | 111 | |
112 | /* --- Done --- */ | |
113 | ||
114 | return (p); | |
d94be366 | 115 | } |
116 | ||
117 | /* --- @pool_alloc@ --- * | |
118 | * | |
119 | * Arguments: @pool *p@ = pool to allocate from | |
120 | * @size_t sz@ = size of block wanted | |
121 | * | |
122 | * Returns: Pointer to the requested block. | |
123 | * | |
124 | * Use: Allocates memory from a resource pool. Memory is never freed | |
125 | * from pools: it is released when the pool is destroyed. | |
126 | */ | |
127 | ||
128 | void *pool_alloc(pool *p, size_t sz) | |
b1a20bee | 129 | { return (doalloc(p->pa, &p->c, sz, p->f)); } |
d94be366 | 130 | |
131 | /* --- @pool_strdup@ --- * | |
132 | * | |
133 | * Arguments: @pool *p@ = pool to allocate from | |
134 | * @const char *s@ = pointer to string | |
135 | * | |
136 | * Returns: A pointer to a copy of the string. | |
137 | * | |
138 | * Use: Allocates a copy of a string. | |
139 | */ | |
140 | ||
141 | char *pool_strdup(pool *p, const char *s) | |
142 | { | |
143 | size_t sz = strlen(s) + 1; | |
b1a20bee MW |
144 | char *pp = doalloc(p->pa, &p->c, sz, p->f); |
145 | ||
d94be366 | 146 | memcpy(pp, s, sz); |
147 | return (pp); | |
148 | } | |
149 | ||
150 | /* --- Arena operations --- */ | |
151 | ||
152 | static void *palloc(arena *a, size_t sz) | |
153 | { | |
154 | pool *p = (pool *)a; | |
b1a20bee MW |
155 | |
156 | return (doalloc(p->pa, &p->c, sz, p->f)); | |
d94be366 | 157 | } |
158 | ||
159 | static void pfree(arena *a, void *p) { return; } /* Trivial */ | |
160 | ||
161 | static arena_ops pool_ops = { palloc, arena_fakerealloc, pfree, 0 }; | |
162 | ||
163 | /* --- @pool_create@ --- * | |
164 | * | |
165 | * Arguments: @arena *a@ = pointer to an arena to allocate memory from | |
166 | * | |
167 | * Returns: A newly created resource pool. | |
168 | * | |
169 | * Use: Creates a resource pool which is not a child of any other | |
170 | * resource pool. | |
171 | */ | |
172 | ||
173 | pool *pool_create(arena *a) | |
174 | { | |
175 | pool_chunk *c = 0; | |
b1a20bee MW |
176 | pool *p; |
177 | unsigned f = 0; | |
178 | ||
179 | VG( if (RUNNING_ON_VALGRIND) f |= PF_VALGRIND; ) | |
180 | p = doalloc(a, &c, sizeof(pool), f); | |
181 | p->c = c; p->r = 0; p->pa = a; p->f = f; | |
182 | p->a.ops = &pool_ops; | |
d94be366 | 183 | return (p); |
184 | } | |
185 | ||
186 | /* --- @pool_destroy@ --- * | |
187 | * | |
188 | * Arguments: @pool *p@ = pointer to pool to destroy | |
189 | * | |
190 | * Returns: --- | |
191 | * | |
192 | * Use: Destroys a pool, freeing all of the resources within it. If | |
c5775f49 | 193 | * this is a pool created by @pool_create@, its memory will be |
194 | * deallocated; if it's a subpool or it was initialized by | |
d4efbcd9 | 195 | * @pool_init@, it is emptied and can be used again. |
d94be366 | 196 | */ |
197 | ||
198 | void pool_destroy(pool *p) | |
199 | { | |
200 | pool_resource *r, *rr; | |
201 | arena *a; | |
202 | pool_chunk *c, *cc; | |
203 | ||
204 | /* --- Dispose of all of the resources --- */ | |
205 | ||
206 | r = p->r; | |
207 | while (r) { | |
208 | rr = r->next; | |
209 | if (r->destroy) | |
210 | r->destroy(r); | |
211 | r = rr; | |
212 | } | |
213 | p->r = 0; | |
214 | ||
215 | /* --- Free all of the memory --- * | |
216 | * | |
217 | * Since root pools are allocated in their own memory, this will free the | |
218 | * root pool block. Subpools are allocated in their parent's memory, so | |
219 | * the pool block itself will be left around. | |
220 | */ | |
221 | ||
b1a20bee | 222 | a = p->pa; c = p->c; p->c = 0; |
d94be366 | 223 | while (c) { |
224 | cc = c->next; | |
b1a20bee | 225 | VG( if (p->f&PF_VALGRIND) VALGRIND_DESTROY_MEMPOOL(c); ) |
d94be366 | 226 | x_free(a, c); |
227 | c = cc; | |
228 | } | |
229 | } | |
230 | ||
231 | /* --- @pool_add@ --- * | |
232 | * | |
233 | * Arguments: @pool *p@ = pointer to pool to add the resource to | |
234 | * @pool_resource *r@ = pointer to resource block | |
235 | * @void (*dfn)(pool_resource *r)@ = destruction function | |
236 | * | |
237 | * Returns: --- | |
238 | * | |
239 | * Use: Adds a resource to a pool. | |
240 | */ | |
241 | ||
242 | void pool_add(pool *p, pool_resource *r, void (*dfn)(pool_resource *r)) | |
243 | { | |
244 | POOL_ADD(p, r, dfn); | |
245 | } | |
246 | ||
247 | /* --- @pool_sub@ --- * | |
248 | * | |
249 | * Arguments: @pool *p@ = pointer to parent pool | |
250 | * | |
251 | * Returns: A new child pool of the parent. | |
252 | * | |
253 | * Use: Creates a subpool. The subpool can either be destroyed on | |
254 | * its own, or will be automatically destroyed at the same time | |
255 | * as the parent. | |
256 | */ | |
257 | ||
258 | typedef struct subpool { | |
259 | pool_resource r; | |
260 | pool p; | |
261 | } subpool; | |
262 | ||
263 | static void subpool_destroy(pool_resource *r) | |
264 | { | |
265 | subpool *p = (subpool *)r; | |
266 | pool_destroy(&p->p); | |
267 | } | |
268 | ||
269 | pool *pool_sub(pool *p) | |
270 | { | |
271 | subpool *pp = pool_alloc(p, sizeof(subpool)); | |
272 | POOL_ADD(p, &pp->r, subpool_destroy); | |
273 | pp->p.a.ops = &pool_ops; | |
274 | pp->p.c = 0; | |
275 | pp->p.r = 0; | |
276 | pp->p.pa = p->pa; | |
277 | return (&pp->p); | |
278 | } | |
279 | ||
280 | /*----- That's all, folks -------------------------------------------------*/ |