Annotation of embedaddon/rsync/lib/pool_alloc.c, revision 1.1
1.1 ! misho 1: #include "rsync.h"
! 2:
! 3: #define POOL_DEF_EXTENT (32 * 1024)
! 4:
! 5: struct alloc_pool
! 6: {
! 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
! 11: * malloc fails */
! 12: int flags;
! 13:
! 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 */
! 21: };
! 22:
! 23: struct pool_extent
! 24: {
! 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;
! 30: };
! 31:
! 32: struct align_test {
! 33: void *foo;
! 34: int64 bar;
! 35: };
! 36:
! 37: #define MINALIGN offsetof(struct align_test, bar)
! 38:
! 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)) )
! 42:
! 43: alloc_pool_t
! 44: pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
! 45: {
! 46: struct alloc_pool *pool;
! 47:
! 48: if (!(pool = new(struct alloc_pool)))
! 49: return pool;
! 50: memset(pool, 0, sizeof (struct alloc_pool));
! 51:
! 52: pool->size = size /* round extent size to min alignment reqs */
! 53: ? (size + MINALIGN - 1) & ~(MINALIGN - 1)
! 54: : POOL_DEF_EXTENT;
! 55: if (flags & POOL_INTERN) {
! 56: pool->size -= sizeof (struct pool_extent);
! 57: flags |= POOL_APPEND;
! 58: }
! 59: pool->quantum = quantum ? quantum : MINALIGN;
! 60: pool->bomb = bomb;
! 61: pool->flags = flags;
! 62:
! 63: return pool;
! 64: }
! 65:
! 66: void
! 67: pool_destroy(alloc_pool_t p)
! 68: {
! 69: struct alloc_pool *pool = (struct alloc_pool *) p;
! 70: struct pool_extent *cur, *next;
! 71:
! 72: if (!pool)
! 73: return;
! 74:
! 75: for (cur = pool->extents; cur; cur = next) {
! 76: next = cur->next;
! 77: free(cur->start);
! 78: if (!(pool->flags & POOL_APPEND))
! 79: free(cur);
! 80: }
! 81: free(pool);
! 82: }
! 83:
! 84: void *
! 85: pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg)
! 86: {
! 87: struct alloc_pool *pool = (struct alloc_pool *) p;
! 88: if (!pool)
! 89: return NULL;
! 90:
! 91: if (!len)
! 92: len = pool->quantum;
! 93: else if (pool->quantum > 1 && len % pool->quantum)
! 94: len += pool->quantum - len % pool->quantum;
! 95:
! 96: if (len > pool->size)
! 97: goto bomb_out;
! 98:
! 99: if (!pool->extents || len > pool->extents->free) {
! 100: void *start;
! 101: size_t free;
! 102: size_t bound;
! 103: size_t skew;
! 104: size_t asize;
! 105: struct pool_extent *ext;
! 106:
! 107: free = pool->size;
! 108: bound = 0;
! 109:
! 110: asize = pool->size;
! 111: if (pool->flags & POOL_APPEND)
! 112: asize += sizeof (struct pool_extent);
! 113:
! 114: if (!(start = new_array(char, asize)))
! 115: goto bomb_out;
! 116:
! 117: if (pool->flags & POOL_CLEAR)
! 118: memset(start, 0, free);
! 119:
! 120: if (pool->flags & POOL_APPEND)
! 121: ext = PTR_ADD(start, free);
! 122: else if (!(ext = new(struct pool_extent)))
! 123: goto bomb_out;
! 124: if (pool->flags & POOL_QALIGN && pool->quantum > 1
! 125: && (skew = (size_t)PTR_ADD(start, free) % pool->quantum)) {
! 126: bound += skew;
! 127: free -= skew;
! 128: }
! 129: ext->start = start;
! 130: ext->free = free;
! 131: ext->bound = bound;
! 132: ext->next = pool->extents;
! 133: pool->extents = ext;
! 134:
! 135: pool->e_created++;
! 136: }
! 137:
! 138: pool->n_allocated++;
! 139: pool->b_allocated += len;
! 140:
! 141: pool->extents->free -= len;
! 142:
! 143: return PTR_ADD(pool->extents->start, pool->extents->free);
! 144:
! 145: bomb_out:
! 146: if (pool->bomb)
! 147: (*pool->bomb)(bomb_msg);
! 148: return NULL;
! 149: }
! 150:
! 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
! 153: * be freed. */
! 154: void
! 155: pool_free(alloc_pool_t p, size_t len, void *addr)
! 156: {
! 157: struct alloc_pool *pool = (struct alloc_pool *)p;
! 158: struct pool_extent *cur, *prev;
! 159:
! 160: if (!pool)
! 161: return;
! 162:
! 163: if (!len)
! 164: len = pool->quantum;
! 165: else if (pool->quantum > 1 && len % pool->quantum)
! 166: len += pool->quantum - len % pool->quantum;
! 167:
! 168: pool->n_freed++;
! 169: pool->b_freed += len;
! 170:
! 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))
! 174: break;
! 175: }
! 176: if (!cur)
! 177: return;
! 178:
! 179: if (!prev) {
! 180: /* The "live" extent is kept ready for more allocations. */
! 181: if (cur->free + cur->bound + len >= pool->size) {
! 182: size_t skew;
! 183:
! 184: if (pool->flags & POOL_CLEAR) {
! 185: memset(PTR_ADD(cur->start, cur->free), 0,
! 186: pool->size - cur->free);
! 187: }
! 188: cur->free = pool->size;
! 189: cur->bound = 0;
! 190: if (pool->flags & POOL_QALIGN && pool->quantum > 1
! 191: && (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
! 192: cur->bound += skew;
! 193: cur->free -= skew;
! 194: }
! 195: } else if (addr == PTR_ADD(cur->start, cur->free)) {
! 196: if (pool->flags & POOL_CLEAR)
! 197: memset(addr, 0, len);
! 198: cur->free += len;
! 199: } else
! 200: cur->bound += len;
! 201: } else {
! 202: cur->bound += len;
! 203:
! 204: if (cur->free + cur->bound >= pool->size) {
! 205: prev->next = cur->next;
! 206: free(cur->start);
! 207: if (!(pool->flags & POOL_APPEND))
! 208: free(cur);
! 209: pool->e_freed++;
! 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;
! 215: }
! 216: }
! 217: }
! 218:
! 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!! */
! 223: void
! 224: pool_free_old(alloc_pool_t p, void *addr)
! 225: {
! 226: struct alloc_pool *pool = (struct alloc_pool *)p;
! 227: struct pool_extent *cur, *prev, *next;
! 228:
! 229: if (!pool || !addr)
! 230: return;
! 231:
! 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))
! 235: break;
! 236: }
! 237: if (!cur)
! 238: return;
! 239:
! 240: if (addr == PTR_ADD(cur->start, cur->free)) {
! 241: if (prev) {
! 242: prev->next = NULL;
! 243: next = cur;
! 244: } else {
! 245: size_t skew;
! 246:
! 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;
! 251: cur->bound = 0;
! 252: if (pool->flags & POOL_QALIGN && pool->quantum > 1
! 253: && (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
! 254: cur->bound += skew;
! 255: cur->free -= skew;
! 256: }
! 257: next = cur->next;
! 258: cur->next = NULL;
! 259: }
! 260: } else {
! 261: next = cur->next;
! 262: cur->next = NULL;
! 263: }
! 264:
! 265: while ((cur = next) != NULL) {
! 266: next = cur->next;
! 267: free(cur->start);
! 268: if (!(pool->flags & POOL_APPEND))
! 269: free(cur);
! 270: pool->e_freed++;
! 271: }
! 272: }
! 273:
! 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. */
! 278: void *
! 279: pool_boundary(alloc_pool_t p, size_t len)
! 280: {
! 281: struct alloc_pool *pool = (struct alloc_pool *)p;
! 282: struct pool_extent *cur;
! 283:
! 284: if (!pool || !pool->extents)
! 285: return NULL;
! 286:
! 287: cur = pool->extents;
! 288:
! 289: if (cur->free < len) {
! 290: cur->bound += cur->free;
! 291: cur->free = 0;
! 292: }
! 293:
! 294: return PTR_ADD(cur->start, cur->free);
! 295: }
! 296:
! 297: #define FDPRINT(label, value) \
! 298: do { \
! 299: int len = snprintf(buf, sizeof buf, label, value); \
! 300: if (write(fd, buf, len) != len) \
! 301: ret = -1; \
! 302: } while (0)
! 303:
! 304: #define FDEXTSTAT(ext) \
! 305: do { \
! 306: int len = snprintf(buf, sizeof buf, " %12ld %5ld\n", \
! 307: (long)ext->free, (long)ext->bound); \
! 308: if (write(fd, buf, len) != len) \
! 309: ret = -1; \
! 310: } while (0)
! 311:
! 312: int
! 313: pool_stats(alloc_pool_t p, int fd, int summarize)
! 314: {
! 315: struct alloc_pool *pool = (struct alloc_pool *) p;
! 316: struct pool_extent *cur;
! 317: char buf[BUFSIZ];
! 318: int ret = 0;
! 319:
! 320: if (!pool)
! 321: return ret;
! 322:
! 323: FDPRINT(" Extent size: %12ld\n", (long) pool->size);
! 324: FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum);
! 325: FDPRINT(" Extents created: %12ld\n", pool->e_created);
! 326: FDPRINT(" Extents freed: %12ld\n", pool->e_freed);
! 327: FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated);
! 328: FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed);
! 329: FDPRINT(" Bytes allocated: %12.0f\n", (double) pool->b_allocated);
! 330: FDPRINT(" Bytes freed: %12.0f\n", (double) pool->b_freed);
! 331:
! 332: if (summarize)
! 333: return ret;
! 334:
! 335: if (!pool->extents)
! 336: return ret;
! 337:
! 338: if (write(fd, "\n", 1) != 1)
! 339: ret = -1;
! 340:
! 341: for (cur = pool->extents; cur; cur = cur->next)
! 342: FDEXTSTAT(cur);
! 343:
! 344: return ret;
! 345: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>