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