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