Commit | Line | Data |
---|---|---|
7efdcf32 S |
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 *live; /* current extent for | |
10 | * allocations */ | |
11 | struct pool_extent *free; /* unfreed extent list */ | |
12 | void (*bomb)(); | |
13 | /* function to call if | |
14 | * malloc fails */ | |
15 | int flags; | |
16 | ||
17 | /* statistical data */ | |
18 | unsigned long e_created; /* extents created */ | |
19 | unsigned long e_freed; /* extents detroyed */ | |
707415d4 WD |
20 | int64 n_allocated; /* calls to alloc */ |
21 | int64 n_freed; /* calls to free */ | |
22 | int64 b_allocated; /* cum. bytes allocated */ | |
23 | int64 b_freed; /* cum. bytes freed */ | |
7efdcf32 S |
24 | }; |
25 | ||
26 | struct pool_extent | |
27 | { | |
28 | void *start; /* starting address */ | |
29 | size_t free; /* free bytecount */ | |
30 | size_t bound; /* bytes bound by padding, | |
31 | * overhead and freed */ | |
32 | struct pool_extent *next; | |
33 | }; | |
34 | ||
4d4df3cd WD |
35 | struct align_test { |
36 | void *foo; | |
707415d4 | 37 | int64 bar; |
4d4df3cd WD |
38 | }; |
39 | ||
40 | #define MINALIGN offsetof(struct align_test, bar) | |
7efdcf32 | 41 | |
71b291d7 WD |
42 | /* Temporarily cast a void* var into a char* var when adding an offset (to |
43 | * keep some compilers from complaining about the pointer arithmetic). */ | |
44 | #define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) ) | |
45 | ||
7efdcf32 | 46 | alloc_pool_t |
4a19c3b2 | 47 | pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags) |
7efdcf32 S |
48 | { |
49 | struct alloc_pool *pool; | |
50 | ||
51 | if (!(pool = (struct alloc_pool*) malloc(sizeof (struct alloc_pool)))) | |
52 | return pool; | |
53 | memset(pool, 0, sizeof (struct alloc_pool)); | |
54 | ||
55 | pool->size = size /* round extent size to min alignment reqs */ | |
56 | ? (size + MINALIGN - 1) & ~(MINALIGN - 1) | |
57 | : POOL_DEF_EXTENT; | |
8ea17b50 | 58 | if (pool->flags & POOL_INTERN) { |
7efdcf32 S |
59 | pool->size -= sizeof (struct pool_extent); |
60 | flags |= POOL_APPEND; | |
61 | } | |
62 | pool->quantum = quantum ? quantum : MINALIGN; | |
63 | pool->bomb = bomb; | |
64 | pool->flags = flags; | |
65 | ||
66 | return pool; | |
67 | } | |
68 | ||
69 | void | |
70 | pool_destroy(alloc_pool_t p) | |
71 | { | |
72 | struct alloc_pool *pool = (struct alloc_pool *) p; | |
73 | struct pool_extent *cur, *next; | |
74 | ||
75 | if (!pool) | |
76 | return; | |
77 | ||
8ea17b50 | 78 | if (pool->live) { |
7efdcf32 S |
79 | cur = pool->live; |
80 | free(cur->start); | |
81 | if (!(pool->flags & POOL_APPEND)) | |
82 | free(cur); | |
83 | } | |
8ea17b50 | 84 | for (cur = pool->free; cur; cur = next) { |
7efdcf32 S |
85 | next = cur->next; |
86 | free(cur->start); | |
87 | if (!(pool->flags & POOL_APPEND)) | |
88 | free(cur); | |
89 | } | |
90 | free(pool); | |
91 | } | |
92 | ||
be20dc34 | 93 | void * |
4a19c3b2 | 94 | pool_alloc(alloc_pool_t p, size_t len, const char *bomb) |
7efdcf32 S |
95 | { |
96 | struct alloc_pool *pool = (struct alloc_pool *) p; | |
97 | if (!pool) | |
15f85b1f | 98 | return NULL; |
7efdcf32 S |
99 | |
100 | if (!len) | |
101 | len = pool->quantum; | |
102 | else if (pool->quantum > 1 && len % pool->quantum) | |
103 | len += pool->quantum - len % pool->quantum; | |
104 | ||
105 | if (len > pool->size) | |
106 | goto bomb; | |
107 | ||
8ea17b50 | 108 | if (!pool->live || len > pool->live->free) { |
7efdcf32 S |
109 | void *start; |
110 | size_t free; | |
111 | size_t bound; | |
112 | size_t sqew; | |
113 | size_t asize; | |
114 | ||
8ea17b50 | 115 | if (pool->live) { |
7efdcf32 S |
116 | pool->live->next = pool->free; |
117 | pool->free = pool->live; | |
118 | } | |
119 | ||
120 | free = pool->size; | |
121 | bound = 0; | |
122 | ||
123 | asize = pool->size; | |
124 | if (pool->flags & POOL_APPEND) | |
125 | asize += sizeof (struct pool_extent); | |
126 | ||
127 | if (!(start = (void *) malloc(asize))) | |
128 | goto bomb; | |
129 | ||
130 | if (pool->flags & POOL_CLEAR) | |
131 | memset(start, 0, pool->size); | |
132 | ||
133 | if (pool->flags & POOL_APPEND) | |
71b291d7 | 134 | pool->live = PTR_ADD(start, free); |
7efdcf32 | 135 | else if (!(pool->live = (struct pool_extent *) malloc(sizeof (struct pool_extent)))) |
7efdcf32 | 136 | goto bomb; |
7efdcf32 | 137 | if (pool->flags & POOL_QALIGN && pool->quantum > 1 |
8ea17b50 | 138 | && (sqew = (size_t)PTR_ADD(start, free) % pool->quantum)) { |
7efdcf32 S |
139 | bound += sqew; |
140 | free -= sqew; | |
141 | } | |
142 | pool->live->start = start; | |
143 | pool->live->free = free; | |
144 | pool->live->bound = bound; | |
145 | pool->live->next = NULL; | |
146 | ||
147 | pool->e_created++; | |
148 | } | |
149 | ||
150 | pool->n_allocated++; | |
151 | pool->b_allocated += len; | |
152 | ||
153 | pool->live->free -= len; | |
154 | ||
71b291d7 | 155 | return PTR_ADD(pool->live->start, pool->live->free); |
7efdcf32 S |
156 | |
157 | bomb: | |
158 | if (pool->bomb) | |
159 | (*pool->bomb)(bomb); | |
160 | return NULL; | |
161 | } | |
162 | ||
163 | void | |
164 | pool_free(alloc_pool_t p, size_t len, void *addr) | |
165 | { | |
166 | struct alloc_pool *pool = (struct alloc_pool *) p; | |
167 | struct pool_extent *cur; | |
168 | struct pool_extent *prev; | |
169 | ||
170 | if (!pool) | |
171 | return; | |
172 | ||
173 | if (!len) | |
174 | len = pool->quantum; | |
175 | else if (pool->quantum > 1 && len % pool->quantum) | |
176 | len += pool->quantum - len % pool->quantum; | |
177 | ||
8ea17b50 | 178 | if (!addr && pool->live) { |
7efdcf32 S |
179 | pool->live->next = pool->free; |
180 | pool->free = pool->live; | |
181 | pool->live = NULL; | |
182 | return; | |
183 | } | |
184 | pool->n_freed++; | |
185 | pool->b_freed += len; | |
186 | ||
187 | cur = pool->live; | |
8ea17b50 WD |
188 | if (cur && addr >= cur->start |
189 | && addr < PTR_ADD(cur->start, pool->size)) { | |
190 | if (addr == PTR_ADD(cur->start, cur->free)) { | |
7efdcf32 S |
191 | if (pool->flags & POOL_CLEAR) |
192 | memset(addr, 0, len); | |
193 | pool->b_freed += len; | |
8ea17b50 | 194 | } else |
7efdcf32 | 195 | cur->bound += len; |
8ea17b50 | 196 | if (cur->free + cur->bound >= pool->size) { |
7efdcf32 S |
197 | size_t sqew; |
198 | ||
199 | cur->free = pool->size; | |
200 | cur->bound = 0; | |
201 | if (pool->flags & POOL_QALIGN && pool->quantum > 1 | |
8ea17b50 | 202 | && (sqew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) { |
7efdcf32 S |
203 | cur->bound += sqew; |
204 | cur->free -= sqew; | |
205 | } | |
206 | } | |
207 | return; | |
208 | } | |
8ea17b50 | 209 | for (prev = NULL, cur = pool->free; cur; prev = cur, cur = cur->next) { |
7efdcf32 | 210 | if (addr >= cur->start |
04575bca | 211 | && addr < PTR_ADD(cur->start, pool->size)) |
7efdcf32 S |
212 | break; |
213 | } | |
214 | if (!cur) | |
215 | return; | |
216 | ||
8ea17b50 | 217 | if (prev) { |
7efdcf32 S |
218 | prev->next = cur->next; |
219 | cur->next = pool->free; | |
220 | pool->free = cur; | |
221 | } | |
222 | cur->bound += len; | |
223 | ||
8ea17b50 | 224 | if (cur->free + cur->bound >= pool->size) { |
7efdcf32 S |
225 | pool->free = cur->next; |
226 | ||
227 | free(cur->start); | |
228 | if (!(pool->flags & POOL_APPEND)) | |
229 | free(cur); | |
230 | pool->e_freed++; | |
231 | } | |
232 | return; | |
233 | } | |
234 | ||
235 | #define FDPRINT(label, value) \ | |
8ea17b50 WD |
236 | snprintf(buf, sizeof buf, label, value), \ |
237 | write(fd, buf, strlen(buf)) | |
7efdcf32 S |
238 | |
239 | #define FDEXTSTAT(ext) \ | |
8ea17b50 | 240 | snprintf(buf, sizeof buf, " %12ld %5ld\n", \ |
7efdcf32 S |
241 | (long) ext->free, \ |
242 | (long) ext->bound), \ | |
243 | write(fd, buf, strlen(buf)) | |
244 | ||
245 | void | |
246 | pool_stats(alloc_pool_t p, int fd, int summarize) | |
247 | { | |
248 | struct alloc_pool *pool = (struct alloc_pool *) p; | |
249 | struct pool_extent *cur; | |
250 | char buf[BUFSIZ]; | |
251 | ||
252 | if (!pool) | |
253 | return; | |
254 | ||
255 | FDPRINT(" Extent size: %12ld\n", (long) pool->size); | |
256 | FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum); | |
257 | FDPRINT(" Extents created: %12ld\n", pool->e_created); | |
258 | FDPRINT(" Extents freed: %12ld\n", pool->e_freed); | |
259 | FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated); | |
260 | FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed); | |
261 | FDPRINT(" Alloc bytes: %12.0f\n", (double) pool->b_allocated); | |
262 | FDPRINT(" Free bytes: %12.0f\n", (double) pool->b_freed); | |
263 | ||
264 | if (summarize) | |
265 | return; | |
266 | ||
267 | if (!pool->live && !pool->free) | |
268 | return; | |
269 | ||
270 | write(fd, "\n", 1); | |
271 | ||
272 | if (pool->live) | |
7efdcf32 | 273 | FDEXTSTAT(pool->live); |
c9bce0b8 | 274 | strlcpy(buf, " FREE BOUND\n", sizeof buf); |
7efdcf32 S |
275 | write(fd, buf, strlen(buf)); |
276 | ||
be20dc34 | 277 | for (cur = pool->free; cur; cur = cur->next) |
7efdcf32 | 278 | FDEXTSTAT(cur); |
7efdcf32 | 279 | } |