X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/8b498b9f1aa9f6419bb633e68a1c21d19c04e381..9411292489496984c8d5d9a446bf071afac3866d:/lib/pool_alloc.c diff --git a/lib/pool_alloc.c b/lib/pool_alloc.c index 7d95f197..5856d591 100644 --- a/lib/pool_alloc.c +++ b/lib/pool_alloc.c @@ -2,6 +2,8 @@ #define POOL_DEF_EXTENT (32 * 1024) +#define POOL_QALIGN_P2 (1<<16) /* power-of-2 qalign */ + struct alloc_pool { size_t size; /* extent size */ @@ -13,7 +15,7 @@ struct alloc_pool /* statistical data */ unsigned long e_created; /* extents created */ - unsigned long e_freed; /* extents detroyed */ + unsigned long e_freed; /* extents destroyed */ int64 n_allocated; /* calls to alloc */ int64 n_freed; /* calls to free */ int64 b_allocated; /* cum. bytes allocated */ @@ -22,16 +24,18 @@ struct alloc_pool struct pool_extent { + struct pool_extent *next; void *start; /* starting address */ size_t free; /* free bytecount */ - size_t bound; /* bytes bound by padding, - * overhead and freed */ - struct pool_extent *next; + size_t bound; /* trapped free bytes */ }; struct align_test { - void *foo; - int64 bar; + uchar foo; + union { + int64 i; + void *p; + } bar; }; #define MINALIGN offsetof(struct align_test, bar) @@ -43,20 +47,42 @@ struct align_test { alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags) { - struct alloc_pool *pool; - - if (!(pool = new(struct alloc_pool))) - return pool; - memset(pool, 0, sizeof (struct alloc_pool)); - - pool->size = size /* round extent size to min alignment reqs */ - ? (size + MINALIGN - 1) & ~(MINALIGN - 1) - : POOL_DEF_EXTENT; - if (pool->flags & POOL_INTERN) { - pool->size -= sizeof (struct pool_extent); - flags |= POOL_APPEND; + struct alloc_pool *pool; + + if (!(pool = new0(struct alloc_pool))) + return NULL; + + if ((MINALIGN & (MINALIGN - 1)) != 0) { + if (bomb) + (*bomb)("Compiler error: MINALIGN is not a power of 2\n"); + return NULL; } - pool->quantum = quantum ? quantum : MINALIGN; + + if (!size) + size = POOL_DEF_EXTENT; + if (!quantum) + quantum = MINALIGN; + + if (flags & POOL_INTERN) { + if (size <= sizeof (struct pool_extent)) + size = quantum; + else + size -= sizeof (struct pool_extent); + flags |= POOL_PREPEND; + } + + if (quantum <= 1) + flags = (flags | POOL_NO_QALIGN) & ~POOL_QALIGN_P2; + else if (!(flags & POOL_NO_QALIGN)) { + if (size % quantum) + size += quantum - size % quantum; + /* If quantum is a power of 2, we'll avoid using modulus. */ + if (!(quantum & (quantum - 1))) + flags |= POOL_QALIGN_P2; + } + + pool->size = size; + pool->quantum = quantum; pool->bomb = bomb; pool->flags = flags; @@ -67,17 +93,21 @@ void pool_destroy(alloc_pool_t p) { struct alloc_pool *pool = (struct alloc_pool *) p; - struct pool_extent *cur, *next; + struct pool_extent *cur, *next; if (!pool) return; for (cur = pool->extents; cur; cur = next) { next = cur->next; - free(cur->start); - if (!(pool->flags & POOL_APPEND)) + if (pool->flags & POOL_PREPEND) + free(PTR_ADD(cur->start, -sizeof (struct pool_extent))); + else { + free(cur->start); free(cur); + } } + free(pool); } @@ -90,45 +120,40 @@ pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg) if (!len) len = pool->quantum; - else if (pool->quantum > 1 && len % pool->quantum) - len += pool->quantum - len % pool->quantum; + else if (pool->flags & POOL_QALIGN_P2) { + if (len & (pool->quantum - 1)) + len += pool->quantum - (len & (pool->quantum - 1)); + } else if (!(pool->flags & POOL_NO_QALIGN)) { + if (len % pool->quantum) + len += pool->quantum - len % pool->quantum; + } if (len > pool->size) goto bomb_out; if (!pool->extents || len > pool->extents->free) { - void *start; - size_t free; - size_t bound; - size_t skew; - size_t asize; + void *start; + size_t asize; struct pool_extent *ext; - free = pool->size; - bound = 0; - asize = pool->size; - if (pool->flags & POOL_APPEND) + if (pool->flags & POOL_PREPEND) asize += sizeof (struct pool_extent); if (!(start = new_array(char, asize))) goto bomb_out; if (pool->flags & POOL_CLEAR) - memset(start, 0, free); + memset(start, 0, asize); - if (pool->flags & POOL_APPEND) - ext = PTR_ADD(start, free); - else if (!(ext = new(struct pool_extent))) + if (pool->flags & POOL_PREPEND) { + ext = start; + start = PTR_ADD(start, sizeof (struct pool_extent)); + } else if (!(ext = new(struct pool_extent))) goto bomb_out; - if (pool->flags & POOL_QALIGN && pool->quantum > 1 - && (skew = (size_t)PTR_ADD(start, free) % pool->quantum)) { - bound += skew; - free -= skew; - } ext->start = start; - ext->free = free; - ext->bound = bound; + ext->free = pool->size; + ext->bound = 0; ext->next = pool->extents; pool->extents = ext; @@ -160,10 +185,24 @@ pool_free(alloc_pool_t p, size_t len, void *addr) if (!pool) return; + if (!addr) { + /* A NULL addr starts a fresh extent for new allocations. */ + if ((cur = pool->extents) != NULL && cur->free != pool->size) { + cur->bound += cur->free; + cur->free = 0; + } + return; + } + if (!len) len = pool->quantum; - else if (pool->quantum > 1 && len % pool->quantum) - len += pool->quantum - len % pool->quantum; + else if (pool->flags & POOL_QALIGN_P2) { + if (len & (pool->quantum - 1)) + len += pool->quantum - (len & (pool->quantum - 1)); + } else if (!(pool->flags & POOL_NO_QALIGN)) { + if (len % pool->quantum) + len += pool->quantum - len % pool->quantum; + } pool->n_freed++; pool->b_freed += len; @@ -179,19 +218,12 @@ pool_free(alloc_pool_t p, size_t len, void *addr) if (!prev) { /* The "live" extent is kept ready for more allocations. */ if (cur->free + cur->bound + len >= pool->size) { - size_t skew; - if (pool->flags & POOL_CLEAR) { memset(PTR_ADD(cur->start, cur->free), 0, pool->size - cur->free); } cur->free = pool->size; cur->bound = 0; - if (pool->flags & POOL_QALIGN && pool->quantum > 1 - && (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) { - cur->bound += skew; - cur->free -= skew; - } } else if (addr == PTR_ADD(cur->start, cur->free)) { if (pool->flags & POOL_CLEAR) memset(addr, 0, len); @@ -203,9 +235,12 @@ pool_free(alloc_pool_t p, size_t len, void *addr) if (cur->free + cur->bound >= pool->size) { prev->next = cur->next; - free(cur->start); - if (!(pool->flags & POOL_APPEND)) + if (pool->flags & POOL_PREPEND) + free(PTR_ADD(cur->start, -sizeof (struct pool_extent))); + else { + free(cur->start); free(cur); + } pool->e_freed++; } else if (prev != pool->extents) { /* Move the extent to be the first non-live extent. */ @@ -242,19 +277,13 @@ pool_free_old(alloc_pool_t p, void *addr) prev->next = NULL; next = cur; } else { - size_t skew; - /* The most recent live extent can just be reset. */ if (pool->flags & POOL_CLEAR) memset(addr, 0, pool->size - cur->free); cur->free = pool->size; cur->bound = 0; - if (pool->flags & POOL_QALIGN && pool->quantum > 1 - && (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) { - cur->bound += skew; - cur->free -= skew; - } next = cur->next; + cur->next = NULL; } } else { next = cur->next; @@ -263,9 +292,12 @@ pool_free_old(alloc_pool_t p, void *addr) while ((cur = next) != NULL) { next = cur->next; - free(cur->start); - if (!(pool->flags & POOL_APPEND)) + if (pool->flags & POOL_PREPEND) + free(PTR_ADD(cur->start, -sizeof (struct pool_extent))); + else { + free(cur->start); free(cur); + } pool->e_freed++; } } @@ -294,24 +326,30 @@ pool_boundary(alloc_pool_t p, size_t len) } #define FDPRINT(label, value) \ - snprintf(buf, sizeof buf, label, value), \ - write(fd, buf, strlen(buf)) + do { \ + int len = snprintf(buf, sizeof buf, label, value); \ + if (write(fd, buf, len) != len) \ + ret = -1; \ + } while (0) #define FDEXTSTAT(ext) \ - snprintf(buf, sizeof buf, " %12ld %5ld\n", \ - (long) ext->free, \ - (long) ext->bound), \ - write(fd, buf, strlen(buf)) - -void + do { \ + int len = snprintf(buf, sizeof buf, " %12ld %5ld\n", \ + (long)ext->free, (long)ext->bound); \ + if (write(fd, buf, len) != len) \ + ret = -1; \ + } while (0) + +int pool_stats(alloc_pool_t p, int fd, int summarize) { struct alloc_pool *pool = (struct alloc_pool *) p; - struct pool_extent *cur; + struct pool_extent *cur; char buf[BUFSIZ]; + int ret = 0; if (!pool) - return; + return ret; FDPRINT(" Extent size: %12ld\n", (long) pool->size); FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum); @@ -323,13 +361,16 @@ pool_stats(alloc_pool_t p, int fd, int summarize) FDPRINT(" Bytes freed: %12.0f\n", (double) pool->b_freed); if (summarize) - return; + return ret; if (!pool->extents) - return; + return ret; - write(fd, "\n", 1); + if (write(fd, "\n", 1) != 1) + ret = -1; for (cur = pool->extents; cur; cur = cur->next) FDEXTSTAT(cur); + + return ret; }