| 37 ) { |
37 ) { |
| 38 if (needed_capacity <= pool->capacity) return 0; |
38 if (needed_capacity <= pool->capacity) return 0; |
| 39 size_t newcap = pool->capacity >= 1000 ? |
39 size_t newcap = pool->capacity >= 1000 ? |
| 40 pool->capacity + 1000 : pool->capacity * 2; |
40 pool->capacity + 1000 : pool->capacity * 2; |
| 41 size_t newmsize; |
41 size_t newmsize; |
| |
42 // LCOV_EXCL_START |
| 42 if (pool->capacity > newcap |
43 if (pool->capacity > newcap |
| 43 || cx_szmul(newcap, sizeof(void*), &newmsize)) { |
44 || cx_szmul(newcap, sizeof(void*), &newmsize)) { |
| 44 errno = EOVERFLOW; |
45 errno = EOVERFLOW; |
| 45 return 1; |
46 return 1; |
| 46 } |
47 } // LCOV_EXCL_STOP |
| 47 void **newdata = cxReallocDefault(pool->data, newmsize); |
48 void **newdata = cxReallocDefault(pool->data, newmsize); |
| 48 if (newdata == NULL) return 1; |
49 if (newdata == NULL) return 1; |
| 49 pool->data = newdata; |
50 pool->data = newdata; |
| 50 pool->capacity = newcap; |
51 pool->capacity = newcap; |
| 51 return 0; |
52 return 0; |
| 57 ) { |
58 ) { |
| 58 if (needed_capacity <= pool->registered_capacity) return 0; |
59 if (needed_capacity <= pool->registered_capacity) return 0; |
| 59 // we do not expect so many registrations |
60 // we do not expect so many registrations |
| 60 size_t newcap = pool->registered_capacity + 8; |
61 size_t newcap = pool->registered_capacity + 8; |
| 61 size_t newmsize; |
62 size_t newmsize; |
| |
63 // LCOV_EXCL_START |
| 62 if (pool->registered_capacity > newcap || cx_szmul(newcap, |
64 if (pool->registered_capacity > newcap || cx_szmul(newcap, |
| 63 sizeof(struct cx_mempool_foreign_memory_s), &newmsize)) { |
65 sizeof(struct cx_mempool_foreign_memory_s), &newmsize)) { |
| 64 errno = EOVERFLOW; |
66 errno = EOVERFLOW; |
| 65 return 1; |
67 return 1; |
| 66 } |
68 } // LCOV_EXCL_STOP |
| 67 void *newdata = cxReallocDefault(pool->registered, newmsize); |
69 void *newdata = cxReallocDefault(pool->registered, newmsize); |
| 68 if (newdata == NULL) return 1; |
70 if (newdata == NULL) return 1; |
| 69 pool->registered = newdata; |
71 pool->registered = newdata; |
| 70 pool->registered_capacity = newcap; |
72 pool->registered_capacity = newcap; |
| 71 return 0; |
73 return 0; |
| 76 size_t n |
78 size_t n |
| 77 ) { |
79 ) { |
| 78 struct cx_mempool_s *pool = p; |
80 struct cx_mempool_s *pool = p; |
| 79 |
81 |
| 80 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { |
82 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { |
| 81 return NULL; |
83 return NULL; // LCOV_EXCL_LINE |
| 82 } |
84 } |
| 83 |
85 |
| 84 struct cx_mempool_memory_s *mem = |
86 struct cx_mempool_memory_s *mem = |
| 85 cxMallocDefault(sizeof(struct cx_mempool_memory_s) + n); |
87 cxMallocDefault(sizeof(struct cx_mempool_memory_s) + n); |
| 86 if (mem == NULL) return NULL; |
88 if (mem == NULL) return NULL; |
| 105 if (ptr == NULL) return NULL; |
107 if (ptr == NULL) return NULL; |
| 106 memset(ptr, 0, nelem * elsize); |
108 memset(ptr, 0, nelem * elsize); |
| 107 return ptr; |
109 return ptr; |
| 108 } |
110 } |
| 109 |
111 |
| |
112 static void cx_mempool_free_simple( |
| |
113 void *p, |
| |
114 void *ptr |
| |
115 ) { |
| |
116 if (!ptr) return; |
| |
117 struct cx_mempool_s *pool = p; |
| |
118 |
| |
119 struct cx_mempool_memory_s *mem = |
| |
120 (void*) ((char *) ptr - sizeof(struct cx_mempool_memory_s)); |
| |
121 |
| |
122 for (size_t i = 0; i < pool->size; i++) { |
| |
123 if (mem == pool->data[i]) { |
| |
124 if (mem->destructor) { |
| |
125 mem->destructor(mem->c); |
| |
126 } |
| |
127 if (pool->destr) { |
| |
128 pool->destr(mem->c); |
| |
129 } |
| |
130 if (pool->destr2) { |
| |
131 pool->destr2(pool->destr2_data, mem->c); |
| |
132 } |
| |
133 cxFreeDefault(mem); |
| |
134 size_t last_index = pool->size - 1; |
| |
135 if (i != last_index) { |
| |
136 pool->data[i] = pool->data[last_index]; |
| |
137 pool->data[last_index] = NULL; |
| |
138 } |
| |
139 pool->size--; |
| |
140 return; |
| |
141 } |
| |
142 } |
| |
143 abort(); // LCOV_EXCL_LINE |
| |
144 } |
| |
145 |
| 110 static void *cx_mempool_realloc_simple( |
146 static void *cx_mempool_realloc_simple( |
| 111 void *p, |
147 void *p, |
| 112 void *ptr, |
148 void *ptr, |
| 113 size_t n |
149 size_t n |
| 114 ) { |
150 ) { |
| |
151 if (ptr == NULL) { |
| |
152 return cx_mempool_malloc_simple(p, n); |
| |
153 } |
| |
154 if (n == 0) { |
| |
155 cx_mempool_free_simple(p, ptr); |
| |
156 return NULL; |
| |
157 } |
| 115 struct cx_mempool_s *pool = p; |
158 struct cx_mempool_s *pool = p; |
| 116 |
159 |
| 117 const unsigned overhead = sizeof(struct cx_mempool_memory_s); |
160 const unsigned overhead = sizeof(struct cx_mempool_memory_s); |
| 118 struct cx_mempool_memory_s *mem = |
161 struct cx_mempool_memory_s *mem = |
| 119 (void *) (((char *) ptr) - overhead); |
162 (void *) (((char *) ptr) - overhead); |
| 128 return ((char*)newm) + overhead; |
171 return ((char*)newm) + overhead; |
| 129 } |
172 } |
| 130 } |
173 } |
| 131 abort(); // LCOV_EXCL_LINE |
174 abort(); // LCOV_EXCL_LINE |
| 132 } else { |
175 } else { |
| 133 return ptr; |
176 // unfortunately glibc() realloc seems to always move |
| 134 } |
177 return ptr; // LCOV_EXCL_LINE |
| 135 } |
178 } |
| 136 |
|
| 137 static void cx_mempool_free_simple( |
|
| 138 void *p, |
|
| 139 void *ptr |
|
| 140 ) { |
|
| 141 if (!ptr) return; |
|
| 142 struct cx_mempool_s *pool = p; |
|
| 143 |
|
| 144 struct cx_mempool_memory_s *mem = |
|
| 145 (void*) ((char *) ptr - sizeof(struct cx_mempool_memory_s)); |
|
| 146 |
|
| 147 for (size_t i = 0; i < pool->size; i++) { |
|
| 148 if (mem == pool->data[i]) { |
|
| 149 if (mem->destructor) { |
|
| 150 mem->destructor(mem->c); |
|
| 151 } |
|
| 152 if (pool->destr) { |
|
| 153 pool->destr(mem->c); |
|
| 154 } |
|
| 155 if (pool->destr2) { |
|
| 156 pool->destr2(pool->destr2_data, mem->c); |
|
| 157 } |
|
| 158 cxFreeDefault(mem); |
|
| 159 size_t last_index = pool->size - 1; |
|
| 160 if (i != last_index) { |
|
| 161 pool->data[i] = pool->data[last_index]; |
|
| 162 pool->data[last_index] = NULL; |
|
| 163 } |
|
| 164 pool->size--; |
|
| 165 return; |
|
| 166 } |
|
| 167 } |
|
| 168 abort(); // LCOV_EXCL_LINE |
|
| 169 } |
179 } |
| 170 |
180 |
| 171 static void cx_mempool_free_all_simple(const struct cx_mempool_s *pool) { |
181 static void cx_mempool_free_all_simple(const struct cx_mempool_s *pool) { |
| 172 const bool has_destr = pool->destr; |
182 const bool has_destr = pool->destr; |
| 173 const bool has_destr2 = pool->destr2; |
183 const bool has_destr2 = pool->destr2; |
| 198 size_t n |
208 size_t n |
| 199 ) { |
209 ) { |
| 200 struct cx_mempool_s *pool = p; |
210 struct cx_mempool_s *pool = p; |
| 201 |
211 |
| 202 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { |
212 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { |
| 203 return NULL; |
213 return NULL; // LCOV_EXCL_LINE |
| 204 } |
214 } |
| 205 |
215 |
| 206 struct cx_mempool_memory2_s *mem = |
216 struct cx_mempool_memory2_s *mem = |
| 207 cxMallocDefault(sizeof(struct cx_mempool_memory_s) + n); |
217 cxMallocDefault(sizeof(struct cx_mempool_memory2_s) + n); |
| 208 if (mem == NULL) return NULL; |
218 if (mem == NULL) return NULL; |
| 209 mem->destructor = NULL; |
219 mem->destructor = NULL; |
| 210 mem->data = NULL; |
220 mem->data = NULL; |
| 211 pool->data[pool->size] = mem; |
221 pool->data[pool->size] = mem; |
| 212 pool->size++; |
222 pool->size++; |
| 228 if (ptr == NULL) return NULL; |
238 if (ptr == NULL) return NULL; |
| 229 memset(ptr, 0, nelem * elsize); |
239 memset(ptr, 0, nelem * elsize); |
| 230 return ptr; |
240 return ptr; |
| 231 } |
241 } |
| 232 |
242 |
| |
243 static void cx_mempool_free_advanced( |
| |
244 void *p, |
| |
245 void *ptr |
| |
246 ) { |
| |
247 if (!ptr) return; |
| |
248 struct cx_mempool_s *pool = p; |
| |
249 |
| |
250 struct cx_mempool_memory2_s *mem = |
| |
251 (void*) ((char *) ptr - sizeof(struct cx_mempool_memory2_s)); |
| |
252 |
| |
253 for (size_t i = 0; i < pool->size; i++) { |
| |
254 if (mem == pool->data[i]) { |
| |
255 if (mem->destructor) { |
| |
256 mem->destructor(mem->data, mem->c); |
| |
257 } |
| |
258 if (pool->destr) { |
| |
259 pool->destr(mem->c); |
| |
260 } |
| |
261 if (pool->destr2) { |
| |
262 pool->destr2(pool->destr2_data, mem->c); |
| |
263 } |
| |
264 cxFreeDefault(mem); |
| |
265 size_t last_index = pool->size - 1; |
| |
266 if (i != last_index) { |
| |
267 pool->data[i] = pool->data[last_index]; |
| |
268 pool->data[last_index] = NULL; |
| |
269 } |
| |
270 pool->size--; |
| |
271 return; |
| |
272 } |
| |
273 } |
| |
274 abort(); // LCOV_EXCL_LINE |
| |
275 } |
| |
276 |
| 233 static void *cx_mempool_realloc_advanced( |
277 static void *cx_mempool_realloc_advanced( |
| 234 void *p, |
278 void *p, |
| 235 void *ptr, |
279 void *ptr, |
| 236 size_t n |
280 size_t n |
| 237 ) { |
281 ) { |
| |
282 if (ptr == NULL) { |
| |
283 return cx_mempool_malloc_advanced(p, n); |
| |
284 } |
| |
285 if (n == 0) { |
| |
286 cx_mempool_free_advanced(p, ptr); |
| |
287 return NULL; |
| |
288 } |
| 238 struct cx_mempool_s *pool = p; |
289 struct cx_mempool_s *pool = p; |
| 239 |
290 |
| 240 const unsigned overhead = sizeof(struct cx_mempool_memory2_s); |
291 const unsigned overhead = sizeof(struct cx_mempool_memory2_s); |
| 241 struct cx_mempool_memory2_s *mem = |
292 struct cx_mempool_memory2_s *mem = |
| 242 (void *) (((char *) ptr) - overhead); |
293 (void *) (((char *) ptr) - overhead); |
| 251 return ((char*)newm) + overhead; |
302 return ((char*)newm) + overhead; |
| 252 } |
303 } |
| 253 } |
304 } |
| 254 abort(); // LCOV_EXCL_LINE |
305 abort(); // LCOV_EXCL_LINE |
| 255 } else { |
306 } else { |
| 256 return ptr; |
307 // unfortunately glibc() realloc seems to always move |
| 257 } |
308 return ptr; // LCOV_EXCL_LINE |
| 258 } |
309 } |
| 259 |
|
| 260 static void cx_mempool_free_advanced( |
|
| 261 void *p, |
|
| 262 void *ptr |
|
| 263 ) { |
|
| 264 if (!ptr) return; |
|
| 265 struct cx_mempool_s *pool = p; |
|
| 266 |
|
| 267 struct cx_mempool_memory2_s *mem = |
|
| 268 (void*) ((char *) ptr - sizeof(struct cx_mempool_memory2_s)); |
|
| 269 |
|
| 270 for (size_t i = 0; i < pool->size; i++) { |
|
| 271 if (mem == pool->data[i]) { |
|
| 272 if (mem->destructor) { |
|
| 273 mem->destructor(mem->data, mem->c); |
|
| 274 } |
|
| 275 if (pool->destr) { |
|
| 276 pool->destr(mem->c); |
|
| 277 } |
|
| 278 if (pool->destr2) { |
|
| 279 pool->destr2(pool->destr2_data, mem->c); |
|
| 280 } |
|
| 281 cxFreeDefault(mem); |
|
| 282 size_t last_index = pool->size - 1; |
|
| 283 if (i != last_index) { |
|
| 284 pool->data[i] = pool->data[last_index]; |
|
| 285 pool->data[last_index] = NULL; |
|
| 286 } |
|
| 287 pool->size--; |
|
| 288 return; |
|
| 289 } |
|
| 290 } |
|
| 291 abort(); // LCOV_EXCL_LINE |
|
| 292 } |
310 } |
| 293 |
311 |
| 294 static void cx_mempool_free_all_advanced(const struct cx_mempool_s *pool) { |
312 static void cx_mempool_free_all_advanced(const struct cx_mempool_s *pool) { |
| 295 const bool has_destr = pool->destr; |
313 const bool has_destr = pool->destr; |
| 296 const bool has_destr2 = pool->destr2; |
314 const bool has_destr2 = pool->destr2; |
| 322 size_t n |
340 size_t n |
| 323 ) { |
341 ) { |
| 324 struct cx_mempool_s *pool = p; |
342 struct cx_mempool_s *pool = p; |
| 325 |
343 |
| 326 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { |
344 if (cx_mempool_ensure_capacity(pool, pool->size + 1)) { |
| 327 return NULL; |
345 return NULL; // LCOV_EXCL_LINE |
| 328 } |
346 } |
| 329 |
347 |
| 330 void *mem = cxMallocDefault(n); |
348 void *mem = cxMallocDefault(n); |
| 331 if (mem == NULL) return NULL; |
349 if (mem == NULL) return NULL; |
| 332 pool->data[pool->size] = mem; |
350 pool->data[pool->size] = mem; |
| 349 if (ptr == NULL) return NULL; |
367 if (ptr == NULL) return NULL; |
| 350 memset(ptr, 0, nelem * elsize); |
368 memset(ptr, 0, nelem * elsize); |
| 351 return ptr; |
369 return ptr; |
| 352 } |
370 } |
| 353 |
371 |
| |
372 static void cx_mempool_free_pure( |
| |
373 void *p, |
| |
374 void *ptr |
| |
375 ) { |
| |
376 if (!ptr) return; |
| |
377 struct cx_mempool_s *pool = p; |
| |
378 |
| |
379 for (size_t i = 0; i < pool->size; i++) { |
| |
380 if (ptr == pool->data[i]) { |
| |
381 if (pool->destr) { |
| |
382 pool->destr(ptr); |
| |
383 } |
| |
384 if (pool->destr2) { |
| |
385 pool->destr2(pool->destr2_data, ptr); |
| |
386 } |
| |
387 cxFreeDefault(ptr); |
| |
388 size_t last_index = pool->size - 1; |
| |
389 if (i != last_index) { |
| |
390 pool->data[i] = pool->data[last_index]; |
| |
391 pool->data[last_index] = NULL; |
| |
392 } |
| |
393 pool->size--; |
| |
394 return; |
| |
395 } |
| |
396 } |
| |
397 abort(); // LCOV_EXCL_LINE |
| |
398 } |
| |
399 |
| 354 static void *cx_mempool_realloc_pure( |
400 static void *cx_mempool_realloc_pure( |
| 355 void *p, |
401 void *p, |
| 356 void *ptr, |
402 void *ptr, |
| 357 size_t n |
403 size_t n |
| 358 ) { |
404 ) { |
| |
405 if (ptr == NULL) { |
| |
406 return cx_mempool_malloc_pure(p, n); |
| |
407 } |
| |
408 if (n == 0) { |
| |
409 cx_mempool_free_pure(p, ptr); |
| |
410 return NULL; |
| |
411 } |
| 359 struct cx_mempool_s *pool = p; |
412 struct cx_mempool_s *pool = p; |
| 360 void *newm = cxReallocDefault(ptr, n); |
413 void *newm = cxReallocDefault(ptr, n); |
| 361 if (newm == NULL) return NULL; |
414 if (newm == NULL) return NULL; |
| 362 if (ptr != newm) { |
415 if (ptr != newm) { |
| 363 for (size_t i = 0; i < pool->size; i++) { |
416 for (size_t i = 0; i < pool->size; i++) { |
| 366 return newm; |
419 return newm; |
| 367 } |
420 } |
| 368 } |
421 } |
| 369 abort(); // LCOV_EXCL_LINE |
422 abort(); // LCOV_EXCL_LINE |
| 370 } else { |
423 } else { |
| 371 return ptr; |
424 // unfortunately glibc() realloc seems to always move |
| 372 } |
425 return ptr; // LCOV_EXCL_LINE |
| 373 } |
426 } |
| 374 |
|
| 375 static void cx_mempool_free_pure( |
|
| 376 void *p, |
|
| 377 void *ptr |
|
| 378 ) { |
|
| 379 if (!ptr) return; |
|
| 380 struct cx_mempool_s *pool = p; |
|
| 381 |
|
| 382 for (size_t i = 0; i < pool->size; i++) { |
|
| 383 if (ptr == pool->data[i]) { |
|
| 384 if (pool->destr) { |
|
| 385 pool->destr(ptr); |
|
| 386 } |
|
| 387 if (pool->destr2) { |
|
| 388 pool->destr2(pool->destr2_data, ptr); |
|
| 389 } |
|
| 390 cxFreeDefault(ptr); |
|
| 391 size_t last_index = pool->size - 1; |
|
| 392 if (i != last_index) { |
|
| 393 pool->data[i] = pool->data[last_index]; |
|
| 394 pool->data[last_index] = NULL; |
|
| 395 } |
|
| 396 pool->size--; |
|
| 397 return; |
|
| 398 } |
|
| 399 } |
|
| 400 abort(); // LCOV_EXCL_LINE |
|
| 401 } |
427 } |
| 402 |
428 |
| 403 static void cx_mempool_free_all_pure(const struct cx_mempool_s *pool) { |
429 static void cx_mempool_free_all_pure(const struct cx_mempool_s *pool) { |
| 404 const bool has_destr = pool->destr; |
430 const bool has_destr = pool->destr; |
| 405 const bool has_destr2 = pool->destr2; |
431 const bool has_destr2 = pool->destr2; |
| 524 enum cx_mempool_type type |
550 enum cx_mempool_type type |
| 525 ) { |
551 ) { |
| 526 if (capacity == 0) capacity = 16; |
552 if (capacity == 0) capacity = 16; |
| 527 size_t poolsize; |
553 size_t poolsize; |
| 528 if (cx_szmul(capacity, sizeof(void*), &poolsize)) { |
554 if (cx_szmul(capacity, sizeof(void*), &poolsize)) { |
| |
555 // LCOV_EXCL_START |
| 529 errno = EOVERFLOW; |
556 errno = EOVERFLOW; |
| 530 return NULL; |
557 return NULL; |
| 531 } |
558 } // LCOV_EXCL_STOP |
| 532 |
559 |
| 533 CxAllocator *provided_allocator = cxMallocDefault(sizeof(CxAllocator)); |
560 CxAllocator *provided_allocator = cxMallocDefault(sizeof(CxAllocator)); |
| 534 if (provided_allocator == NULL) { // LCOV_EXCL_START |
561 if (provided_allocator == NULL) { // LCOV_EXCL_START |
| 535 return NULL; |
562 return NULL; |
| 536 } // LCOV_EXCL_STOP |
563 } // LCOV_EXCL_STOP |
| 537 |
564 |
| 538 CxMempool *pool = cxCallocDefault(1, sizeof(CxMempool)); |
565 CxMempool *pool = cxCallocDefault(1, sizeof(CxMempool)); |
| 539 if (pool == NULL) { |
566 if (pool == NULL) { // LCOV_EXCL_START |
| 540 cxFreeDefault(provided_allocator); |
567 cxFreeDefault(provided_allocator); |
| 541 return NULL; |
568 return NULL; |
| 542 } |
569 } // LCOV_EXCL_STOP |
| 543 |
570 |
| 544 provided_allocator->data = pool; |
571 provided_allocator->data = pool; |
| 545 pool->allocator = provided_allocator; |
572 pool->allocator = provided_allocator; |
| 546 if (type == CX_MEMPOOL_TYPE_SIMPLE) { |
573 if (type == CX_MEMPOOL_TYPE_SIMPLE) { |
| 547 provided_allocator->cl = &cx_mempool_simple_allocator_class; |
574 provided_allocator->cl = &cx_mempool_simple_allocator_class; |