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,
28 /*----- Header files ------------------------------------------------------*/
34 #ifdef HAVE_VALGRIND_VALGRIND_H
35 # include <valgrind/valgrind.h>
36 # include <valgrind/memcheck.h>
47 /*----- Constants ---------------------------------------------------------*/
49 #define REDZONE_SIZE (2*ALIGNOF(union align))
51 /*----- Main code ---------------------------------------------------------*/
53 /* --- @doalloc@ --- *
55 * Arguments: @arena *a@ = pointer to arena to allocate memory from
56 * @pool_chunk **cc@ = pointer to chunk list
57 * @size_t sz@ = size of memory wanted
58 * @unsigned f@ = flags (@PF_...@)
60 * Returns: Pointer to the allocated block.
62 * Use: The basic allocator for resource pools. This is also used
63 * during pool creation, hence the slightly bizarre interface.
66 static void *doalloc(arena
*a
, pool_chunk
**cc
, size_t sz
, unsigned f
)
71 size_t redsz
= VG( f
&PF_VALGRIND ? REDZONE_SIZE
: ) 0;
72 VG( size_t sz0
= sz
; )
74 /* --- See if there's enough space --- *
76 * The chunks are sorted by available space, so if there's not enough space
77 * in the first chunk there isn't enough space anywhere.
80 ALIGN(sz
); sz
+= redsz
;
82 if (c
&& c
->left
>= sz
) {
83 p
= c
->p
; VG( if (f
&PF_VALGRIND
) VALGRIND_MEMPOOL_ALLOC(c
, p
, sz0
); )
84 c
->p
+= sz
; c
->left
-= sz
;
88 /* --- Failed to find anything --- *
90 * I must allocate a new block from the arena, then.
94 ssz
= sizeof(pool_chunk
);
96 csz
= (ssz
+ redsz
+ sz
+ POOL_CHUNKSZ
- 1); csz
-= csz
% POOL_CHUNKSZ
;
98 p
= (unsigned char *)c
+ ssz
+ redsz
;
99 VG( if (f
&PF_VALGRIND
) {
100 VALGRIND_CREATE_MEMPOOL(c
, REDZONE_SIZE
, 0);
101 VALGRIND_MEMPOOL_ALLOC(c
, p
, sz0
);
103 c
->p
= (unsigned char *)p
+ sz
;
104 c
->left
= csz
- ssz
- redsz
- sz
;
107 /* --- Move this chunk in the list so that it's sorted --- */
109 while (*cc
&& (*cc
)->left
> c
->left
) cc
= &(*cc
)->next
;
110 c
->next
= *cc
; *cc
= c
;
117 /* --- @pool_alloc@ --- *
119 * Arguments: @pool *p@ = pool to allocate from
120 * @size_t sz@ = size of block wanted
122 * Returns: Pointer to the requested block.
124 * Use: Allocates memory from a resource pool. Memory is never freed
125 * from pools: it is released when the pool is destroyed.
128 void *pool_alloc(pool
*p
, size_t sz
)
129 { return (doalloc(p
->pa
, &p
->c
, sz
, p
->f
)); }
131 /* --- @pool_strdup@ --- *
133 * Arguments: @pool *p@ = pool to allocate from
134 * @const char *s@ = pointer to string
136 * Returns: A pointer to a copy of the string.
138 * Use: Allocates a copy of a string.
141 char *pool_strdup(pool
*p
, const char *s
)
143 size_t sz
= strlen(s
) + 1;
144 char *pp
= doalloc(p
->pa
, &p
->c
, sz
, p
->f
);
150 /* --- Arena operations --- */
152 static void *palloc(arena
*a
, size_t sz
)
156 return (doalloc(p
->pa
, &p
->c
, sz
, p
->f
));
159 static void pfree(arena
*a
, void *p
) { return; } /* Trivial */
161 static arena_ops pool_ops
= { palloc
, arena_fakerealloc
, pfree
, 0 };
163 /* --- @pool_create@ --- *
165 * Arguments: @arena *a@ = pointer to an arena to allocate memory from
167 * Returns: A newly created resource pool.
169 * Use: Creates a resource pool which is not a child of any other
173 pool
*pool_create(arena
*a
)
179 VG( if (RUNNING_ON_VALGRIND
) f
|= PF_VALGRIND
; )
180 p
= doalloc(a
, &c
, sizeof(pool
), f
);
181 p
->c
= c
; p
->r
= 0; p
->pa
= a
; p
->f
= f
;
182 p
->a
.ops
= &pool_ops
;
186 /* --- @pool_destroy@ --- *
188 * Arguments: @pool *p@ = pointer to pool to destroy
192 * Use: Destroys a pool, freeing all of the resources within it. If
193 * this is a pool created by @pool_create@, its memory will be
194 * deallocated; if it's a subpool or it was initialized by
195 * @pool_init@, it is emptied and can be used again.
198 void pool_destroy(pool
*p
)
200 pool_resource
*r
, *rr
;
204 /* --- Dispose of all of the resources --- */
215 /* --- Free all of the memory --- *
217 * Since root pools are allocated in their own memory, this will free the
218 * root pool block. Subpools are allocated in their parent's memory, so
219 * the pool block itself will be left around.
222 a
= p
->pa
; c
= p
->c
; p
->c
= 0;
225 VG( if (p
->f
&PF_VALGRIND
) VALGRIND_DESTROY_MEMPOOL(c
); )
231 /* --- @pool_add@ --- *
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
239 * Use: Adds a resource to a pool.
242 void pool_add(pool
*p
, pool_resource
*r
, void (*dfn
)(pool_resource
*r
))
247 /* --- @pool_sub@ --- *
249 * Arguments: @pool *p@ = pointer to parent pool
251 * Returns: A new child pool of the parent.
253 * Use: Creates a subpool. The subpool can either be destroyed on
254 * its own, or will be automatically destroyed at the same time
258 typedef struct subpool
{
263 static void subpool_destroy(pool_resource
*r
)
265 subpool
*p
= (subpool
*)r
;
269 pool
*pool_sub(pool
*p
)
271 subpool
*pp
= pool_alloc(p
, sizeof(subpool
));
272 POOL_ADD(p
, &pp
->r
, subpool_destroy
);
273 pp
->p
.a
.ops
= &pool_ops
;
280 /*----- That's all, folks -------------------------------------------------*/