chiark / gitweb /
codec, baseconv: Cleanup of the various binary encoding functions.
[mLib] / mem / pool.c
1 /* -*-c-*-
2  *
3  * Resource pool handling
4  *
5  * (c) 2000 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <string.h>
31
32 #include "align.h"
33 #include "alloc.h"
34 #include "arena.h"
35 #include "pool.h"
36
37 /*----- Main code ---------------------------------------------------------*/
38
39 /* --- @doalloc@ --- *
40  *
41  * Arguments:   @arena *a@ = pointer to arena to allocate memory from
42  *              @pool_chunk **cc@ = pointer to chunk list
43  *              @size_t sz@ = size of memory wanted
44  *
45  * Returns:     Pointer to the allocated block.
46  *
47  * Use:         The basic allocator for resource pools.  This is also used
48  *              during pool creation, hence the slightly bizarre interface.
49  */
50
51 static void *doalloc(arena *a, pool_chunk **cc, size_t sz)
52 {
53   pool_chunk *c;
54   void *p;
55   size_t csz, ssz;
56
57   /* --- See if there's enough space --- *
58    *
59    * The chunks are sorted by available space, so if there's not enough space
60    * in the first chunk there isn't enough space anywhere.
61    */
62
63   ALIGN(sz);
64   c = *cc;
65   if (c && c->left >= sz) {
66     p = c->p;
67     c->p += sz;
68     c->left -= sz;
69     *cc = c->next;
70   }
71
72   /* --- Failed to find anything --- *
73    *
74    * I must allocate a new block from the arena, then.
75    */
76
77   else {
78     ssz = sizeof(pool_chunk);
79     ALIGN(ssz);
80     csz = (ssz + sz + POOL_CHUNKSZ - 1); csz -= csz % POOL_CHUNKSZ;
81     c = x_alloc(a, csz);
82     p = (char *)c + ssz;
83     c->p = (char *)p + sz;
84     c->left = csz - ssz - sz;
85   }
86
87   /* --- Move this chunk in the list so that it's sorted --- */
88
89   while (*cc && (*cc)->left > c->left)
90     cc = &(*cc)->next;
91   c->next = *cc;
92   *cc = c;
93
94   /* --- Done --- */
95
96   return (p);
97 }
98
99 /* --- @pool_alloc@ --- *
100  *
101  * Arguments:   @pool *p@ = pool to allocate from
102  *              @size_t sz@ = size of block wanted
103  *
104  * Returns:     Pointer to the requested block.
105  *
106  * Use:         Allocates memory from a resource pool.  Memory is never freed
107  *              from pools: it is released when the pool is destroyed.
108  */
109
110 void *pool_alloc(pool *p, size_t sz)
111 {
112   return (doalloc(p->pa, &p->c, sz));
113 }
114
115 /* --- @pool_strdup@ --- *
116  *
117  * Arguments:   @pool *p@ = pool to allocate from
118  *              @const char *s@ = pointer to string
119  *
120  * Returns:     A pointer to a copy of the string.
121  *
122  * Use:         Allocates a copy of a string.
123  */
124
125 char *pool_strdup(pool *p, const char *s)
126 {
127   size_t sz = strlen(s) + 1;
128   char *pp = doalloc(p->pa, &p->c, sz);
129   memcpy(pp, s, sz);
130   return (pp);
131 }
132
133 /* --- Arena operations --- */
134
135 static void *palloc(arena *a, size_t sz)
136 {
137   pool *p = (pool *)a;
138   return (doalloc(p->pa, &p->c, sz));
139 }
140
141 static void pfree(arena *a, void *p) { return; } /* Trivial */
142
143 static arena_ops pool_ops = { palloc, arena_fakerealloc, pfree, 0 };
144
145 /* --- @pool_init@ --- *
146  *
147  * Arguments:   @pool *p@ = pointer to the pool structure to initialize
148  *              @arena *a@ = pointer to an arena to allocate memory from
149  *
150  * Returns:     ---
151  *
152  * Use:         Initializes a chunk of memory as a resource pool which is not
153  *              a child of any other resource pool.
154  */
155
156 void pool_init(pool *p, arena *a)
157 {
158   p->a.ops = &pool_ops;
159   p->c = 0;
160   p->r = 0;
161   p->pa = a;
162 }
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   pool_init(p, a);
179   p->c = c;
180   return (p);
181 }
182
183 /* --- @pool_destroy@ --- *
184  *
185  * Arguments:   @pool *p@ = pointer to pool to destroy
186  *
187  * Returns:     ---
188  *
189  * Use:         Destroys a pool, freeing all of the resources within it.  If
190  *              this is a pool created by @pool_create@, its memory will be
191  *              deallocated; if it's a subpool or it was initialized by
192  *              @pool_init@, it is emptied and can be used again.
193  */
194
195 void pool_destroy(pool *p)
196 {
197   pool_resource *r, *rr;
198   arena *a;
199   pool_chunk *c, *cc;
200
201   /* --- Dispose of all of the resources --- */
202
203   r = p->r;
204   while (r) {
205     rr = r->next;
206     if (r->destroy)
207       r->destroy(r);
208     r = rr;
209   }
210   p->r = 0;
211
212   /* --- Free all of the memory --- *
213    *
214    * Since root pools are allocated in their own memory, this will free the
215    * root pool block.  Subpools are allocated in their parent's memory, so
216    * the pool block itself will be left around.
217    */
218
219   a = p->pa;
220   c = p->c;
221   p->c = 0;
222   while (c) {
223     cc = c->next;
224     x_free(a, c);
225     c = cc;
226   }
227 }
228
229 /* --- @pool_add@ --- *
230  *
231  * Arguments:   @pool *p@ = pointer to pool to add the resource to
232  *              @pool_resource *r@ = pointer to resource block
233  *              @void (*dfn)(pool_resource *r)@ = destruction function
234  *
235  * Returns:     ---
236  *
237  * Use:         Adds a resource to a pool.
238  */
239
240 void pool_add(pool *p, pool_resource *r, void (*dfn)(pool_resource *r))
241 {
242   POOL_ADD(p, r, dfn);
243 }
244
245 /* --- @pool_sub@ --- *
246  *
247  * Arguments:   @pool *p@ = pointer to parent pool
248  *
249  * Returns:     A new child pool of the parent.
250  *
251  * Use:         Creates a subpool.  The subpool can either be destroyed on
252  *              its own, or will be automatically destroyed at the same time
253  *              as the parent.
254  */
255
256 typedef struct subpool {
257   pool_resource r;
258   pool p;
259 } subpool;
260
261 static void subpool_destroy(pool_resource *r)
262 {
263   subpool *p = (subpool *)r;
264   pool_destroy(&p->p);
265 }
266
267 pool *pool_sub(pool *p)
268 {
269   subpool *pp = pool_alloc(p, sizeof(subpool));
270   POOL_ADD(p, &pp->r, subpool_destroy);
271   pp->p.a.ops = &pool_ops;
272   pp->p.c = 0;
273   pp->p.r = 0;
274   pp->p.pa = p->pa;
275   return (&pp->p);
276 }
277
278 /*----- That's all, folks -------------------------------------------------*/