1 /*
2 * Copyright (C) 2004-2008 Christos Tsantilas
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA.
18 */
19
20 #include "common.h"
21 #include "c-icap.h"
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <ctype.h>
25 #include "ci_threads.h"
26 #include "debug.h"
27 #include "mem.h"
28 #include <assert.h>
29
30 int ci_buffers_init();
31
32 /*General Functions */
33 ci_mem_allocator_t *default_allocator = NULL;
34 int MEM_ALLOCATOR_POOL = -1;
35 int PACK_ALLOCATOR_POOL = -1;
36
37 static size_t sizeof_pack_allocator();
38 ci_mem_allocator_t *ci_create_pool_allocator(int items_size);
39
mem_init()40 CI_DECLARE_FUNC(int) mem_init()
41 {
42 int ret = -1;
43 ret = ci_buffers_init();
44
45 default_allocator = ci_create_os_allocator();
46 if (!default_allocator && ret ==-1)
47 ret = 0;
48
49 MEM_ALLOCATOR_POOL = ci_object_pool_register("ci_mem_allocator_t", sizeof(ci_mem_allocator_t));
50 assert(MEM_ALLOCATOR_POOL >= 0);
51
52 PACK_ALLOCATOR_POOL = ci_object_pool_register("pack_allocator_t", sizeof_pack_allocator());
53 assert(PACK_ALLOCATOR_POOL >= 0);
54
55 return ret;
56 }
57
mem_reset()58 void mem_reset()
59 {
60 }
61
62 void ci_object_pools_destroy();
ci_mem_exit()63 void ci_mem_exit()
64 {
65 ci_mem_allocator_destroy(default_allocator);
66 default_allocator = NULL;
67 ci_buffers_destroy();
68 MEM_ALLOCATOR_POOL = -1;
69 PACK_ALLOCATOR_POOL = -1;
70 ci_object_pools_destroy();
71 }
72
ci_mem_allocator_destroy(ci_mem_allocator_t * allocator)73 void ci_mem_allocator_destroy(ci_mem_allocator_t *allocator)
74 {
75 /* The allocator->destroy may release allocator struct */
76 int must_free = allocator->must_free;
77 void (*destroyer)(struct ci_mem_allocator *);
78 destroyer = allocator->destroy;
79
80 destroyer(allocator);
81 /*space for ci_mem_allocator_t struct is not always allocated
82 using malloc */
83 if (must_free == 1)
84 free(allocator);
85 else if (must_free == 2)
86 ci_object_pool_free(allocator);
87 /*
88 else if (allocator->must_free == 0) {
89 user is responsible to release the allocator object
90 or the object is already released while the
91 destroyer/allocator->destroy is called.
92 }
93 */
94
95 }
96
97 /******************/
alloc_mem_allocator_struct()98 static ci_mem_allocator_t *alloc_mem_allocator_struct()
99 {
100 ci_mem_allocator_t *alc;
101 if (MEM_ALLOCATOR_POOL < 0) {
102 alc = (ci_mem_allocator_t *) malloc(sizeof(ci_mem_allocator_t));
103 alc->must_free = 1;
104 } else {
105 alc = ci_object_pool_alloc(MEM_ALLOCATOR_POOL);
106 alc->must_free = 2;
107 }
108
109 return alc;
110 }
111
112 /*******************************************************************/
113 /* Buffers pool api functions */
114 #define BUF_SIGNATURE 0xAA55
115 struct mem_buffer_block {
116 uint16_t sig;
117 int ID;
118 union {
119 double __align;
120 char ptr[1];
121 } data;
122 };
123
124 #define offsetof(type,member) ((size_t) &((type*)0)->member)
125 #define PTR_OFFSET offsetof(struct mem_buffer_block,data.ptr[0])
126
127 ci_mem_allocator_t *short_buffers[16];
128 ci_mem_allocator_t *long_buffers[16];
129
130 enum {
131 BUF64_POOL, BUF128_POOL, BUF256_POOL,BUF512_POOL, BUF1024_POOL,
132 BUF2048_POOL, BUF4096_POOL, BUF8192_POOL, BUF16384_POOL, BUF32768_POOL,
133 BUF_END_POOL
134 };
135
136 static ci_mem_allocator_t *Pools[BUF_END_POOL];
137
ci_buffers_init()138 int ci_buffers_init()
139 {
140 int i;
141 memset(Pools, 0, sizeof(Pools));
142 memset(short_buffers, 0, sizeof(short_buffers));
143 memset(long_buffers, 0, sizeof(long_buffers));
144
145 Pools[BUF64_POOL] = ci_create_pool_allocator(64+PTR_OFFSET);
146 Pools[BUF128_POOL] = ci_create_pool_allocator(128+PTR_OFFSET);
147 Pools[BUF256_POOL] = ci_create_pool_allocator(256+PTR_OFFSET);
148 Pools[BUF512_POOL] = ci_create_pool_allocator(512+PTR_OFFSET);
149 Pools[BUF1024_POOL] = ci_create_pool_allocator(1024+PTR_OFFSET);
150
151 Pools[BUF2048_POOL] = ci_create_pool_allocator(2048+PTR_OFFSET);
152 Pools[BUF4096_POOL] = ci_create_pool_allocator(4096+PTR_OFFSET);
153 Pools[BUF8192_POOL] = ci_create_pool_allocator(8192+PTR_OFFSET);
154 Pools[BUF16384_POOL] = ci_create_pool_allocator(16384+PTR_OFFSET);
155 Pools[BUF32768_POOL] = ci_create_pool_allocator(32768+PTR_OFFSET);
156
157 short_buffers[0] = Pools[BUF64_POOL];
158 short_buffers[1] = Pools[BUF128_POOL];
159 short_buffers[2] = short_buffers[3] = Pools[BUF256_POOL];
160 short_buffers[4] = short_buffers[5] =
161 short_buffers[6] = short_buffers[7] = Pools[BUF512_POOL];
162 for (i = 8; i < 16; i++)
163 short_buffers[i] = Pools[BUF1024_POOL];
164
165 long_buffers[0] = Pools[BUF2048_POOL];
166 long_buffers[1] = Pools[BUF4096_POOL];
167 long_buffers[2] = long_buffers[3] = Pools[BUF8192_POOL];
168 long_buffers[4] = long_buffers[5] =
169 long_buffers[6] = long_buffers[7] = Pools[BUF16384_POOL];
170 for (i = 8; i < 16; i++)
171 long_buffers[i] = Pools[BUF32768_POOL];
172
173 return 1;
174 }
175
176 int short_buffer_sizes[16] = {
177 64,
178 128,
179 256,256,
180 512, 512, 512, 512,
181 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024
182 };
183
184 int long_buffer_sizes[16] = {
185 2048,
186 4096,
187 8192, 8192,
188 16384, 16384, 16384, 16384,
189 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768
190 };
191
ci_buffers_destroy()192 void ci_buffers_destroy()
193 {
194 int i;
195 for (i = 0; i < BUF_END_POOL; i++) {
196 if (Pools[i] != NULL)
197 ci_mem_allocator_destroy(Pools[i]);
198 }
199 memset(Pools, 0, sizeof(Pools));
200 memset(short_buffers, 0, sizeof(short_buffers));
201 memset(long_buffers, 0, sizeof(long_buffers));
202 }
203
ci_buffer_alloc(int block_size)204 void *ci_buffer_alloc(int block_size)
205 {
206 int type, size;
207 struct mem_buffer_block *block = NULL;
208 size = block_size + PTR_OFFSET;
209 type = (block_size-1) >> 6;
210 if (type< 16 && short_buffers[type] != NULL) {
211 block = short_buffers[type]->alloc(short_buffers[type], size);
212 } else if (type < 512) {
213 type = type >> 5;
214 if (long_buffers[type] != NULL) {
215 block = long_buffers[type]->alloc(long_buffers[type], size);
216 }
217 }
218
219 if (!block)
220 block = (struct mem_buffer_block *)malloc(size);
221
222 if (!block) {
223 ci_debug_printf(1, "Failed to allocate space for buffer of size:%d\n", block_size);
224 return NULL;
225 }
226
227 block->sig = BUF_SIGNATURE;
228 block->ID = block_size;
229 ci_debug_printf(8, "Geting buffer from pool %d:%d\n", block_size, type);
230 return (void *)block->data.ptr;
231 }
232
ci_buffer_blocksize(const void * data)233 size_t ci_buffer_blocksize(const void *data)
234 {
235 const struct mem_buffer_block *block;
236 int type;
237 size_t buffer_block_size = 0;
238 block = (const struct mem_buffer_block *)(data-PTR_OFFSET);
239 if (block->sig != BUF_SIGNATURE) {
240 ci_debug_printf(1,"ci_buffer_blocksize: ERROR, %p is not internal buffer. This is a bug!!!!\n", data);
241 return 0;
242 }
243
244 type = (block->ID - 1) >> 6;
245 if (type< 16 && short_buffers[type] != NULL) {
246 buffer_block_size = short_buffer_sizes[type];
247 } else if (type < 512) {
248 type = type >> 5;
249 if (long_buffers[type] != NULL) {
250 buffer_block_size = long_buffer_sizes[type];
251 }
252 }
253
254 if (!buffer_block_size)
255 buffer_block_size = block->ID;
256 return buffer_block_size;
257 }
258
ci_buffer_realloc(void * data,int block_size)259 void * ci_buffer_realloc(void *data, int block_size)
260 {
261 int buffer_size = 0;
262 struct mem_buffer_block *block;
263
264 if (!data)
265 return ci_buffer_alloc(block_size);
266
267 block = (struct mem_buffer_block *)(data-PTR_OFFSET);
268 if (block->sig != BUF_SIGNATURE) {
269 ci_debug_printf(1,"ci_buffer_realloc: ERROR, %p is not internal buffer. This is a bug!!!!\n", data);
270 return NULL;
271 }
272
273 buffer_size = ci_buffer_blocksize(data);
274 assert(buffer_size > 0);
275 ci_debug_printf(8, "Current block size for realloc: %d, requested block size: %d. The initial size: %d\n",
276 buffer_size, block_size, block->ID);
277
278 /*If no block_size created than our buffer actual size probably requires a realloc.....*/
279 if (block_size > buffer_size) {
280 ci_debug_printf(10, "We are going to allocate a bigger block of size: %d\n", block_size);
281 data = ci_buffer_alloc(block_size);
282 if (!data)
283 return NULL;
284 ci_debug_printf(10, "Preserve data of size: %d\n", block->ID);
285 memcpy(data, block->data.ptr, block->ID);
286 ci_buffer_free(block->data.ptr);
287 } else {
288 /*we neeed to update block->ID to the new requested size...*/
289 block->ID = block_size;
290 }
291
292 return data;
293 }
294
ci_buffer_free(void * data)295 void ci_buffer_free(void *data)
296 {
297 int block_size, type;
298 struct mem_buffer_block *block;
299
300 if (!data)
301 return;
302
303 block = (struct mem_buffer_block *)(data-PTR_OFFSET);
304 if (block->sig != BUF_SIGNATURE) {
305 ci_debug_printf(1,"ci_buffer_free: ERROR, %p is not internal buffer. This is a bug!!!!\n", data);
306 return;
307 }
308 block_size = block->ID;
309 type = (block_size-1) >> 6;
310 if (type < 16 && short_buffers[type] != NULL) {
311 short_buffers[type]->free(short_buffers[type], block);
312 ci_debug_printf(8, "Store buffer to short pool %d:%d\n", block_size, type);
313 } else if (type < 512) {
314 type = type >> 5;
315 if (long_buffers[type] != NULL)
316 long_buffers[type]->free(long_buffers[type], block);
317 else
318 free(block);
319 ci_debug_printf(8, "Store buffer to long pool %d:%d\n", block_size, type);
320 } else {
321 free(block);
322 }
323 }
324
325 /*******************************************************************/
326 /*Object pools */
327 #define OBJ_SIGNATURE 0x55AA
328 ci_mem_allocator_t **object_pools = NULL;
329 int object_pools_size = 0;
330 int object_pools_used = 0;
331
ci_object_pools_init()332 int ci_object_pools_init()
333 {
334 return 1;
335 }
336
ci_object_pools_destroy()337 void ci_object_pools_destroy()
338 {
339 int i;
340 for (i = 0; i < object_pools_used; i++) {
341 if (object_pools[i] != NULL)
342 ci_mem_allocator_destroy(object_pools[i]);
343 }
344 }
345
346 #define STEP 128
ci_object_pool_register(const char * name,int size)347 int ci_object_pool_register(const char *name, int size)
348 {
349 int ID, i;
350 ID = -1;
351 /*search for an empty position on object_pools and assign here?*/
352 if (object_pools == NULL) {
353 object_pools = malloc(STEP*sizeof(ci_mem_allocator_t *));
354 object_pools_size = STEP;
355 ID = 0;
356 } else {
357 for (i = 0; i < object_pools_used; i++) {
358 if (object_pools[i] == NULL) {
359 ID = i;
360 break;
361 }
362 }
363 if (ID == -1) {
364 if (object_pools_size == object_pools_used) {
365 object_pools_size += STEP;
366 object_pools = realloc(object_pools, object_pools_size*sizeof(ci_mem_allocator_t *));
367 }
368 ID=object_pools_used;
369 }
370 }
371 if (object_pools == NULL) //??????
372 return -1;
373
374 object_pools[ID] = ci_create_pool_allocator(size+PTR_OFFSET);
375
376 object_pools_used++;
377 return ID;
378 }
379
ci_object_pool_unregister(int id)380 void ci_object_pool_unregister(int id)
381 {
382 if (id >= object_pools_used || id < 0) {
383 /*A error message ....*/
384 return;
385 }
386 if (object_pools[id]) {
387 ci_mem_allocator_destroy(object_pools[id]);
388 object_pools[id] = NULL;
389 }
390
391 }
392
ci_object_pool_alloc(int id)393 void *ci_object_pool_alloc(int id)
394 {
395 struct mem_buffer_block *block = NULL;
396 if (id >= object_pools_used || id < 0 || !object_pools[id]) {
397 /*A error message ....*/
398 ci_debug_printf(1, "Invalid object pool %d. This is a BUG!\n", id);
399 return NULL;
400 }
401 block = object_pools[id]->alloc(object_pools[id], 1/*A small size smaller than obj size*/);
402 if (!block) {
403 ci_debug_printf(2, "Failed to allocate object from pool %d\n", id);
404 return NULL;
405 }
406 ci_debug_printf(8, "Allocating from objects pool object %d\n", id);
407 block->sig = OBJ_SIGNATURE;
408 block->ID = id;
409 return (void *)block->data.ptr;
410 }
411
ci_object_pool_free(void * ptr)412 void ci_object_pool_free(void *ptr)
413 {
414 struct mem_buffer_block *block = (struct mem_buffer_block *)(ptr-PTR_OFFSET);
415 if (block->sig != OBJ_SIGNATURE) {
416 ci_debug_printf(1,"ci_object_pool_free: ERROR, %p is not internal buffer. This is a bug!!!!\n", ptr);
417 return;
418 }
419 if (block->ID > object_pools_used || block->ID < 0 || !object_pools[block->ID]) {
420 ci_debug_printf(1,"ci_object_pool_free: ERROR, %p is pointing to corrupted mem? This is a bug!!!!\n", ptr);
421 return;
422 }
423 ci_debug_printf(8, "Storing to objects pool object %d\n", block->ID);
424 object_pools[block->ID]->free(object_pools[block->ID], block);
425 }
426
427 /*******************************************************************/
428 /*A simple allocator implementation which uses the system malloc */
429
os_allocator_alloc(ci_mem_allocator_t * allocator,size_t size)430 static void *os_allocator_alloc(ci_mem_allocator_t *allocator,size_t size)
431 {
432 return malloc(size);
433 }
434
os_allocator_free(ci_mem_allocator_t * allocator,void * p)435 static void os_allocator_free(ci_mem_allocator_t *allocator,void *p)
436 {
437 free(p);
438 }
439
os_allocator_reset(ci_mem_allocator_t * allocator)440 static void os_allocator_reset(ci_mem_allocator_t *allocator)
441 {
442 /*nothing to do*/
443 }
444
os_allocator_destroy(ci_mem_allocator_t * allocator)445 static void os_allocator_destroy(ci_mem_allocator_t *allocator)
446 {
447 /*nothing to do*/
448 }
449
ci_create_os_allocator()450 ci_mem_allocator_t *ci_create_os_allocator()
451 {
452 ci_mem_allocator_t *allocator = alloc_mem_allocator_struct();
453 if (!allocator)
454 return NULL;
455 allocator->alloc = os_allocator_alloc;
456 allocator->free = os_allocator_free;
457 allocator->reset = os_allocator_reset;
458 allocator->destroy = os_allocator_destroy;
459 allocator->data = NULL;
460 allocator->name = NULL;
461 allocator->type = OS_ALLOC;
462 return allocator;
463 }
464
465
466
467 /************************************************************/
468 /* The serial allocator implementation */
469
470
471 typedef struct serial_allocator {
472 void *memchunk;
473 void *curpos;
474 void *endpos;
475 struct serial_allocator *next;
476 } serial_allocator_t;
477
478
serial_allocator_build(int size)479 static serial_allocator_t *serial_allocator_build(int size)
480 {
481 serial_allocator_t *serial_alloc;
482 void *buffer;
483 size = _CI_ALIGN(size);
484 /*The serial_allocator and mem_allocator structures will be
485 allocated in the buffer */
486 if (size < sizeof(serial_allocator_t) + sizeof(ci_mem_allocator_t))
487 return NULL;
488 buffer = ci_buffer_alloc(size);
489 serial_alloc = buffer;
490 /*The allocated block size maybe is larger, than the requested.
491 Lets fix size to actual block size: */
492 size = ci_buffer_blocksize(buffer);
493
494 serial_alloc->memchunk = buffer + sizeof(serial_allocator_t);
495 size -= sizeof(serial_allocator_t);
496 serial_alloc->curpos = serial_alloc->memchunk;
497 serial_alloc->endpos = serial_alloc->memchunk + size;
498 serial_alloc->next = NULL;
499 return serial_alloc;
500 }
501
serial_allocation(serial_allocator_t * serial_alloc,size_t size)502 static void *serial_allocation(serial_allocator_t *serial_alloc, size_t size)
503 {
504 int max_size;
505 void *mem;
506 size = _CI_ALIGN(size); /*round size to a correct alignment size*/
507 max_size = serial_alloc->endpos - serial_alloc->memchunk;
508 if (size > max_size)
509 return NULL;
510
511 while (size > (serial_alloc->endpos - serial_alloc->curpos)) {
512 if (serial_alloc->next == NULL) {
513 serial_alloc->next = serial_allocator_build(max_size);
514 if (!serial_alloc->next)
515 return NULL;
516 }
517 serial_alloc = serial_alloc->next;
518 }
519
520 mem = serial_alloc->curpos;
521 serial_alloc->curpos += size;
522 return mem;
523 }
524
serial_allocator_alloc(ci_mem_allocator_t * allocator,size_t size)525 static void *serial_allocator_alloc(ci_mem_allocator_t *allocator,size_t size)
526 {
527 serial_allocator_t *serial_alloc = (serial_allocator_t *)allocator->data;
528
529 if (!serial_alloc)
530 return NULL;
531 return serial_allocation(serial_alloc, size);
532 }
533
serial_allocator_free(ci_mem_allocator_t * allocator,void * p)534 static void serial_allocator_free(ci_mem_allocator_t *allocator,void *p)
535 {
536 /* We can not free :-) */
537 }
538
serial_allocator_reset(ci_mem_allocator_t * allocator)539 static void serial_allocator_reset(ci_mem_allocator_t *allocator)
540 {
541 serial_allocator_t *serial_alloc, *sa;
542 void *tmp;
543 serial_alloc = (serial_allocator_t *)allocator->data;
544 serial_alloc->curpos = serial_alloc->memchunk + _CI_ALIGN(sizeof(ci_mem_allocator_t));
545 sa = serial_alloc->next;
546 serial_alloc->next = NULL;
547
548 /*release any other allocated chunk*/
549 while (sa) {
550 tmp = (void *)sa;
551 ci_buffer_free(tmp);
552 sa = sa->next;
553 }
554 }
555
serial_allocator_destroy(ci_mem_allocator_t * allocator)556 static void serial_allocator_destroy(ci_mem_allocator_t *allocator)
557 {
558 serial_allocator_t *cur, *next;
559
560 if (!allocator->data)
561 return;
562
563 cur = (serial_allocator_t *)allocator->data;
564 next = cur->next;
565 while (cur) {
566 ci_buffer_free((void *)cur);
567 cur = next;
568 if (next)
569 next = next->next;
570 }
571 }
572
ci_create_serial_allocator(int size)573 ci_mem_allocator_t *ci_create_serial_allocator(int size)
574 {
575 ci_mem_allocator_t *allocator;
576
577 serial_allocator_t *sdata= serial_allocator_build(size);
578
579 /*Allocate space for ci_mem_allocator_t from our serial allocator ...*/
580 allocator = serial_allocation(sdata, sizeof(ci_mem_allocator_t));
581 if (!allocator) {
582 ci_buffer_free((void *)sdata);
583 return NULL;
584 }
585 allocator->alloc = serial_allocator_alloc;
586 allocator->free = serial_allocator_free;
587 allocator->reset = serial_allocator_reset;
588 allocator->destroy = serial_allocator_destroy;
589 allocator->data = sdata;
590 allocator->name = NULL;
591 allocator->type = SERIAL_ALLOC;
592 /*It is allocated in our buffer space...*/
593 allocator->must_free = 0;
594 return allocator;
595 }
596 /****************************************************************/
597
598
599 typedef struct pack_allocator {
600 void *memchunk;
601 void *curpos;
602 void *endpos;
603 void *end;
604 int must_free;
605 } pack_allocator_t;
606
607 /*Api functions for pack allocator:*/
ci_pack_allocator_alloc_unaligned(ci_mem_allocator_t * allocator,size_t size)608 void *ci_pack_allocator_alloc_unaligned(ci_mem_allocator_t *allocator, size_t size)
609 {
610 int max_size;
611 void *mem;
612 pack_allocator_t *pack_alloc;
613
614 assert(allocator->type == PACK_ALLOC);
615 pack_alloc = (pack_allocator_t *)allocator->data;
616
617 if (!pack_alloc)
618 return NULL;
619
620 max_size = pack_alloc->endpos - pack_alloc->curpos;
621
622 if (size > max_size)
623 return NULL;
624
625 mem = pack_alloc->curpos;
626 pack_alloc->curpos += size;
627 return mem;
628 }
629
ci_pack_allocator_alloc(ci_mem_allocator_t * allocator,size_t size)630 void *ci_pack_allocator_alloc(ci_mem_allocator_t *allocator,size_t size)
631 {
632 size = _CI_ALIGN(size); /*round size to a correct alignment size*/
633 return ci_pack_allocator_alloc_unaligned(allocator, size);
634 }
635
ci_pack_allocator_alloc_from_rear(ci_mem_allocator_t * allocator,int size)636 void *ci_pack_allocator_alloc_from_rear(ci_mem_allocator_t *allocator, int size)
637 {
638 int max_size;
639 void *mem;
640 pack_allocator_t *pack_alloc;
641
642 assert(allocator->type == PACK_ALLOC);
643 pack_alloc = (pack_allocator_t *)allocator->data;
644
645 if (!pack_alloc)
646 return NULL;
647
648 size = _CI_ALIGN(size); /*round size to a correct alignment size*/
649 max_size = pack_alloc->endpos - pack_alloc->curpos;
650
651 if (size > max_size)
652 return NULL;
653
654 pack_alloc->endpos -= size; /*Allocate block from the end of memory block*/
655 mem = pack_alloc->endpos;
656 return mem;
657 }
658
ci_pack_allocator_free(ci_mem_allocator_t * allocator,void * p)659 void ci_pack_allocator_free(ci_mem_allocator_t *allocator,void *p)
660 {
661 /* We can not free :-) */
662 }
663
ci_pack_allocator_reset(ci_mem_allocator_t * allocator)664 void ci_pack_allocator_reset(ci_mem_allocator_t *allocator)
665 {
666 pack_allocator_t *pack_alloc;
667 assert(allocator->type == PACK_ALLOC);
668 pack_alloc = (pack_allocator_t *)allocator->data;
669 pack_alloc->curpos = pack_alloc->memchunk;
670 pack_alloc->endpos = pack_alloc->end;
671 }
672
ci_pack_allocator_destroy(ci_mem_allocator_t * allocator)673 void ci_pack_allocator_destroy(ci_mem_allocator_t *allocator)
674 {
675 pack_allocator_t *pack_alloc;
676 assert(allocator->type == PACK_ALLOC);
677 pack_alloc = (pack_allocator_t *)allocator->data;
678 if (pack_alloc->must_free != 0) {
679 ci_object_pool_free(allocator->data);
680 allocator->data = NULL;
681 }
682 }
683
684 /*If "off" is not aligned return the first smaller aligned offset*/
685 #define _ALIGNED_OFFSET(off) (off != _CI_ALIGN(off) ? _CI_ALIGN(off - _CI_NBYTES_ALIGNMENT) : off)
686
init_pack_allocator(ci_mem_allocator_t * allocator,pack_allocator_t * pack_alloc,char * memblock,size_t size,int free)687 ci_mem_allocator_t *init_pack_allocator(ci_mem_allocator_t *allocator, pack_allocator_t *pack_alloc, char *memblock, size_t size, int free)
688 {
689 /*We may not be able to use all of the memblock size.
690 We need to support allocating memory space from the end, so we
691 need to have aligned the pack_alloc->end to correctly calculate
692 memory block offsets from the end in ci_pack_allocator_alloc_from_rear
693 function.
694 */
695 size = _ALIGNED_OFFSET(size);
696 pack_alloc->memchunk = memblock;
697 pack_alloc->curpos =pack_alloc->memchunk;
698 pack_alloc->end = pack_alloc->memchunk + size;
699 pack_alloc->endpos = pack_alloc->end;
700 pack_alloc->must_free = free;
701
702 allocator->alloc = ci_pack_allocator_alloc;
703 allocator->free = ci_pack_allocator_free;
704 allocator->reset = ci_pack_allocator_reset;
705 allocator->destroy = ci_pack_allocator_destroy;
706 allocator->data = pack_alloc;
707 allocator->name = NULL;
708 allocator->type = PACK_ALLOC;
709 allocator->must_free = free;
710 return allocator;
711 }
712
ci_create_pack_allocator(char * memblock,size_t size)713 ci_mem_allocator_t *ci_create_pack_allocator(char *memblock, size_t size)
714 {
715 ci_mem_allocator_t *allocator;
716 pack_allocator_t *pack_alloc;
717 pack_alloc = ci_object_pool_alloc(PACK_ALLOCATOR_POOL);
718 if (!pack_alloc)
719 return NULL;
720 allocator = alloc_mem_allocator_struct();
721 if (!allocator) {
722 ci_object_pool_free(pack_alloc);
723 return NULL;
724 }
725
726 return init_pack_allocator(allocator, pack_alloc, memblock, size, 2);
727 }
728
729 /*similar to the above but allocates required space for pack_allocator on the given memblock*/
ci_create_pack_allocator_on_memblock(char * memblock,size_t size)730 ci_mem_allocator_t *ci_create_pack_allocator_on_memblock(char *memblock, size_t size)
731 {
732 ci_mem_allocator_t *allocator;
733
734 /*We need to allocate space on memblock for internal structures*/
735 if (size <= (_CI_ALIGN(sizeof(pack_allocator_t)) + _CI_ALIGN(sizeof(ci_mem_allocator_t))))
736 return NULL;
737
738 pack_allocator_t *pack_alloc = (pack_allocator_t *)memblock;
739 memblock += _CI_ALIGN(sizeof(pack_allocator_t));
740 size -= _CI_ALIGN(sizeof(pack_allocator_t));
741 allocator = (ci_mem_allocator_t *)memblock;
742 memblock += _CI_ALIGN(sizeof(ci_mem_allocator_t));
743 size -= _CI_ALIGN(sizeof(ci_mem_allocator_t));
744
745 return init_pack_allocator(allocator, pack_alloc, memblock, size, 0);
746 }
747
ci_pack_allocator_data_size(ci_mem_allocator_t * allocator)748 int ci_pack_allocator_data_size(ci_mem_allocator_t *allocator)
749 {
750 assert(allocator->type == PACK_ALLOC);
751 pack_allocator_t *pack_alloc = (pack_allocator_t *)allocator->data;
752 return (int) (pack_alloc->curpos - pack_alloc->memchunk) +
753 (pack_alloc->end - pack_alloc->endpos);
754 }
755
ci_pack_allocator_required_size()756 size_t ci_pack_allocator_required_size()
757 {
758 return _CI_ALIGN(sizeof(pack_allocator_t)) + _CI_ALIGN(sizeof(ci_mem_allocator_t));
759 }
760
sizeof_pack_allocator()761 static size_t sizeof_pack_allocator() {return sizeof(pack_allocator_t);}
762
ci_pack_allocator_set_start_pos(ci_mem_allocator_t * allocator,void * p)763 void ci_pack_allocator_set_start_pos(ci_mem_allocator_t *allocator, void *p)
764 {
765 pack_allocator_t *pack_alloc;
766 assert(allocator->type == PACK_ALLOC);
767 pack_alloc = (pack_allocator_t *)allocator->data;
768 assert(p >= pack_alloc->memchunk);
769 pack_alloc->curpos = p;
770 }
771
ci_pack_allocator_set_end_pos(ci_mem_allocator_t * allocator,void * p)772 void ci_pack_allocator_set_end_pos(ci_mem_allocator_t *allocator, void *p)
773 {
774 pack_allocator_t *pack_alloc;
775 assert(allocator->type == PACK_ALLOC);
776 pack_alloc = (pack_allocator_t *)allocator->data;
777 assert(p <= pack_alloc->end);
778 if (p == NULL)
779 pack_alloc->endpos = pack_alloc->end;
780 else
781 pack_alloc->endpos = p;
782 }
783
784 /****************************************************************/
785
786 struct mem_block_item {
787 void *data;
788 struct mem_block_item *next;
789 };
790
791 struct pool_allocator {
792 int items_size;
793 int strict;
794 int alloc_count;
795 int hits_count;
796 ci_thread_mutex_t mutex;
797 struct mem_block_item *free;
798 struct mem_block_item *allocated;
799 };
800
pool_allocator_build(int items_size,int strict)801 static struct pool_allocator *pool_allocator_build(int items_size,
802 int strict)
803 {
804 struct pool_allocator *palloc;
805
806 palloc = (struct pool_allocator *)malloc(sizeof(struct pool_allocator));
807
808 if (!palloc) {
809 return NULL;
810 }
811
812 palloc->items_size = items_size;
813 palloc->strict = strict;
814 palloc->free = NULL;
815 palloc->allocated = NULL;
816 palloc->alloc_count = 0;
817 palloc->hits_count = 0;
818 ci_thread_mutex_init(&palloc->mutex);
819 return palloc;
820 }
821
pool_allocator_alloc(ci_mem_allocator_t * allocator,size_t size)822 static void *pool_allocator_alloc(ci_mem_allocator_t *allocator,size_t size)
823 {
824 struct mem_block_item *mem_item;
825 void *data = NULL;
826 struct pool_allocator *palloc = (struct pool_allocator *)allocator->data;
827
828 if (size > palloc->items_size)
829 return NULL;
830
831 ci_thread_mutex_lock(&palloc->mutex);
832
833 if (palloc->free) {
834 mem_item = palloc->free;
835 palloc->free=palloc->free->next;
836 data = mem_item->data;
837 mem_item->data = NULL;
838 palloc->hits_count++;
839 } else {
840 mem_item = malloc(sizeof(struct mem_block_item));
841 mem_item->data = NULL;
842 data = malloc(palloc->items_size);
843 palloc->alloc_count++;
844 }
845
846 mem_item->next = palloc->allocated;
847 palloc->allocated = mem_item;
848
849 ci_thread_mutex_unlock(&palloc->mutex);
850 ci_debug_printf(8, "pool hits: %d allocations: %d\n", palloc->hits_count, palloc->alloc_count);
851 return data;
852 }
853
pool_allocator_free(ci_mem_allocator_t * allocator,void * p)854 static void pool_allocator_free(ci_mem_allocator_t *allocator,void *p)
855 {
856 struct mem_block_item *mem_item;
857 struct pool_allocator *palloc = (struct pool_allocator *)allocator->data;
858
859 ci_thread_mutex_lock(&palloc->mutex);
860 if (!palloc->allocated) {
861 /*Yes can happen! after a reset but users did not free all objects*/
862 free(p);
863 } else {
864 mem_item = palloc->allocated;
865 palloc->allocated = palloc->allocated->next;
866
867 mem_item->data = p;
868 mem_item->next = palloc->free;
869 palloc->free = mem_item;
870 }
871 ci_thread_mutex_unlock(&palloc->mutex);
872 }
873
pool_allocator_reset(ci_mem_allocator_t * allocator)874 static void pool_allocator_reset(ci_mem_allocator_t *allocator)
875 {
876 struct mem_block_item *mem_item, *cur;
877 struct pool_allocator *palloc = (struct pool_allocator *)allocator->data;
878
879 ci_thread_mutex_lock(&palloc->mutex);
880 if (palloc->allocated) {
881 mem_item = palloc->allocated;
882 while (mem_item != NULL) {
883 cur = mem_item;
884 mem_item = mem_item->next;
885 free(cur);
886 }
887
888 }
889 palloc->allocated = NULL;
890 if (palloc->free) {
891 mem_item = palloc->free;
892 while (mem_item != NULL) {
893 cur = mem_item;
894 mem_item = mem_item->next;
895 free(cur->data);
896 free(cur);
897 }
898 }
899 palloc->free = NULL;
900 ci_thread_mutex_unlock(&palloc->mutex);
901 }
902
903
pool_allocator_destroy(ci_mem_allocator_t * allocator)904 static void pool_allocator_destroy(ci_mem_allocator_t *allocator)
905 {
906 pool_allocator_reset(allocator);
907 struct pool_allocator *palloc = (struct pool_allocator *)allocator->data;
908 ci_thread_mutex_destroy(&palloc->mutex);
909 free(palloc);
910 }
911
ci_create_pool_allocator(int items_size)912 ci_mem_allocator_t *ci_create_pool_allocator(int items_size)
913 {
914 struct pool_allocator *palloc;
915 ci_mem_allocator_t *allocator;
916
917 palloc = pool_allocator_build(items_size, 0);
918 /*Use always malloc for ci_mem_alocator struct.*/
919 allocator = (ci_mem_allocator_t *) malloc(sizeof(ci_mem_allocator_t));
920 if (!allocator)
921 return NULL;
922 allocator->alloc = pool_allocator_alloc;
923 allocator->free = pool_allocator_free;
924 allocator->reset = pool_allocator_reset;
925 allocator->destroy = pool_allocator_destroy;
926 allocator->data = palloc;
927 allocator->name = NULL;
928 allocator->type = POOL_ALLOC;
929 allocator->must_free = 1;
930 return allocator;
931 }
932