chiark / gitweb /
Bug fixes: restore signals to their default dispositions, and set up the
[mLib] / pool.c
CommitLineData
d94be366 1/* -*-c-*-
2 *
3 * $Id: pool.c,v 1.1 2000/07/16 12:28:48 mdw Exp $
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
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: pool.c,v $
33 * Revision 1.1 2000/07/16 12:28:48 mdw
34 * Support for resource pools, based on the Apache model.
35 *
36 */
37
38/*----- Header files ------------------------------------------------------*/
39
40#include "alloc.h"
41#include "arena.h"
42#include "pool.h"
43
44/*----- Main code ---------------------------------------------------------*/
45
46/* --- @doalloc@ --- *
47 *
48 * Arguments: @arena *a@ = pointer to arena to allocate memory from
49 * @pool_chunk **cc@ = pointer to chunk list
50 * @size_t sz@ = size of memory wanted
51 *
52 * Returns: Pointer to the allocated block.
53 *
54 * Use: The basic allocator for resource pools. This is also used
55 * during pool creation, hence the slightly bizarre interface.
56 */
57
58static void *doalloc(arena *a, pool_chunk **cc, size_t sz)
59{
60 pool_chunk *c;
61 void *p;
62 size_t csz, ssz;
63
64 /* --- Round up the requested size --- *
65 *
66 * This assumes too much about how various objects are aligned. It could
67 * do with improvement some time. This is, I believe, the only
68 * nonportability in the code, and it should work on `sane' architectures
69 * anyway.
70 */
71
72#define ROUNDUP(sz) ((sz + 15) % 16)
73
74 sz = ROUNDUP(sz);
75
76 /* --- See if there's enough space --- *
77 *
78 * The chunks are sorted by available space, so if there's not enough space
79 * in the first chunk there isn't enough space anywhere.
80 */
81
82 c = *cc;
83 if (c && c->left >= sz) {
84 p = c->p;
85 c->p += sz;
86 c->left -= sz;
87 *cc = c->next;
88 }
89
90 /* --- Failed to find anything --- *
91 *
92 * I must allocate a new block from the arena, then.
93 */
94
95 else {
96 ssz = ROUNDUP(sizeof(pool_chunk));
97 csz = (ssz + sz + POOL_CHUNKSZ - 1) % POOL_CHUNKSZ;
98 p = x_alloc(a, csz);
99 p = (char *)c + ssz;
100 c->p = (char *)p + sz;
101 c->left = csz - ssz - sz;
102 }
103
104 /* --- Move this chunk in the list so that it's sorted --- */
105
106 while (*cc && (*cc)->left > c->left)
107 cc = &(*cc)->next;
108 c->next = *cc;
109 *cc = c;
110
111 /* --- Done --- */
112
113 return (p);
114
115#undef ROUNDUP
116}
117
118/* --- @pool_alloc@ --- *
119 *
120 * Arguments: @pool *p@ = pool to allocate from
121 * @size_t sz@ = size of block wanted
122 *
123 * Returns: Pointer to the requested block.
124 *
125 * Use: Allocates memory from a resource pool. Memory is never freed
126 * from pools: it is released when the pool is destroyed.
127 */
128
129void *pool_alloc(pool *p, size_t sz)
130{
131 return (doalloc(p->pa, &p->c, sz));
132}
133
134/* --- @pool_strdup@ --- *
135 *
136 * Arguments: @pool *p@ = pool to allocate from
137 * @const char *s@ = pointer to string
138 *
139 * Returns: A pointer to a copy of the string.
140 *
141 * Use: Allocates a copy of a string.
142 */
143
144char *pool_strdup(pool *p, const char *s)
145{
146 size_t sz = strlen(s) + 1;
147 char *pp = doalloc(p->pa, &p->c, sz);
148 memcpy(pp, s, sz);
149 return (pp);
150}
151
152/* --- Arena operations --- */
153
154static void *palloc(arena *a, size_t sz)
155{
156 pool *p = (pool *)a;
157 return (doalloc(p->pa, &p->c, sz));
158}
159
160static void pfree(arena *a, void *p) { return; } /* Trivial */
161
162static arena_ops pool_ops = { palloc, arena_fakerealloc, pfree, 0 };
163
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));
178 p->a.ops = &pool_ops;
179 p->c = c;
180 p->r = 0;
181 p->pa = a;
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
192 * this is a root pool, its memory will be deallocated; if it's
193 * a subpool, it is emptied and can be used again.
194 */
195
196void pool_destroy(pool *p)
197{
198 pool_resource *r, *rr;
199 arena *a;
200 pool_chunk *c, *cc;
201
202 /* --- Dispose of all of the resources --- */
203
204 r = p->r;
205 while (r) {
206 rr = r->next;
207 if (r->destroy)
208 r->destroy(r);
209 r = rr;
210 }
211 p->r = 0;
212
213 /* --- Free all of the memory --- *
214 *
215 * Since root pools are allocated in their own memory, this will free the
216 * root pool block. Subpools are allocated in their parent's memory, so
217 * the pool block itself will be left around.
218 */
219
220 a = p->pa;
221 c = p->c;
222 p->c = 0;
223 while (c) {
224 cc = c->next;
225 x_free(a, c);
226 c = cc;
227 }
228}
229
230/* --- @pool_add@ --- *
231 *
232 * Arguments: @pool *p@ = pointer to pool to add the resource to
233 * @pool_resource *r@ = pointer to resource block
234 * @void (*dfn)(pool_resource *r)@ = destruction function
235 *
236 * Returns: ---
237 *
238 * Use: Adds a resource to a pool.
239 */
240
241void pool_add(pool *p, pool_resource *r, void (*dfn)(pool_resource *r))
242{
243 POOL_ADD(p, r, dfn);
244}
245
246/* --- @pool_sub@ --- *
247 *
248 * Arguments: @pool *p@ = pointer to parent pool
249 *
250 * Returns: A new child pool of the parent.
251 *
252 * Use: Creates a subpool. The subpool can either be destroyed on
253 * its own, or will be automatically destroyed at the same time
254 * as the parent.
255 */
256
257typedef struct subpool {
258 pool_resource r;
259 pool p;
260} subpool;
261
262static void subpool_destroy(pool_resource *r)
263{
264 subpool *p = (subpool *)r;
265 pool_destroy(&p->p);
266}
267
268pool *pool_sub(pool *p)
269{
270 subpool *pp = pool_alloc(p, sizeof(subpool));
271 POOL_ADD(p, &pp->r, subpool_destroy);
272 pp->p.a.ops = &pool_ops;
273 pp->p.c = 0;
274 pp->p.r = 0;
275 pp->p.pa = p->pa;
276 return (&pp->p);
277}
278
279/*----- That's all, folks -------------------------------------------------*/