00001 #include "rsync.h"
00002
00003 #define POOL_DEF_EXTENT (32 * 1024)
00004
00005 struct alloc_pool
00006 {
00007 size_t size;
00008 size_t quantum;
00009 struct pool_extent *live;
00010
00011 struct pool_extent *free;
00012 void (*bomb)();
00013
00014
00015 int flags;
00016
00017
00018 unsigned long e_created;
00019 unsigned long e_freed;
00020 int64 n_allocated;
00021 int64 n_freed;
00022 int64 b_allocated;
00023 int64 b_freed;
00024 };
00025
00026 struct pool_extent
00027 {
00028 void *start;
00029 size_t free;
00030 size_t bound;
00031
00032 struct pool_extent *next;
00033 };
00034
00035 struct align_test {
00036 void *foo;
00037 int64 bar;
00038 };
00039
00040 #define MINALIGN offsetof(struct align_test, bar)
00041
00042
00043
00044 #define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) )
00045
00046 alloc_pool_t
00047 pool_create(size_t size, size_t quantum,
00048 void (*bomb)(char *), int flags)
00049 {
00050 struct alloc_pool *pool;
00051
00052 if (!(pool = (struct alloc_pool*) malloc(sizeof (struct alloc_pool))))
00053 return pool;
00054 memset(pool, 0, sizeof (struct alloc_pool));
00055
00056 pool->size = size
00057 ? (size + MINALIGN - 1) & ~(MINALIGN - 1)
00058 : POOL_DEF_EXTENT;
00059 if (pool->flags & POOL_INTERN) {
00060 pool->size -= sizeof (struct pool_extent);
00061 flags |= POOL_APPEND;
00062 }
00063 pool->quantum = quantum ? quantum : MINALIGN;
00064 pool->bomb = bomb;
00065 pool->flags = flags;
00066
00067 return pool;
00068 }
00069
00070 void
00071 pool_destroy(alloc_pool_t p)
00072 {
00073 struct alloc_pool *pool = (struct alloc_pool *) p;
00074 struct pool_extent *cur, *next;
00075
00076 if (!pool)
00077 return;
00078
00079 if (pool->live) {
00080 cur = pool->live;
00081 free(cur->start);
00082 if (!(pool->flags & POOL_APPEND))
00083 free(cur);
00084 }
00085 for (cur = pool->free; cur; cur = next) {
00086 next = cur->next;
00087 free(cur->start);
00088 if (!(pool->flags & POOL_APPEND))
00089 free(cur);
00090 }
00091 free(pool);
00092 }
00093
00094 void *
00095 pool_alloc(alloc_pool_t p, size_t len, char *bomb)
00096 {
00097 struct alloc_pool *pool = (struct alloc_pool *) p;
00098 if (!pool)
00099 return NULL;
00100
00101 if (!len)
00102 len = pool->quantum;
00103 else if (pool->quantum > 1 && len % pool->quantum)
00104 len += pool->quantum - len % pool->quantum;
00105
00106 if (len > pool->size)
00107 goto bomb;
00108
00109 if (!pool->live || len > pool->live->free) {
00110 void *start;
00111 size_t free;
00112 size_t bound;
00113 size_t sqew;
00114 size_t asize;
00115
00116 if (pool->live) {
00117 pool->live->next = pool->free;
00118 pool->free = pool->live;
00119 }
00120
00121 free = pool->size;
00122 bound = 0;
00123
00124 asize = pool->size;
00125 if (pool->flags & POOL_APPEND)
00126 asize += sizeof (struct pool_extent);
00127
00128 if (!(start = (void *) malloc(asize)))
00129 goto bomb;
00130
00131 if (pool->flags & POOL_CLEAR)
00132 memset(start, 0, pool->size);
00133
00134 if (pool->flags & POOL_APPEND)
00135 pool->live = PTR_ADD(start, free);
00136 else if (!(pool->live = (struct pool_extent *) malloc(sizeof (struct pool_extent))))
00137 goto bomb;
00138 if (pool->flags & POOL_QALIGN && pool->quantum > 1
00139 && (sqew = (size_t)PTR_ADD(start, free) % pool->quantum)) {
00140 bound += sqew;
00141 free -= sqew;
00142 }
00143 pool->live->start = start;
00144 pool->live->free = free;
00145 pool->live->bound = bound;
00146 pool->live->next = NULL;
00147
00148 pool->e_created++;
00149 }
00150
00151 pool->n_allocated++;
00152 pool->b_allocated += len;
00153
00154 pool->live->free -= len;
00155
00156 return PTR_ADD(pool->live->start, pool->live->free);
00157
00158 bomb:
00159 if (pool->bomb)
00160 (*pool->bomb)(bomb);
00161 return NULL;
00162 }
00163
00164 void
00165 pool_free(alloc_pool_t p, size_t len, void *addr)
00166 {
00167 struct alloc_pool *pool = (struct alloc_pool *) p;
00168 struct pool_extent *cur;
00169 struct pool_extent *prev;
00170
00171 if (!pool)
00172 return;
00173
00174 if (!len)
00175 len = pool->quantum;
00176 else if (pool->quantum > 1 && len % pool->quantum)
00177 len += pool->quantum - len % pool->quantum;
00178
00179 if (!addr && pool->live) {
00180 pool->live->next = pool->free;
00181 pool->free = pool->live;
00182 pool->live = NULL;
00183 return;
00184 }
00185 pool->n_freed++;
00186 pool->b_freed += len;
00187
00188 cur = pool->live;
00189 if (cur && addr >= cur->start
00190 && addr < PTR_ADD(cur->start, pool->size)) {
00191 if (addr == PTR_ADD(cur->start, cur->free)) {
00192 if (pool->flags & POOL_CLEAR)
00193 memset(addr, 0, len);
00194 pool->b_freed += len;
00195 } else
00196 cur->bound += len;
00197 if (cur->free + cur->bound >= pool->size) {
00198 size_t sqew;
00199
00200 cur->free = pool->size;
00201 cur->bound = 0;
00202 if (pool->flags & POOL_QALIGN && pool->quantum > 1
00203 && (sqew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
00204 cur->bound += sqew;
00205 cur->free -= sqew;
00206 }
00207 }
00208 return;
00209 }
00210 for (prev = NULL, cur = pool->free; cur; prev = cur, cur = cur->next) {
00211 if (addr >= cur->start
00212 && addr < PTR_ADD(cur->start, pool->size))
00213 break;
00214 }
00215 if (!cur)
00216 return;
00217
00218 if (prev) {
00219 prev->next = cur->next;
00220 cur->next = pool->free;
00221 pool->free = cur;
00222 }
00223 cur->bound += len;
00224
00225 if (cur->free + cur->bound >= pool->size) {
00226 pool->free = cur->next;
00227
00228 free(cur->start);
00229 if (!(pool->flags & POOL_APPEND))
00230 free(cur);
00231 pool->e_freed++;
00232 }
00233 return;
00234 }
00235
00236 #define FDPRINT(label, value) \
00237 snprintf(buf, sizeof buf, label, value), \
00238 write(fd, buf, strlen(buf))
00239
00240 #define FDEXTSTAT(ext) \
00241 snprintf(buf, sizeof buf, " %12ld %5ld\n", \
00242 (long) ext->free, \
00243 (long) ext->bound), \
00244 write(fd, buf, strlen(buf))
00245
00246 void
00247 pool_stats(alloc_pool_t p, int fd, int summarize)
00248 {
00249 struct alloc_pool *pool = (struct alloc_pool *) p;
00250 struct pool_extent *cur;
00251 char buf[BUFSIZ];
00252
00253 if (!pool)
00254 return;
00255
00256 FDPRINT(" Extent size: %12ld\n", (long) pool->size);
00257 FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum);
00258 FDPRINT(" Extents created: %12ld\n", pool->e_created);
00259 FDPRINT(" Extents freed: %12ld\n", pool->e_freed);
00260 FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated);
00261 FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed);
00262 FDPRINT(" Alloc bytes: %12.0f\n", (double) pool->b_allocated);
00263 FDPRINT(" Free bytes: %12.0f\n", (double) pool->b_freed);
00264
00265 if (summarize)
00266 return;
00267
00268 if (!pool->live && !pool->free)
00269 return;
00270
00271 write(fd, "\n", 1);
00272
00273 if (pool->live)
00274 FDEXTSTAT(pool->live);
00275 strcpy(buf, " FREE BOUND\n");
00276 write(fd, buf, strlen(buf));
00277
00278 for (cur = pool->free; cur; cur = cur->next)
00279 FDEXTSTAT(cur);
00280 }