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)