chiark / gitweb /
Makefile.am: Use $(mkdir_p) instead of $(mkinstalldirs).
[mLib] / pool.c
CommitLineData
d94be366 1/* -*-c-*-
2 *
eae919b5 3 * $Id$
d94be366 4 *
5 * Resource pool handling
6 *
7 * (c) 2000 Straylight/Edgeware
8 */
9
d4efbcd9 10/*----- Licensing notice --------------------------------------------------*
d94be366 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.
d4efbcd9 18 *
d94be366 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.
d4efbcd9 23 *
d94be366 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
eae919b5 32#include <string.h>
33
c5775f49 34#include "align.h"
d94be366 35#include "alloc.h"
36#include "arena.h"
37#include "pool.h"
38
39/*----- Main code ---------------------------------------------------------*/
40
41/* --- @doalloc@ --- *
42 *
43 * Arguments: @arena *a@ = pointer to arena to allocate memory from
44 * @pool_chunk **cc@ = pointer to chunk list
45 * @size_t sz@ = size of memory wanted
46 *
47 * Returns: Pointer to the allocated block.
48 *
49 * Use: The basic allocator for resource pools. This is also used
50 * during pool creation, hence the slightly bizarre interface.
51 */
52
53static void *doalloc(arena *a, pool_chunk **cc, size_t sz)
54{
55 pool_chunk *c;
56 void *p;
57 size_t csz, ssz;
58
d94be366 59 /* --- See if there's enough space --- *
60 *
61 * The chunks are sorted by available space, so if there's not enough space
62 * in the first chunk there isn't enough space anywhere.
63 */
64
c5775f49 65 ALIGN(sz);
d94be366 66 c = *cc;
67 if (c && c->left >= sz) {
68 p = c->p;
69 c->p += sz;
70 c->left -= sz;
71 *cc = c->next;
72 }
73
74 /* --- Failed to find anything --- *
75 *
76 * I must allocate a new block from the arena, then.
77 */
78
79 else {
c5775f49 80 ssz = sizeof(pool_chunk);
81 ALIGN(ssz);
82 csz = (ssz + sz + POOL_CHUNKSZ - 1); csz -= csz % POOL_CHUNKSZ;
83 c = x_alloc(a, csz);
d94be366 84 p = (char *)c + ssz;
85 c->p = (char *)p + sz;
86 c->left = csz - ssz - sz;
87 }
88
89 /* --- Move this chunk in the list so that it's sorted --- */
90
91 while (*cc && (*cc)->left > c->left)
92 cc = &(*cc)->next;
93 c->next = *cc;
94 *cc = c;
95
96 /* --- Done --- */
97
98 return (p);
d94be366 99}
100
101/* --- @pool_alloc@ --- *
102 *
103 * Arguments: @pool *p@ = pool to allocate from
104 * @size_t sz@ = size of block wanted
105 *
106 * Returns: Pointer to the requested block.
107 *
108 * Use: Allocates memory from a resource pool. Memory is never freed
109 * from pools: it is released when the pool is destroyed.
110 */
111
112void *pool_alloc(pool *p, size_t sz)
113{
114 return (doalloc(p->pa, &p->c, sz));
115}
116
117/* --- @pool_strdup@ --- *
118 *
119 * Arguments: @pool *p@ = pool to allocate from
120 * @const char *s@ = pointer to string
121 *
122 * Returns: A pointer to a copy of the string.
123 *
124 * Use: Allocates a copy of a string.
125 */
126
127char *pool_strdup(pool *p, const char *s)
128{
129 size_t sz = strlen(s) + 1;
130 char *pp = doalloc(p->pa, &p->c, sz);
131 memcpy(pp, s, sz);
132 return (pp);
133}
134
135/* --- Arena operations --- */
136
137static void *palloc(arena *a, size_t sz)
138{
139 pool *p = (pool *)a;
140 return (doalloc(p->pa, &p->c, sz));
141}
142
143static void pfree(arena *a, void *p) { return; } /* Trivial */
144
145static arena_ops pool_ops = { palloc, arena_fakerealloc, pfree, 0 };
146
c5775f49 147/* --- @pool_init@ --- *
148 *
149 * Arguments: @pool *p@ = pointer to the pool structure to initialize
150 * @arena *a@ = pointer to an arena to allocate memory from
151 *
152 * Returns: ---
153 *
154 * Use: Initializes a chunk of memory as a resource pool which is not
155 * a child of any other resource pool.
156 */
157
158void pool_init(pool *p, arena *a)
159{
160 p->a.ops = &pool_ops;
161 p->c = 0;
162 p->r = 0;
163 p->pa = a;
164}
165
d94be366 166/* --- @pool_create@ --- *
167 *
168 * Arguments: @arena *a@ = pointer to an arena to allocate memory from
169 *
170 * Returns: A newly created resource pool.
171 *
172 * Use: Creates a resource pool which is not a child of any other
173 * resource pool.
174 */
175
176pool *pool_create(arena *a)
177{
178 pool_chunk *c = 0;
179 pool *p = doalloc(a, &c, sizeof(pool));
c5775f49 180 pool_init(p, a);
d94be366 181 p->c = c;
d94be366 182 return (p);
183}
184
185/* --- @pool_destroy@ --- *
186 *
187 * Arguments: @pool *p@ = pointer to pool to destroy
188 *
189 * Returns: ---
190 *
191 * Use: Destroys a pool, freeing all of the resources within it. If
c5775f49 192 * this is a pool created by @pool_create@, its memory will be
193 * deallocated; if it's a subpool or it was initialized by
d4efbcd9 194 * @pool_init@, it is emptied and can be used again.
d94be366 195 */
196
197void pool_destroy(pool *p)
198{
199 pool_resource *r, *rr;
200 arena *a;
201 pool_chunk *c, *cc;
202
203 /* --- Dispose of all of the resources --- */
204
205 r = p->r;
206 while (r) {
207 rr = r->next;
208 if (r->destroy)
209 r->destroy(r);
210 r = rr;
211 }
212 p->r = 0;
213
214 /* --- Free all of the memory --- *
215 *
216 * Since root pools are allocated in their own memory, this will free the
217 * root pool block. Subpools are allocated in their parent's memory, so
218 * the pool block itself will be left around.
219 */
220
221 a = p->pa;
222 c = p->c;
223 p->c = 0;
224 while (c) {
225 cc = c->next;
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 -------------------------------------------------*/