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