chiark / gitweb /
Makefile.am: Use $(mkdir_p) instead of $(mkinstalldirs).
[mLib] / pool.c
1 /* -*-c-*-
2  *
3  * $Id$
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 /*----- Header files ------------------------------------------------------*/
31
32 #include <string.h>
33
34 #include "align.h"
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
53 static void *doalloc(arena *a, pool_chunk **cc, size_t sz)
54 {
55   pool_chunk *c;
56   void *p;
57   size_t csz, ssz;
58
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
65   ALIGN(sz);
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 {
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);
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);
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
112 void *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
127 char *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
137 static void *palloc(arena *a, size_t sz)
138 {
139   pool *p = (pool *)a;
140   return (doalloc(p->pa, &p->c, sz));
141 }
142
143 static void pfree(arena *a, void *p) { return; } /* Trivial */
144
145 static arena_ops pool_ops = { palloc, arena_fakerealloc, pfree, 0 };
146
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
158 void 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
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
176 pool *pool_create(arena *a)
177 {
178   pool_chunk *c = 0;
179   pool *p = doalloc(a, &c, sizeof(pool));
180   pool_init(p, a);
181   p->c = c;
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 pool created by @pool_create@, its memory will be
193  *              deallocated; if it's a subpool or it was initialized by
194  *              @pool_init@, it is emptied and can be used again.
195  */
196
197 void 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
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 -------------------------------------------------*/