3 #define POOL_DEF_EXTENT (32 * 1024)
7 size_t size
; /* extent size */
8 size_t quantum
; /* allocation quantum */
9 struct pool_extent
*extents
; /* top extent is "live" */
10 void (*bomb
)(); /* function to call if
14 /* statistical data */
15 unsigned long e_created
; /* extents created */
16 unsigned long e_freed
; /* extents detroyed */
17 int64 n_allocated
; /* calls to alloc */
18 int64 n_freed
; /* calls to free */
19 int64 b_allocated
; /* cum. bytes allocated */
20 int64 b_freed
; /* cum. bytes freed */
25 void *start
; /* starting address */
26 size_t free
; /* free bytecount */
27 size_t bound
; /* bytes bound by padding,
28 * overhead and freed */
29 struct pool_extent
*next
;
37 #define MINALIGN offsetof(struct align_test, bar)
39 /* Temporarily cast a void* var into a char* var when adding an offset (to
40 * keep some compilers from complaining about the pointer arithmetic). */
41 #define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) )
44 pool_create(size_t size
, size_t quantum
, void (*bomb
)(const char *), int flags
)
46 struct alloc_pool
*pool
;
48 if (!(pool
= new(struct alloc_pool
)))
50 memset(pool
, 0, sizeof (struct alloc_pool
));
52 pool
->size
= size
/* round extent size to min alignment reqs */
53 ? (size
+ MINALIGN
- 1) & ~(MINALIGN
- 1)
55 if (flags
& POOL_INTERN
) {
56 pool
->size
-= sizeof (struct pool_extent
);
59 pool
->quantum
= quantum
? quantum
: MINALIGN
;
67 pool_destroy(alloc_pool_t p
)
69 struct alloc_pool
*pool
= (struct alloc_pool
*) p
;
70 struct pool_extent
*cur
, *next
;
75 for (cur
= pool
->extents
; cur
; cur
= next
) {
78 if (!(pool
->flags
& POOL_APPEND
))
85 pool_alloc(alloc_pool_t p
, size_t len
, const char *bomb_msg
)
87 struct alloc_pool
*pool
= (struct alloc_pool
*) p
;
93 else if (pool
->quantum
> 1 && len
% pool
->quantum
)
94 len
+= pool
->quantum
- len
% pool
->quantum
;
99 if (!pool
->extents
|| len
> pool
->extents
->free
) {
105 struct pool_extent
*ext
;
111 if (pool
->flags
& POOL_APPEND
)
112 asize
+= sizeof (struct pool_extent
);
114 if (!(start
= new_array(char, asize
)))
117 if (pool
->flags
& POOL_CLEAR
)
118 memset(start
, 0, free
);
120 if (pool
->flags
& POOL_APPEND
)
121 ext
= PTR_ADD(start
, free
);
122 else if (!(ext
= new(struct pool_extent
)))
124 if (pool
->flags
& POOL_QALIGN
&& pool
->quantum
> 1
125 && (skew
= (size_t)PTR_ADD(start
, free
) % pool
->quantum
)) {
132 ext
->next
= pool
->extents
;
139 pool
->b_allocated
+= len
;
141 pool
->extents
->free
-= len
;
143 return PTR_ADD(pool
->extents
->start
, pool
->extents
->free
);
147 (*pool
->bomb
)(bomb_msg
);
151 /* This function allows you to declare memory in the pool that you are done
152 * using. If you free all the memory in a pool's extent, that extent will
155 pool_free(alloc_pool_t p
, size_t len
, void *addr
)
157 struct alloc_pool
*pool
= (struct alloc_pool
*)p
;
158 struct pool_extent
*cur
, *prev
;
165 else if (pool
->quantum
> 1 && len
% pool
->quantum
)
166 len
+= pool
->quantum
- len
% pool
->quantum
;
169 pool
->b_freed
+= len
;
171 for (prev
= NULL
, cur
= pool
->extents
; cur
; prev
= cur
, cur
= cur
->next
) {
172 if (addr
>= cur
->start
173 && addr
< PTR_ADD(cur
->start
, pool
->size
))
180 /* The "live" extent is kept ready for more allocations. */
181 if (cur
->free
+ cur
->bound
+ len
>= pool
->size
) {
184 if (pool
->flags
& POOL_CLEAR
) {
185 memset(PTR_ADD(cur
->start
, cur
->free
), 0,
186 pool
->size
- cur
->free
);
188 cur
->free
= pool
->size
;
190 if (pool
->flags
& POOL_QALIGN
&& pool
->quantum
> 1
191 && (skew
= (size_t)PTR_ADD(cur
->start
, cur
->free
) % pool
->quantum
)) {
195 } else if (addr
== PTR_ADD(cur
->start
, cur
->free
)) {
196 if (pool
->flags
& POOL_CLEAR
)
197 memset(addr
, 0, len
);
204 if (cur
->free
+ cur
->bound
>= pool
->size
) {
205 prev
->next
= cur
->next
;
207 if (!(pool
->flags
& POOL_APPEND
))
210 } else if (prev
!= pool
->extents
) {
211 /* Move the extent to be the first non-live extent. */
212 prev
->next
= cur
->next
;
213 cur
->next
= pool
->extents
->next
;
214 pool
->extents
->next
= cur
;
219 /* This allows you to declare that the given address marks the edge of some
220 * pool memory that is no longer needed. Any extents that hold only data
221 * older than the boundary address are freed. NOTE: You MUST NOT USE BOTH
222 * pool_free() and pool_free_old() on the same pool!! */
224 pool_free_old(alloc_pool_t p
, void *addr
)
226 struct alloc_pool
*pool
= (struct alloc_pool
*)p
;
227 struct pool_extent
*cur
, *prev
, *next
;
232 for (prev
= NULL
, cur
= pool
->extents
; cur
; prev
= cur
, cur
= cur
->next
) {
233 if (addr
>= cur
->start
234 && addr
< PTR_ADD(cur
->start
, pool
->size
))
240 if (addr
== PTR_ADD(cur
->start
, cur
->free
)) {
247 /* The most recent live extent can just be reset. */
248 if (pool
->flags
& POOL_CLEAR
)
249 memset(addr
, 0, pool
->size
- cur
->free
);
250 cur
->free
= pool
->size
;
252 if (pool
->flags
& POOL_QALIGN
&& pool
->quantum
> 1
253 && (skew
= (size_t)PTR_ADD(cur
->start
, cur
->free
) % pool
->quantum
)) {
265 while ((cur
= next
) != NULL
) {
268 if (!(pool
->flags
& POOL_APPEND
))
274 /* If the current extent doesn't have "len" free space in it, mark it as full
275 * so that the next alloc will start a new extent. If len is (size_t)-1, this
276 * bump will always occur. The function returns a boundary address that can
277 * be used with pool_free_old(), or a NULL if no memory is allocated. */
279 pool_boundary(alloc_pool_t p
, size_t len
)
281 struct alloc_pool
*pool
= (struct alloc_pool
*)p
;
282 struct pool_extent
*cur
;
284 if (!pool
|| !pool
->extents
)
289 if (cur
->free
< len
) {
290 cur
->bound
+= cur
->free
;
294 return PTR_ADD(cur
->start
, cur
->free
);
297 #define FDPRINT(label, value) \
298 snprintf(buf, sizeof buf, label, value), \
299 write(fd, buf, strlen(buf))
301 #define FDEXTSTAT(ext) \
302 snprintf(buf, sizeof buf, " %12ld %5ld\n", \
304 (long) ext->bound), \
305 write(fd, buf, strlen(buf))
308 pool_stats(alloc_pool_t p
, int fd
, int summarize
)
310 struct alloc_pool
*pool
= (struct alloc_pool
*) p
;
311 struct pool_extent
*cur
;
317 FDPRINT(" Extent size: %12ld\n", (long) pool
->size
);
318 FDPRINT(" Alloc quantum: %12ld\n", (long) pool
->quantum
);
319 FDPRINT(" Extents created: %12ld\n", pool
->e_created
);
320 FDPRINT(" Extents freed: %12ld\n", pool
->e_freed
);
321 FDPRINT(" Alloc count: %12.0f\n", (double) pool
->n_allocated
);
322 FDPRINT(" Free Count: %12.0f\n", (double) pool
->n_freed
);
323 FDPRINT(" Bytes allocated: %12.0f\n", (double) pool
->b_allocated
);
324 FDPRINT(" Bytes freed: %12.0f\n", (double) pool
->b_freed
);
334 for (cur
= pool
->extents
; cur
; cur
= cur
->next
)