3 //#include <stdio.h> // temporary
7 #define MOVEABLE_POOL 1
13 void check_invariants(struct pool_head *head) {
17 avail = head->item.base - head->item.limit;
18 for (p = head->item.next; p != &head->item; p = p->next) {
19 assert(p->prev->next == p && p->next->prev == p);
20 assert(p->base >= p->prev->limit && p->limit <= p->next->base);
21 avail += p->base - p->limit;
23 assert(avail == head->avail);
28 struct pool_head *head,
31 void (*move)(struct pool_item *item, int new_base),
32 void (*move_up)(struct pool_item *item, int new_limit)
34 head->item.prev = &head->item;
35 head->item.next = &head->item;
36 head->item.base = limit; // note: swapped
37 head->item.limit = base; // note: swapped
38 head->avail = limit - base;
40 head->move_up = move_up;
42 check_invariants(head);
47 struct pool_head *head,
48 struct pool_item *item,
55 int new_base, new_limit, avail;
57 struct pool_item *p, *q;
59 struct pool_item *r, *target_item;
62 int base_offset, limit_offset;
66 if (mode & POOL_ALLOC_MODE_REALLOC) {
67 // realloc, item must be already allocated
68 assert(item->prev && item->next);
69 size_change += item->base - item->limit;
71 // calculate new spot if block is extended not moved
73 new_base = item->base - va_arg(ap, int);
75 new_limit = new_base + size;
77 if (new_base >= item->prev->limit && new_limit <= item->next->base)
83 // alloc, item must not be already allocated
84 assert(item->prev == NULL && item->next == NULL);
88 // check size, disregarding fragmentation
89 avail = head->avail - size_change;
93 // work in specified direction, then reverse
94 dir = (mode & POOL_ALLOC_MODE_LAST_FIT) != 0;
101 // enter here when either blocker has changed
104 //printf("a target_size %d\n", target_size);
105 if (mode & POOL_ALLOC_MODE_REALLOC) {
106 if (new_base >= item->prev->limit && new_limit <= item->next->base)
109 if (mode & POOL_ALLOC_MODE_MOVEABLE) {
110 // check both blockers to see if smaller than item
112 if (new_base < r->limit && r != &head->item) {
113 gap = r->limit - r->base;
114 if (gap < target_size) {
117 //printf("b target_size %d\n", target_size);
122 if (new_limit > r->base && r != &head->item) {
123 gap = r->limit - r->base;
124 if (gap < target_size) {
127 //printf("c target_size %d\n", target_size);
135 //printf("avail %d\n", avail);
136 // advance, so that p, q are before/after gap
141 // skip our own item for gap calculation
145 // if non-moveable, do our own item specially then reverse direction
146 if (mode & POOL_ALLOC_MODE_MOVEABLE)
150 //printf("forw %p(%d)->%p(%d)\n", p, p->limit, q, q->base);
156 // skip our own item for gap calculation
160 // if non-moveable, do our own item specially then reverse direction
161 if (mode & POOL_ALLOC_MODE_MOVEABLE)
165 //printf("back %p(%d)->%p(%d)\n", p, p->limit, q, q->base);
168 // see if target fits in current gap
169 gap = q->base - p->limit;
171 if (target_size <= gap) {
172 //printf("target\n");
173 if (target_item == item)
176 assert(mode & POOL_ALLOC_MODE_MOVEABLE);
179 head->move(target_item, p->limit);
180 target_item->limit += p->limit - target_item->base;
181 target_item->base = p->limit;
184 assert(head->move_up);
185 head->move_up(target_item, q->base);
186 target_item->base += q->base - target_item->limit;
187 target_item->limit = q->base;
191 target_item->prev->next = target_item->next;
192 target_item->next->prev = target_item->prev;
198 // insert into list at found position
199 target_item->prev = p;
200 p->next = target_item;
201 target_item->next = q;
202 q->prev = target_item;
213 // see if gap can be left alone
217 if (!(mode & POOL_ALLOC_MODE_MOVEABLE))
221 //printf("compact\n");
224 head->move(q, p->limit);
225 q->limit += p->limit - q->base;
229 assert(head->move_up);
230 head->move_up(p, q->base);
231 p->base += q->base - p->limit;
235 // if we have just moved the target, then the target is
236 // no longer valid and we should go to blocker_test, but
237 // the loop is about to terminate anyway => don't bother
243 assert((dir ? p : q) != &head->item);
245 //printf("done %p(%d)->%p(%d)\n", p, p->limit, q, q->base);
247 // have compacted up from bottom and reached our item,
248 // or compacted down from top and reached our item
249 // (test is slightly different here, as we will ignore
250 // our item for the purpose of calculating the gap)
251 gap = q->base - p->limit;
256 //printf("dir changed to %d\n", dir);
257 assert(dir != ((mode & POOL_ALLOC_MODE_LAST_FIT) != 0));
262 // before clobbering the in-place position calculation,
263 // figure out how much each end is truncated or extended
264 // (if non-zero, one of these was passed as a parameter)
265 base_offset = item->base - new_base;
266 limit_offset = item->limit - new_limit;
268 // align ourself in found spot
269 // (try to allow future extension in desired direction)
270 if ((mode & POOL_ALLOC_MODE_LAST_FIT) == 0) {
272 new_limit = new_base + size;
276 new_base = new_limit - size;
279 if (mode & POOL_ALLOC_MODE_REALLOC) {
280 // move ourself into found spot
281 // (throw away truncated parts before calling move routine)
282 assert(head->move && head->move_up);
283 if (base_offset < 0) {
284 item->base -= base_offset;
287 if (limit_offset > 0) {
288 item->limit -= limit_offset;
291 base_offset += new_base;
292 gap = base_offset - item->base; // amount to move by
294 head->move(item, base_offset);
296 head->move_up(item, limit_offset + new_limit);
299 item->prev->next = item->next;
300 item->next->prev = item->prev;
303 // insert into list at found position
310 //printf("fits %p(%d)->%p(%d) [%d,%d)\n", item->prev, item->prev->limit, item->next, item->next->base, new_base, new_limit);
311 item->base = new_base;
312 item->limit = new_limit;
314 // keep track of total allocation
315 head->avail -= size_change;
317 check_invariants(head);
322 void pool_free(struct pool_head *head, struct pool_item *item) {
323 // item must be already allocated
324 assert(item->prev && item->next);
327 item->prev->next = item->next;
328 item->next->prev = item->prev;
334 // keep track of total allocation
335 head->avail += item->limit - item->base;
337 check_invariants(head);