chiark / gitweb /
New feature: watch a file for changes.
[mLib] / pool.c
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
58 static 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
129 void *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
144 char *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
154 static void *palloc(arena *a, size_t sz)
155 {
156   pool *p = (pool *)a;
157   return (doalloc(p->pa, &p->c, sz));
158 }
159
160 static void pfree(arena *a, void *p) { return; } /* Trivial */
161
162 static 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
174 pool *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
196 void 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
241 void 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
257 typedef struct subpool {
258   pool_resource r;
259   pool p;
260 } subpool;
261
262 static void subpool_destroy(pool_resource *r)
263 {
264   subpool *p = (subpool *)r;
265   pool_destroy(&p->p);
266 }
267
268 pool *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 -------------------------------------------------*/