@@@ fltfmt mess
[mLib] / mem / pool.c
CommitLineData
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 66static 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
128void *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
141char *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
152static 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
159static void pfree(arena *a, void *p) { return; } /* Trivial */
160
161static 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
173pool *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
198void 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
242void 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
258typedef struct subpool {
259 pool_resource r;
260 pool p;
261} subpool;
262
263static void subpool_destroy(pool_resource *r)
264{
265 subpool *p = (subpool *)r;
266 pool_destroy(&p->p);
267}
268
269pool *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 -------------------------------------------------*/