3 * Resource pool handling
5 * (c) 2000 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
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.
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.
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,
35 /*----- Header files ------------------------------------------------------*/
47 /*----- Data structures ---------------------------------------------------*/
49 #define POOL_CHUNKSZ 65536
51 typedef struct pool_chunk {
52 unsigned char *p; /* Free area in this chunk */
54 size_t sz; /* Amount of memory left */
55 struct pool_chunk *next; /* Link to next dead chunk */
59 typedef struct pool_resource {
60 struct pool_resource *next; /* Next resource in the chain */
61 void (*destroy)(struct pool_resource */*r*/); /* Destruction function */
65 arena a; /* The arena for allocating memory */
66 pool_chunk *active; /* Most recent memory chunk */
67 pool_resource *resources; /* Head of resource list */
68 arena *pa; /* Arena for real allocation */
69 unsigned f; /* Flags */
70 #define PF_VALGRIND 1u /* Special Valgrind hacks active */
71 #define PF_SUBPOOL 2u /* Pool is a subpool */
72 size_t lastsz; /* Size of most recent allocation */
73 pool_chunk **live; /* Chunks, max-heap by space left */
74 size_t nlive; /* Number of chunks in the heap */
75 size_t livesz; /* Allocated size of heap vector */
76 pool_chunk *dead; /* List of dead chunks */
79 typedef struct pool_file {
80 pool_resource r; /* A pool resource record */
81 FILE *fp; /* The actual file handle */
84 /*----- Basic pool management ---------------------------------------------*/
86 /* --- @pool_create@ --- *
88 * Arguments: @arena *a@ = pointer to an arena to allocate memory from
90 * Returns: A newly created resource pool.
92 * Use: Creates a fresh root resource pool, i.e., one which is not a
93 * child of any other pool.
96 extern pool *pool_create(arena */*a*/);
98 /* --- @pool_sub@ --- *
100 * Arguments: @pool *p@ = pointer to parent pool
102 * Returns: A new child pool of the parent.
104 * Use: Creates a subpool. The subpool can either be destroyed on
105 * its own, or will be automatically destroyed at the same time
109 extern pool *pool_sub(pool */*p*/);
111 /* --- @pool_alloc@, @pool_allocv@ --- *
113 * Arguments: @pool *p@ = pool to allocate from
114 * @size_t n@ = number of elements to allocate (for
116 * @size_t sz@ = size of block wanted
118 * Returns: Pointer to the requested block.
120 * Use: The @pool_allocv@ function allocates memory for @n@ elements
121 * of @sz@ bytes each from a resource pool. Only the most
122 * recent allocation can usefully be adjusted and/or freed;
123 * other allocations persist until the pool is destroyed. The
124 * @pool_alloc@ function is the same, but with @n@ fixed equal
125 * to 1. If there's not enough memory, the exception
126 * @EXC_NOMEM@ is thrown.
129 extern void *pool_alloc(pool */*p*/, size_t /*sz*/);
130 void *pool_allocv(pool */*p*/, size_t /*n*/, size_t /*sz*/);
132 /* --- @POOL_NEW@, @POOL_NEWV@ --- *
134 * Arguments: @type *q@ = pointer to allocate
135 * @pool *p@ = pool to allocate from
136 * @size_t n@ = number of elements to allocate (for @POOL_NEWV@)
140 * Use: The @POOL_NEW@ macro sets @p@ to point to a freshly allocated
141 * block of memory large enough for an object of the type
142 * pointed to by @p@. The @POOL_NEWV@ macro allocated enough
143 * space for a vector of @n@ elements, each of the type pointed
144 * to by @p@. If there is not enough memory, the exception
145 * @EXC_NOMEM@ is thrown.
148 #define POOL_NEW(q, p) do { (q) = pool_alloc((p), sizeof(*(q))); } while (0)
149 #define POOL_NEWV(q, p, n) \
150 do { (q) = pool_allocv((p), (n), sizeof(*(q))); } while (0)
152 /* --- @pool_realloc@, @pool_reallocv@ --- *
154 * Arguments: @pool *p@ = pointer to the pool
155 * @void *q@ = pointer to block
156 * @size_t n@ = new number of elements (for @pool_reallocv@)
157 * @size_t on@ = old number of elements (for @pool_reallocv@)
158 * @size_t sz@ = size of elements (for @pool_reallocv@)
159 * @size_t newsz@ = the new size required (for @pool_realloc@)
160 * @size_t oldsz@ = existing size allocated (for @pool_realloc@)
162 * Returns: The new address of the block.
164 * Use: The @pool_reallocv@ function returns a pointer to a block of
165 * memory, large enough for @n@ elements each of size @sz@,
166 * containing a copy of the first @min(n, on)@ elements
167 * currently in the block at @q@. If the new pointer is not
168 * equal to @q@, then @q@ is invalidated and it is an error to
169 * make further use of it.
171 * If @q@ points to the most recently allocated block, then the
172 * old storage is reclaimed. Otherwise, if @n@ is smaller than
173 * @on@, the block is shrunk in place, but the excess space is
174 * lost until the pool is destroyed. Otherwise, a fresh block
175 * is allocated and the data copied, and the old block's space
176 * is lost until the pool is destroyed.
178 * The @pool_realloc@ function is the same, except that @sz@ is
179 * fixed at 1, and @n@ and @on@ are renamed to @newsz@ and
183 extern void *pool_realloc(pool */*p*/, void */*q*/,
184 size_t /*newsz*/, size_t /*oldsz*/);
185 extern void *pool_reallocv(pool */*p*/, void */*q*/,
186 size_t /*n*/, size_t /*on*/, size_t /*sz*/);
188 /* --- @POOL_RENEWV@ --- *
190 * Arguments: @type *q@ = a pointer to allocate
191 * @pool *q@ = pointer to pool
192 * @size_t n, on@ = new and existing numbers of elements
196 * Use: Adjust @p@ to point to a new block of memory with space for
197 * @n@ elements of the type pointed to by @p@, on the assumption
198 * that @p@ is either null or currently points to a block with
199 * space for @on@ elements.
202 #define POOL_RENEWV(q, p, n, on) \
203 do { (q) = pool_reallocv((p), (n), (on), sizeof(*(q))); while (0)
205 /* --- @pool_strdup@ --- *
207 * Arguments: @pool *p@ = pool to allocate from
208 * @const char *s@ = pointer to string
210 * Returns: A pointer to a copy of the string.
212 * Use: Allocates a copy of a string.
215 extern char *pool_strdup(pool */*p*/, const char */*s*/);
217 /* --- @pool_free@ --- *
219 * Arguments: @pool *p@ = pointer to the pool
220 * @void *q@ = pointer to block
224 * Use: Try to recycle the memory used by the block allocated at @q@.
225 * If @q@ points to the most recently allocated block, then it
226 * can be reclaimed at no cost. Otherwise, the allocation
227 * persists anyway until the pool as a whole is destroyed --
228 * though the pointer is logically invalidated, and it is an
229 * error to make further use of it.
232 extern void pool_free(pool */*p*/, void */*q*/);
234 /* --- @pool_recycle@ --- *
236 * Arguments: @pool *p@ = pointer to the pool
240 * Use: Release all of the memory and resources held by the pool,
241 * with the expectation that it will be used again. The chunks
242 * from which allocations were satisfied are retained for future
246 extern void pool_recycle(pool */*p*/);
248 /* --- @pool_destroy@ --- *
250 * Arguments: @pool *p@ = pointer to pool to destroy
254 * Use: Destroys a pool, freeing all of the resources within it. If
255 * this is a root pool, its memory will be deallocated; if it's
256 * a subpool, it is emptied and can be used again.
259 extern void pool_destroy(pool */*p*/);
261 /* --- @pool_add@, @POOL_ADD@ --- *
263 * Arguments: @pool *p@ = pointer to pool to add the resource to
264 * @pool_resource *r@ = pointer to resource block
265 * @void (*dfn)(pool_resource *r)@ = destruction function
269 * Use: Adds a resource to a pool.
272 #define POOL_ADD(p, rr, dfn) do { \
274 pool_resource *_r = (rr); \
276 _r->next = _p->resources; \
278 _p->resources = _r; \
281 extern void pool_add(pool */*p*/, pool_resource */*r*/,
282 void (*/*dfn*/)(pool_resource */*r*/));
284 /*----- Various simple resource types -------------------------------------*/
286 /* --- @pool_fopen@ --- *
288 * Arguments: @pool *p@ = pointer to a pool
289 * @const char *file@ = name of the file to open
290 * @const char *how@ = string specifying opening parameters
292 * Returns: A pointer to a pool resource containing an open file handle,
293 * or null if the file open filed.
295 * Use: Opens a file so that it will be freed again when a pool is
299 extern pool_file *pool_fopen(pool */*p*/,
300 const char */*file*/, const char */*how*/);
302 /* --- @pool_fclose@ --- *
304 * Arguments: @pool_file *pf@ = pointer to a file resource
306 * Returns: The response from the @fclose@ function.
308 * Use: Closes a file. It is not an error to close a file multiple
312 extern int pool_fclose(pool_file */*pf*/);
314 /* --- @pool_subarena@ --- *
316 * Arguments: @pool *p@ = pointer to the pool
318 * Returns: A subarena built from the pool's memory allocator.
320 * Use: Creates a suballocation arena attached to a pool. The arena
321 * and all of its memory will be freed when the pool is
325 extern subarena *pool_subarena(pool */*p*/);
327 /*----- That's all, folks -------------------------------------------------*/