Annotation of embedaddon/rsync/lib/pool_alloc.c, revision 1.1.1.3
1.1 misho 1: #include "rsync.h"
2:
3: #define POOL_DEF_EXTENT (32 * 1024)
4:
1.1.1.2 misho 5: #define POOL_QALIGN_P2 (1<<16) /* power-of-2 qalign */
6:
1.1 misho 7: struct alloc_pool
8: {
9: size_t size; /* extent size */
10: size_t quantum; /* allocation quantum */
11: struct pool_extent *extents; /* top extent is "live" */
12: void (*bomb)(); /* function to call if
13: * malloc fails */
14: int flags;
15:
16: /* statistical data */
17: unsigned long e_created; /* extents created */
1.1.1.2 misho 18: unsigned long e_freed; /* extents destroyed */
1.1 misho 19: int64 n_allocated; /* calls to alloc */
20: int64 n_freed; /* calls to free */
21: int64 b_allocated; /* cum. bytes allocated */
22: int64 b_freed; /* cum. bytes freed */
23: };
24:
25: struct pool_extent
26: {
1.1.1.2 misho 27: struct pool_extent *next;
1.1 misho 28: void *start; /* starting address */
29: size_t free; /* free bytecount */
1.1.1.2 misho 30: size_t bound; /* trapped free bytes */
1.1 misho 31: };
32:
33: struct align_test {
1.1.1.2 misho 34: uchar foo;
35: union {
36: int64 i;
37: void *p;
38: } bar;
1.1 misho 39: };
40:
41: #define MINALIGN offsetof(struct align_test, bar)
42:
43: /* Temporarily cast a void* var into a char* var when adding an offset (to
44: * keep some compilers from complaining about the pointer arithmetic). */
45: #define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) )
46:
47: alloc_pool_t
1.1.1.3 ! misho 48: pool_create(size_t size, size_t quantum, void (*bomb)(const char*, const char*, int), int flags)
1.1 misho 49: {
1.1.1.2 misho 50: struct alloc_pool *pool;
51:
52: if ((MINALIGN & (MINALIGN - 1)) != 0) {
53: if (bomb)
1.1.1.3 ! misho 54: (*bomb)("Compiler error: MINALIGN is not a power of 2", __FILE__, __LINE__);
1.1.1.2 misho 55: return NULL;
56: }
57:
1.1.1.3 ! misho 58: if (!(pool = new0(struct alloc_pool)))
! 59: return NULL;
! 60:
1.1.1.2 misho 61: if (!size)
62: size = POOL_DEF_EXTENT;
63: if (!quantum)
64: quantum = MINALIGN;
1.1 misho 65:
66: if (flags & POOL_INTERN) {
1.1.1.2 misho 67: if (size <= sizeof (struct pool_extent))
68: size = quantum;
69: else
70: size -= sizeof (struct pool_extent);
71: flags |= POOL_PREPEND;
72: }
73:
74: if (quantum <= 1)
75: flags = (flags | POOL_NO_QALIGN) & ~POOL_QALIGN_P2;
76: else if (!(flags & POOL_NO_QALIGN)) {
77: if (size % quantum)
78: size += quantum - size % quantum;
79: /* If quantum is a power of 2, we'll avoid using modulus. */
80: if (!(quantum & (quantum - 1)))
81: flags |= POOL_QALIGN_P2;
1.1 misho 82: }
1.1.1.2 misho 83:
84: pool->size = size;
85: pool->quantum = quantum;
1.1 misho 86: pool->bomb = bomb;
87: pool->flags = flags;
88:
89: return pool;
90: }
91:
92: void
93: pool_destroy(alloc_pool_t p)
94: {
95: struct alloc_pool *pool = (struct alloc_pool *) p;
1.1.1.2 misho 96: struct pool_extent *cur, *next;
1.1 misho 97:
98: if (!pool)
99: return;
100:
101: for (cur = pool->extents; cur; cur = next) {
102: next = cur->next;
1.1.1.2 misho 103: if (pool->flags & POOL_PREPEND)
104: free(PTR_ADD(cur->start, -sizeof (struct pool_extent)));
105: else {
106: free(cur->start);
1.1 misho 107: free(cur);
1.1.1.2 misho 108: }
1.1 misho 109: }
1.1.1.2 misho 110:
1.1 misho 111: free(pool);
112: }
113:
114: void *
115: pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg)
116: {
117: struct alloc_pool *pool = (struct alloc_pool *) p;
118: if (!pool)
119: return NULL;
120:
121: if (!len)
122: len = pool->quantum;
1.1.1.2 misho 123: else if (pool->flags & POOL_QALIGN_P2) {
124: if (len & (pool->quantum - 1))
125: len += pool->quantum - (len & (pool->quantum - 1));
126: } else if (!(pool->flags & POOL_NO_QALIGN)) {
127: if (len % pool->quantum)
128: len += pool->quantum - len % pool->quantum;
129: }
1.1 misho 130:
131: if (len > pool->size)
132: goto bomb_out;
133:
134: if (!pool->extents || len > pool->extents->free) {
1.1.1.2 misho 135: void *start;
136: size_t asize;
1.1 misho 137: struct pool_extent *ext;
138:
139: asize = pool->size;
1.1.1.2 misho 140: if (pool->flags & POOL_PREPEND)
1.1 misho 141: asize += sizeof (struct pool_extent);
142:
143: if (!(start = new_array(char, asize)))
144: goto bomb_out;
145:
146: if (pool->flags & POOL_CLEAR)
1.1.1.2 misho 147: memset(start, 0, asize);
1.1 misho 148:
1.1.1.2 misho 149: if (pool->flags & POOL_PREPEND) {
150: ext = start;
151: start = PTR_ADD(start, sizeof (struct pool_extent));
152: } else if (!(ext = new(struct pool_extent)))
1.1 misho 153: goto bomb_out;
154: ext->start = start;
1.1.1.2 misho 155: ext->free = pool->size;
156: ext->bound = 0;
1.1 misho 157: ext->next = pool->extents;
158: pool->extents = ext;
159:
160: pool->e_created++;
161: }
162:
163: pool->n_allocated++;
164: pool->b_allocated += len;
165:
166: pool->extents->free -= len;
167:
168: return PTR_ADD(pool->extents->start, pool->extents->free);
169:
170: bomb_out:
171: if (pool->bomb)
1.1.1.3 ! misho 172: (*pool->bomb)(bomb_msg, __FILE__, __LINE__);
1.1 misho 173: return NULL;
174: }
175:
176: /* This function allows you to declare memory in the pool that you are done
177: * using. If you free all the memory in a pool's extent, that extent will
178: * be freed. */
179: void
180: pool_free(alloc_pool_t p, size_t len, void *addr)
181: {
182: struct alloc_pool *pool = (struct alloc_pool *)p;
183: struct pool_extent *cur, *prev;
184:
185: if (!pool)
186: return;
187:
1.1.1.2 misho 188: if (!addr) {
189: /* A NULL addr starts a fresh extent for new allocations. */
190: if ((cur = pool->extents) != NULL && cur->free != pool->size) {
191: cur->bound += cur->free;
192: cur->free = 0;
193: }
194: return;
195: }
196:
1.1 misho 197: if (!len)
198: len = pool->quantum;
1.1.1.2 misho 199: else if (pool->flags & POOL_QALIGN_P2) {
200: if (len & (pool->quantum - 1))
201: len += pool->quantum - (len & (pool->quantum - 1));
202: } else if (!(pool->flags & POOL_NO_QALIGN)) {
203: if (len % pool->quantum)
204: len += pool->quantum - len % pool->quantum;
205: }
1.1 misho 206:
207: pool->n_freed++;
208: pool->b_freed += len;
209:
210: for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) {
211: if (addr >= cur->start
212: && addr < PTR_ADD(cur->start, pool->size))
213: break;
214: }
215: if (!cur)
216: return;
217:
218: if (!prev) {
219: /* The "live" extent is kept ready for more allocations. */
220: if (cur->free + cur->bound + len >= pool->size) {
221: if (pool->flags & POOL_CLEAR) {
222: memset(PTR_ADD(cur->start, cur->free), 0,
223: pool->size - cur->free);
224: }
225: cur->free = pool->size;
226: cur->bound = 0;
227: } else if (addr == PTR_ADD(cur->start, cur->free)) {
228: if (pool->flags & POOL_CLEAR)
229: memset(addr, 0, len);
230: cur->free += len;
231: } else
232: cur->bound += len;
233: } else {
234: cur->bound += len;
235:
236: if (cur->free + cur->bound >= pool->size) {
237: prev->next = cur->next;
1.1.1.2 misho 238: if (pool->flags & POOL_PREPEND)
239: free(PTR_ADD(cur->start, -sizeof (struct pool_extent)));
240: else {
241: free(cur->start);
1.1 misho 242: free(cur);
1.1.1.2 misho 243: }
1.1 misho 244: pool->e_freed++;
245: } else if (prev != pool->extents) {
246: /* Move the extent to be the first non-live extent. */
247: prev->next = cur->next;
248: cur->next = pool->extents->next;
249: pool->extents->next = cur;
250: }
251: }
252: }
253:
254: /* This allows you to declare that the given address marks the edge of some
255: * pool memory that is no longer needed. Any extents that hold only data
256: * older than the boundary address are freed. NOTE: You MUST NOT USE BOTH
257: * pool_free() and pool_free_old() on the same pool!! */
258: void
259: pool_free_old(alloc_pool_t p, void *addr)
260: {
261: struct alloc_pool *pool = (struct alloc_pool *)p;
262: struct pool_extent *cur, *prev, *next;
263:
264: if (!pool || !addr)
265: return;
266:
267: for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) {
268: if (addr >= cur->start
269: && addr < PTR_ADD(cur->start, pool->size))
270: break;
271: }
272: if (!cur)
273: return;
274:
275: if (addr == PTR_ADD(cur->start, cur->free)) {
276: if (prev) {
277: prev->next = NULL;
278: next = cur;
279: } else {
280: /* The most recent live extent can just be reset. */
281: if (pool->flags & POOL_CLEAR)
282: memset(addr, 0, pool->size - cur->free);
283: cur->free = pool->size;
284: cur->bound = 0;
285: next = cur->next;
286: cur->next = NULL;
287: }
288: } else {
289: next = cur->next;
290: cur->next = NULL;
291: }
292:
293: while ((cur = next) != NULL) {
294: next = cur->next;
1.1.1.2 misho 295: if (pool->flags & POOL_PREPEND)
296: free(PTR_ADD(cur->start, -sizeof (struct pool_extent)));
297: else {
298: free(cur->start);
1.1 misho 299: free(cur);
1.1.1.2 misho 300: }
1.1 misho 301: pool->e_freed++;
302: }
303: }
304:
305: /* If the current extent doesn't have "len" free space in it, mark it as full
306: * so that the next alloc will start a new extent. If len is (size_t)-1, this
307: * bump will always occur. The function returns a boundary address that can
308: * be used with pool_free_old(), or a NULL if no memory is allocated. */
309: void *
310: pool_boundary(alloc_pool_t p, size_t len)
311: {
312: struct alloc_pool *pool = (struct alloc_pool *)p;
313: struct pool_extent *cur;
314:
315: if (!pool || !pool->extents)
316: return NULL;
317:
318: cur = pool->extents;
319:
320: if (cur->free < len) {
321: cur->bound += cur->free;
322: cur->free = 0;
323: }
324:
325: return PTR_ADD(cur->start, cur->free);
326: }
327:
328: #define FDPRINT(label, value) \
329: do { \
330: int len = snprintf(buf, sizeof buf, label, value); \
331: if (write(fd, buf, len) != len) \
332: ret = -1; \
333: } while (0)
334:
335: #define FDEXTSTAT(ext) \
336: do { \
337: int len = snprintf(buf, sizeof buf, " %12ld %5ld\n", \
338: (long)ext->free, (long)ext->bound); \
339: if (write(fd, buf, len) != len) \
340: ret = -1; \
341: } while (0)
342:
343: int
344: pool_stats(alloc_pool_t p, int fd, int summarize)
345: {
346: struct alloc_pool *pool = (struct alloc_pool *) p;
1.1.1.2 misho 347: struct pool_extent *cur;
1.1 misho 348: char buf[BUFSIZ];
349: int ret = 0;
350:
351: if (!pool)
352: return ret;
353:
354: FDPRINT(" Extent size: %12ld\n", (long) pool->size);
355: FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum);
356: FDPRINT(" Extents created: %12ld\n", pool->e_created);
357: FDPRINT(" Extents freed: %12ld\n", pool->e_freed);
358: FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated);
359: FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed);
360: FDPRINT(" Bytes allocated: %12.0f\n", (double) pool->b_allocated);
361: FDPRINT(" Bytes freed: %12.0f\n", (double) pool->b_freed);
362:
363: if (summarize)
364: return ret;
365:
366: if (!pool->extents)
367: return ret;
368:
369: if (write(fd, "\n", 1) != 1)
370: ret = -1;
371:
372: for (cur = pool->extents; cur; cur = cur->next)
373: FDEXTSTAT(cur);
374:
375: return ret;
376: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>