89985a4c723676492d8be1c902c4cb4e708bdde7
[sip-router] / src / core / mem / f_malloc.c
1 /*
2  * Copyright (C) 2001-2003 FhG Fokus
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19
20 /**
21  * \file
22  * \brief Simple, very fast, malloc library
23  * \ingroup mem
24  */
25
26
27 #if defined(F_MALLOC)
28
29 #include <string.h>
30 #include <stdlib.h>
31
32 #include "f_malloc.h"
33 #include "../dprint.h"
34 #include "../globals.h"
35 #include "../compiler_opt.h"
36 #include "memdbg.h"
37 #include "../bit_scan.h"
38 #include "../cfg/cfg.h" /* memlog */
39 #ifdef MALLOC_STATS
40 #include "../events.h"
41 #endif
42
43
44 /* useful macros */
45
46 #define FRAG_NEXT(f) \
47         ((struct fm_frag*)((char*)(f)+sizeof(struct fm_frag)+(f)->size ))
48
49 #define FRAG_OVERHEAD   (sizeof(struct fm_frag))
50 #define INIT_OVERHEAD   \
51         (ROUNDUP(sizeof(struct fm_block))+2*sizeof(struct fm_frag))
52
53
54
55 /** ROUNDTO= 2^k so the following works */
56 #define ROUNDTO_MASK    (~((unsigned long)ROUNDTO-1))
57 #define ROUNDUP(s)              (((s)+(ROUNDTO-1))&ROUNDTO_MASK)
58 #define ROUNDDOWN(s)    ((s)&ROUNDTO_MASK)
59
60
61
62 /** finds the hash value for s, s=ROUNDTO multiple */
63 #define GET_HASH(s)   ( ((unsigned long)(s)<=F_MALLOC_OPTIMIZE)?\
64                                                         (unsigned long)(s)/ROUNDTO: \
65                                                         F_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
66                                                                 F_MALLOC_OPTIMIZE_FACTOR+1 )
67
68 #define UN_HASH(h)      ( ((unsigned long)(h)<=(F_MALLOC_OPTIMIZE/ROUNDTO))?\
69                                                 (unsigned long)(h)*ROUNDTO: \
70                                                 1UL<<((unsigned long)(h)-F_MALLOC_OPTIMIZE/ROUNDTO+\
71                                                         F_MALLOC_OPTIMIZE_FACTOR-1)\
72                                         )
73
74
75 #ifdef F_MALLOC_HASH_BITMAP
76
77 #define fm_bmp_set(qm, b) \
78         do{ \
79                 (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] |= \
80                                                                                         1UL<<((b)%FM_HASH_BMP_BITS); \
81         }while(0)
82
83 #define fm_bmp_reset(qm, b) \
84         do{ \
85                 (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] &= \
86                                                                                         ~(1UL<<((b)%FM_HASH_BMP_BITS)); \
87         }while(0)
88
89 /** returns 0 if not set, !=0 if set */
90 #define fm_bmp_is_set(qm, b) \
91         ((qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] & (1UL<<((b)%FM_HASH_BMP_BITS)))
92
93
94 #define fm_is_free(f) ((f)->is_free)
95
96 /**
97  * \brief Find the first free fragment in a memory block
98  *
99  * Find the first free fragment in a memory block
100  * \param qm searched memory block
101  * \param start start value
102  * \return index for free fragment
103  */
104 inline static int fm_bmp_first_set(struct fm_block* qm, int start)
105 {
106         int bmp_idx;
107         int bit;
108         int r;
109         fm_hash_bitmap_t test_val;
110         fm_hash_bitmap_t v;
111
112         bmp_idx=start/FM_HASH_BMP_BITS;
113         bit=start%FM_HASH_BMP_BITS;
114         test_val=1UL <<((unsigned long)bit);
115         if (qm->free_bitmap[bmp_idx] & test_val)
116                 return start;
117         else if (qm->free_bitmap[bmp_idx] & ~(test_val-1)){
118 #if 0
119                 test_val<<=1;
120                 for (r=bit+1; r<FM_HASH_BMP_BITS; r++, test_val<<=1){
121                         if (qm->free_bitmap[bmp_idx] & test_val)
122                                 return (start-bit+r);
123                 }
124 #endif
125                 v=qm->free_bitmap[bmp_idx]>>(bit+1);
126                 return start+1+bit_scan_forward((unsigned long)v);
127         }
128         for (r=bmp_idx+1;r<FM_HASH_BMP_SIZE; r++){
129                 if (qm->free_bitmap[r]){
130                         /* find first set bit */
131                         return r*FM_HASH_BMP_BITS+
132                                                 bit_scan_forward((unsigned long)qm->free_bitmap[r]);
133                 }
134         }
135         /* not found, nothing free */
136         return -1;
137 }
138 #endif /* F_MALLOC_HASH_BITMAP */
139
140
141
142 /* mark/test used/unused frags */
143 #define FRAG_MARK_USED(f)
144 #define FRAG_CLEAR_USED(f)
145 #define FRAG_WAS_USED(f)   (1)
146
147 /* other frag related defines:
148  * MEM_COALESCE_FRAGS
149  * MEM_FRAG_AVOIDANCE
150  */
151 #define MEM_FRAG_AVOIDANCE
152
153
154 /** computes hash number for big buckets */
155 #define big_hash_idx(s) ((unsigned long)bit_scan_reverse((unsigned long)(s)))
156
157
158 /**
159  * \name Memory manager boundary check pattern
160  */
161 /*@{ */
162 #define ST_CHECK_PATTERN   0xf0f0f0f0 /** inserted at the beginning */
163 #define END_CHECK_PATTERN1 0xc0c0c0c0 /** inserted at the end       */
164 #define END_CHECK_PATTERN2 0xabcdefed /** inserted at the end       */
165 /*@} */
166
167
168 /**
169  * \brief Extract memory fragment from free list
170  * \param qm memory block
171  * \param frag memory fragment
172  */
173 static inline void fm_extract_free(struct fm_block* qm, struct fm_frag* frag)
174 {
175         int hash;
176
177         hash = GET_HASH(frag->size);
178
179         if(frag->prev_free) {
180                 frag->prev_free->next_free = frag->next_free;
181         } else {
182                 qm->free_hash[hash].first = frag->next_free;
183         }
184         if(frag->next_free) {
185                 frag->next_free->prev_free = frag->prev_free;
186         }
187
188         frag->prev_free = NULL;
189         frag->next_free = NULL;
190         frag->is_free = 0;
191
192         qm->ffrags--;
193         qm->free_hash[hash].no--;
194 #ifdef F_MALLOC_HASH_BITMAP
195         if (qm->free_hash[hash].no==0)
196                 fm_bmp_reset(qm, hash);
197 #endif /* F_MALLOC_HASH_BITMAP */
198
199         qm->real_used+=frag->size;
200         qm->used+=frag->size;
201 }
202
203 /**
204  * \brief Insert a memory fragment in a memory block
205  * \param qm memory block
206  * \param frag memory fragment
207  */
208 static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag)
209 {
210         struct fm_frag* f;
211         struct fm_frag* p;
212         int hash;
213
214         hash=GET_HASH(frag->size);
215         f=qm->free_hash[hash].first;
216         p=NULL;
217         if (frag->size > F_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH,
218                                                                                         (different from 0.8.1[24] on
219                                                                                         purpose --andrei ) */
220                 /* large fragments list -- add at a position ordered by size */
221                 for(; f; f=f->next_free){
222                         if (frag->size <= f->size) break;
223                         p = f;
224                 }
225
226                 frag->next_free = f;
227                 frag->prev_free = p;
228                 if(f) {
229                         f->prev_free = frag;
230                 }
231                 if(p) {
232                         p->next_free = frag;
233                 } else {
234                         qm->free_hash[hash].first = frag;
235                 }
236         } else {
237                 /* fixed fragment size list -- add first */
238                 frag->prev_free = 0;
239                 frag->next_free = f;
240                 if(f) {
241                         f->prev_free = frag;
242                 }
243                 qm->free_hash[hash].first = frag;
244         }
245         frag->is_free = 1;
246         qm->ffrags++;
247         qm->free_hash[hash].no++;
248 #ifdef F_MALLOC_HASH_BITMAP
249         fm_bmp_set(qm, hash);
250 #endif /* F_MALLOC_HASH_BITMAP */
251         qm->used-=frag->size;
252         qm->real_used-=frag->size;
253 }
254
255
256 /**
257  *\brief Split a memory fragement
258  *
259  * Split a memory fragement, size should be already rounded-up
260  * \param qm memory block
261  * \param frag memory fragment
262  * \param size fragement size
263  */
264 static inline
265 #ifdef DBG_F_MALLOC
266 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
267                                         size_t size,
268                                         const char* file, const char* func, unsigned int line,
269                                         const char* mname)
270 #else
271 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
272                                         size_t size)
273 #endif
274 {
275         size_t rest;
276         struct fm_frag* n;
277
278         rest=frag->size-size;
279 #ifdef MEM_FRAG_AVOIDANCE
280         if ((rest> (FRAG_OVERHEAD+F_MALLOC_OPTIMIZE))||
281                 (rest>=(FRAG_OVERHEAD+size))){ /* the residue fragm. is big enough*/
282 #else
283         if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
284 #endif
285                 frag->size=size;
286                 /*split the fragment*/
287                 n=FRAG_NEXT(frag);
288                 n->size=rest-FRAG_OVERHEAD;
289                 FRAG_CLEAR_USED(n); /* never used */
290 #ifdef DBG_F_MALLOC
291                 /* frag created by malloc, mark it*/
292                 n->file=file;
293                 n->func="frag. from fm_split_frag";
294                 n->line=line;
295                 n->mname=mname;
296 #endif
297                 n->check=ST_CHECK_PATTERN;
298                 /* reinsert n in free list*/
299                 qm->used-=FRAG_OVERHEAD;
300                 fm_insert_free(qm, n);
301         }else{
302                 /* we cannot split this fragment any more => alloc all of it*/
303         }
304 }
305
306
307 /**
308  * \brief Initialize memory manager malloc
309  * \param address start address for memory block
310  * \param size Size of allocation
311  * \return return the fm_block
312  */
313 struct fm_block* fm_malloc_init(char* address, unsigned long size, int type)
314 {
315         char* start;
316         char* end;
317         struct fm_block* qm;
318         unsigned long init_overhead;
319
320         /* make address and size multiple of 8*/
321         start=(char*)ROUNDUP((unsigned long) address);
322         DBG("fm_malloc_init: F_OPTIMIZE=%lu, /ROUNDTO=%lu\n",
323                         F_MALLOC_OPTIMIZE, F_MALLOC_OPTIMIZE/ROUNDTO);
324         DBG("fm_malloc_init: F_HASH_SIZE=%lu, fm_block size=%lu\n",
325                         F_HASH_SIZE, (unsigned long)sizeof(struct fm_block));
326         DBG("fm_malloc_init(%p, %lu), start=%p\n", address, (unsigned long)size,
327                         start);
328
329         if (size<start-address) return 0;
330         size-=(start-address);
331         if (size <(MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0;
332         size=ROUNDDOWN(size);
333
334         init_overhead=INIT_OVERHEAD;
335
336         if (size < init_overhead)
337         {
338                 /* not enough mem to create our control structures !!!*/
339                 LM_ERR("fm_malloc_init(%lu) - no memory left for control structures!\n",
340                                 (unsigned long)size);
341                 return 0;
342         }
343         end=start+size;
344         qm=(struct fm_block*)start;
345         memset(qm, 0, sizeof(struct fm_block));
346         qm->size=size;
347         qm->used = size - init_overhead;
348         qm->real_used=size;
349         qm->max_real_used=init_overhead;
350         qm->type = type;
351         size-=init_overhead;
352
353         qm->first_frag=(struct fm_frag*)(start+ROUNDUP(sizeof(struct fm_block)));
354         qm->last_frag=(struct fm_frag*)(end-sizeof(struct fm_frag));
355         /* init first fragment*/
356         qm->first_frag->size=size;
357         qm->first_frag->prev_free=0;
358         qm->first_frag->next_free=0;
359         qm->first_frag->is_free=0;
360         /* init last fragment*/
361         qm->last_frag->size=0;
362         qm->last_frag->prev_free=0;
363         qm->last_frag->next_free=0;
364         qm->last_frag->is_free=0;
365
366         qm->first_frag->check=ST_CHECK_PATTERN;
367         qm->last_frag->check=END_CHECK_PATTERN1;
368
369         /* link initial fragment into the free list*/
370
371         fm_insert_free(qm, qm->first_frag);
372
373         return qm;
374 }
375
376 /**
377  * \brief Try merging free fragments to fit requested size
378  * \param qm memory block
379  * \param size memory allocation size
380  * \return address of allocated memory
381  */
382 struct fm_frag* fm_search_defrag(struct fm_block* qm, size_t size)
383 {
384         struct fm_frag* frag;
385         struct fm_frag* nxt;
386
387         frag = qm->first_frag;
388         while((char*)frag < (char*)qm->last_frag) {
389                 nxt = FRAG_NEXT(frag);
390
391                 if ( ((char*)nxt < (char*)qm->last_frag) && fm_is_free(frag)
392                                 && fm_is_free(nxt)) {
393                         /* join frag with all next consecutive free frags */
394                         fm_extract_free(qm, frag);
395                         do {
396                                 fm_extract_free(qm, nxt);
397                                 frag->size += nxt->size + FRAG_OVERHEAD;
398
399                                 /* after join - one frag less, add its overhead to used
400                                  * (real_used already has it - f and n were extracted */
401                                 qm->used += FRAG_OVERHEAD;
402
403                                 if( frag->size >size )
404                                         return frag;
405
406                                 nxt = FRAG_NEXT(frag);
407                         } while (((char*)nxt < (char*)qm->last_frag) && fm_is_free(nxt));
408
409                         fm_insert_free(qm, frag);
410                 }
411                 frag = nxt;
412         }
413
414         LM_ERR("fm_search_defrag(%p, %lu); Free fragment not found!\n", qm,
415                         (unsigned long)size);
416
417         return 0;
418 }
419
420 /**
421  * \brief Main memory manager allocation function
422  *
423  * Main memory manager allocation function, provide functionality necessary for pkg_malloc
424  * \param qm memory block
425  * \param size memory allocation size
426  * \return address of allocated memory
427  */
428 #ifdef DBG_F_MALLOC
429 void* fm_malloc(void* qmp, size_t size, const char* file,
430                 const char* func, unsigned int line, const char* mname)
431 #else
432 void* fm_malloc(void* qmp, size_t size)
433 #endif
434 {
435         struct fm_block* qm;
436         struct fm_frag* f;
437         struct fm_frag* frag;
438         int hash;
439
440         qm = (struct fm_block*)qmp;
441
442 #ifdef DBG_F_MALLOC
443         MDBG("fm_malloc(%p, %lu) called from %s: %s(%d)\n", qm,
444                         (unsigned long)size, file, func, line);
445 #endif
446         /*malloc(0) should return a valid pointer according to specs*/
447         if(unlikely(size==0)) size=4;
448         /*size must be a multiple of 8*/
449         size=ROUNDUP(size);
450
451         /*search for a suitable free frag*/
452
453 #ifdef F_MALLOC_HASH_BITMAP
454         hash=fm_bmp_first_set(qm, GET_HASH(size));
455         if (likely(hash>=0)){
456                 if (likely(hash<=F_MALLOC_OPTIMIZE/ROUNDTO)) { /* return first match */
457                         f=qm->free_hash[hash].first;
458                         if(likely(f)) goto found;
459 #ifdef DBG_F_MALLOC
460                         MDBG(" block %p hash %d empty but no. is %lu\n", qm,
461                                         hash, qm->free_hash[hash].no);
462 #endif
463                         /* reset slot and try next hash */
464                         qm->free_hash[hash].no=0;
465                         fm_bmp_reset(qm, hash);
466                         hash++;
467                 }
468                 /* if we are here we are searching next hash slot or a "big" fragment
469                  * between F_MALLOC_OPTIMIZE/ROUNDTO+1
470                  * and F_MALLOC_OPTIMIZE/ROUNDTO + (32|64) - F_MALLOC_OPTIMIZE_FACTOR
471                  * => 18 hash buckets on 32 bits and 50 buckets on 64 bits
472                  * The free hash bitmap is used to jump directly to non-empty
473                  * hash buckets.
474                  */
475                 do {
476                         for(f=qm->free_hash[hash].first; f; f=f->next_free)
477                                 if (f->size>=size) goto found;
478                         hash++; /* try in next hash cell */
479                 }while((hash < F_HASH_SIZE) &&
480                                 ((hash=fm_bmp_first_set(qm, hash)) >= 0));
481         }
482 #else /* F_MALLOC_HASH_BITMAP */
483         for(hash=GET_HASH(size);hash<F_HASH_SIZE;hash++){
484                 f=qm->free_hash[hash].first;
485                 for(; f; f=f->u.nxt_free)
486                         if (f->size>=size) goto found;
487                 /* try in a bigger bucket */
488         }
489 #endif /* F_MALLOC_HASH_BITMAP */
490         /* not found, search by defrag */
491
492         frag = fm_search_defrag(qm, size);
493
494         if(frag) goto finish;
495
496 #ifdef DBG_F_MALLOC
497         LM_ERR("fm_malloc(%p, %lu) called from %s: %s(%d),"
498                         " module: %s; Free fragment not found!\n",
499                                 qm, (unsigned long)size, file, func, line, mname);
500 #else
501         LM_ERR("fm_malloc(%p, %lu); Free fragment not found!\n",
502                                 qm, (unsigned long)size);
503 #endif
504
505         return 0;
506
507 found:
508         /* we found it!*/
509         /* detach it from the free list*/
510         frag=f;
511         fm_extract_free(qm, frag);
512
513         /*see if use full frag or split it in two*/
514 #ifdef DBG_F_MALLOC
515         fm_split_frag(qm, frag, size, file, func, line, mname);
516 #else
517         fm_split_frag(qm, frag, size);
518 #endif
519
520 finish:
521
522 #ifdef DBG_F_MALLOC
523         frag->file=file;
524         frag->func=func;
525         frag->mname=mname;
526         frag->line=line;
527         MDBG("fm_malloc(%p, %lu) returns address %p \n", qm, (unsigned long)size,
528                 (char*)frag+sizeof(struct fm_frag));
529 #endif
530         frag->check=ST_CHECK_PATTERN;
531
532         if (qm->max_real_used<qm->real_used)
533                 qm->max_real_used=qm->real_used;
534         FRAG_MARK_USED(frag); /* mark it as used */
535         if(qm->type==MEM_TYPE_PKG) {
536                 sr_event_exec(SREV_PKG_UPDATE_STATS, 0);
537         }
538         return (char*)frag+sizeof(struct fm_frag);
539 }
540
541
542 #ifdef MEM_JOIN_FREE
543 /**
544  * join fragment free frag f with next one (if it is free)
545  */
546 static void fm_join_frag(struct fm_block* qm, struct fm_frag* f)
547 {
548         struct fm_frag *n;
549
550         n=FRAG_NEXT(f);
551
552         /* check if n is valid and if in free list */
553         if (((char*)n >= (char*)qm->last_frag) || !fm_is_free(n))
554                 return;
555
556         /* detach n from the free list */
557         fm_extract_free(qm, n);
558
559         /* join - f extended with size of n plus its overhead */
560         f->size+=n->size+FRAG_OVERHEAD;
561
562         /* after join - one frag less, add its overhead to used
563          * (real_used already has it - f and n were extracted */
564         qm->used += FRAG_OVERHEAD;
565
566 }
567 #endif /*MEM_JOIN_FREE*/
568
569 /**
570  * \brief Main memory manager free function
571  *
572  * Main memory manager free function, provide functionality necessary for pkg_free
573  * \param qm memory block
574  * \param p freed memory
575  */
576 #ifdef DBG_F_MALLOC
577 void fm_free(void* qmp, void* p, const char* file, const char* func,
578                                 unsigned int line, const char* mname)
579 #else
580 void fm_free(void* qmp, void* p)
581 #endif
582 {
583         struct fm_block* qm;
584         struct fm_frag* f;
585
586         qm = (struct fm_block*)qmp;
587
588 #ifdef DBG_F_MALLOC
589         MDBG("fm_free(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line);
590 #endif
591         if (p==0) {
592                 MDBG("WARNING:fm_free: free(0) called\n");
593                 return;
594         }
595 #ifdef DBG_F_MALLOC
596         if (p>(void*)qm->last_frag || p<(void*)qm->first_frag){
597                 LM_CRIT("BUG: bad pointer %p (out of memory block (%p)!),"
598                                 " called from %s: %s(%d) - aborting\n", p, qm,
599                                 file, func, line);
600                 if(likely(cfg_get(core, core_cfg, mem_safety)==0))
601                         abort();
602                 else return;
603         }
604 #endif
605         f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
606 #ifdef DBG_F_MALLOC
607         MDBG("fm_free: freeing block alloc'ed from %s: %s(%ld)\n",
608                         f->file, f->func, f->line);
609 #endif
610         if(unlikely(fm_is_free(f))) {
611                 LM_INFO("freeing a free fragment (%p/%p) - ignore\n",
612                                 f, p);
613                 return;
614         }
615         if(qm->type==MEM_TYPE_PKG) {
616                 sr_event_exec(SREV_PKG_UPDATE_STATS, 0);
617         }
618 #ifdef DBG_F_MALLOC
619         f->file=file;
620         f->func=func;
621         f->line=line;
622         f->mname=mname;
623 #endif
624 #ifdef MEM_JOIN_FREE
625         if(unlikely(cfg_get(core, core_cfg, mem_join)!=0))
626                 fm_join_frag(qm, f);
627 #endif /*MEM_JOIN_FREE*/
628         fm_insert_free(qm, f);
629 }
630
631
632 /**
633  * \brief Main memory manager realloc function
634  *
635  * Main memory manager realloc function, provide functionality for pkg_realloc
636  * \param qm memory block
637  * \param p reallocated memory block
638  * \param size
639  * \return reallocated memory block
640  */
641 #ifdef DBG_F_MALLOC
642 void* fm_realloc(void* qmp, void* p, size_t size,
643                                         const char* file, const char* func, unsigned int line,
644                                         const char *mname)
645 #else
646 void* fm_realloc(void* qmp, void* p, size_t size)
647 #endif
648 {
649         struct fm_block* qm;
650         struct fm_frag *f;
651         size_t diff;
652         size_t orig_size;
653         struct fm_frag *n;
654         void *ptr;
655
656         qm = (struct fm_block*)qmp;
657
658 #ifdef DBG_F_MALLOC
659         MDBG("fm_realloc(%p, %p, %lu) called from %s: %s(%d)\n", qm, p,
660                         (unsigned long)size, file, func, line);
661         if ((p)&&(p>(void*)qm->last_frag || p<(void*)qm->first_frag)){
662                 LM_CRIT("BUG: bad pointer %p (out of memory block (%p)!) - "
663                                 "aborting\n", p, qm);
664                 abort();
665         }
666 #endif
667         if (size==0) {
668                 if (p)
669 #ifdef DBG_F_MALLOC
670                         fm_free(qm, p, file, func, line, mname);
671 #else
672                         fm_free(qm, p);
673 #endif
674                 return 0;
675         }
676         if (p==0)
677 #ifdef DBG_F_MALLOC
678                 return fm_malloc(qm, size, file, func, line, mname);
679 #else
680                 return fm_malloc(qm, size);
681 #endif
682         f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
683 #ifdef DBG_F_MALLOC
684         MDBG("fm_realloc: realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
685                         f, f->file, f->func, f->line);
686 #endif
687         size=ROUNDUP(size);
688         orig_size=f->size;
689         if (f->size > size){
690                 /* shrink */
691 #ifdef DBG_F_MALLOC
692                 MDBG("fm_realloc: shrinking from %lu to %lu\n", f->size,
693                                 (unsigned long)size);
694                 fm_split_frag(qm, f, size, file, "frag. from fm_realloc", line, mname);
695 #else
696                 fm_split_frag(qm, f, size);
697 #endif
698         }else if (f->size<size){
699                 /* grow */
700 #ifdef DBG_F_MALLOC
701                 MDBG("fm_realloc: growing from %lu to %lu\n", f->size,
702                                 (unsigned long)size);
703 #endif
704                 diff=size-f->size;
705                 n=FRAG_NEXT(f);
706                 /*if next frag is free, check if a join has enough size*/
707                 if (((char*)n < (char*)qm->last_frag) &&
708                                 fm_is_free(n) && ((n->size+FRAG_OVERHEAD)>=diff)){
709                         /* detach n from the free list */
710                         fm_extract_free(qm, n);
711                         /* join */
712                         f->size+=n->size+FRAG_OVERHEAD;
713                         qm->used+=FRAG_OVERHEAD;
714
715                         /* split it if necessary */
716                         if (f->size > size){
717                 #ifdef DBG_F_MALLOC
718                                 fm_split_frag(qm, f, size, file, "fragm. from fm_realloc",
719                                                 line, mname);
720                 #else
721                                 fm_split_frag(qm, f, size);
722                 #endif
723                         }
724                 }else{
725                         /* could not join => realloc */
726         #ifdef DBG_F_MALLOC
727                         ptr=fm_malloc(qm, size, file, func, line, mname);
728         #else
729                         ptr=fm_malloc(qm, size);
730         #endif
731                         if (ptr){
732                                 /* copy, need by libssl */
733                                 memcpy(ptr, p, orig_size);
734                         } else {
735 #ifdef DBG_F_MALLOC
736                                 LM_ERR("fm_realloc(%p, %lu) called from %s: %s(%d),"
737                                                 " module: %s; fm_malloc() failed!\n",
738                                                 qm, (unsigned long)size, file, func, line, mname);
739 #else
740                                 LM_ERR("fm_realloc(%p, %lu); fm_malloc() failed!\n",
741                                                 qm, (unsigned long)size);
742 #endif
743                         }
744         #ifdef DBG_F_MALLOC
745                         fm_free(qm, p, file, func, line, mname);
746         #else
747                         fm_free(qm, p);
748         #endif
749                         p=ptr;
750                 }
751         }else{
752                 /* do nothing */
753 #ifdef DBG_F_MALLOC
754                 MDBG("fm_realloc: doing nothing, same size: %lu - %lu\n",
755                                 f->size, (unsigned long)size);
756 #endif
757         }
758 #ifdef DBG_F_MALLOC
759         MDBG("fm_realloc: returning %p\n", p);
760 #endif
761         if(qm->type==MEM_TYPE_PKG) {
762                 sr_event_exec(SREV_PKG_UPDATE_STATS, 0);
763         }
764         return p;
765 }
766
767
768 /**
769  * \brief Report internal memory manager status
770  * \param qm memory block
771  */
772 void fm_status(void* qmp)
773 {
774         struct fm_block* qm;
775         struct fm_frag* f;
776         int i,j;
777         int h;
778         int unused;
779         unsigned long size;
780         int memlog;
781         int mem_summary;
782
783         qm = (struct fm_block*)qmp;
784
785         memlog=cfg_get(core, core_cfg, memlog);
786         mem_summary=cfg_get(core, core_cfg, mem_summary);
787         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", "fm_status (%p):\n", qm);
788         if (!qm) return;
789
790         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", " heap size= %ld\n",
791                         qm->size);
792 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
793         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
794                         " used= %lu, used+overhead=%lu, free=%lu\n",
795                         qm->used, qm->real_used, qm->size-qm->real_used);
796         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
797                         " max used (+overhead)= %lu\n", qm->max_real_used);
798 #endif
799
800         if (mem_summary & 16) return;
801
802         /*
803         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", "dumping all fragments:\n");
804         for (f=qm->first_frag, i=0;((char*)f<(char*)qm->last_frag) && (i<10);
805                         f=FRAG_NEXT(f), i++){
806                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
807                                 "    %3d. %c  address=%x  size=%d\n", i,
808                                 (f->u.reserved)?'a':'N',
809                                 (char*)f+sizeof(struct fm_frag), f->size);
810 #ifdef DBG_F_MALLOC
811                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
812                                 "            %s from %s: %s(%d)\n",
813                                 (f->u.is_free)?"freed":"alloc'd", f->file, f->func, f->line);
814 #endif
815         }
816 */
817         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", "dumping free list:\n");
818         for(h=0,i=0,size=0;h<F_HASH_SIZE;h++){
819                 unused=0;
820                 for (f=qm->free_hash[h].first,j=0; f;
821                                 size+=f->size,f=f->next_free,i++,j++){
822                         if (!FRAG_WAS_USED(f)){
823                                 unused++;
824 #ifdef DBG_F_MALLOC
825                                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
826                                                         "unused fragm.: hash = %3d, fragment %p,"
827                                                         " address %p size %lu, created from %s: %s(%ld)\n",
828                                                         h, f, (char*)f+sizeof(struct fm_frag), f->size,
829                                                         f->file, f->func, f->line);
830 #endif
831                         };
832                 }
833                 if (j) LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
834                                                         "hash = %3d fragments no.: %5d, unused: %5d\n\t\t"
835                                                         " bucket size: %9lu - %9lu (first %9lu)\n",
836                                                         h, j, unused, UN_HASH(h),
837                                                 ((h<=F_MALLOC_OPTIMIZE/ROUNDTO)?1:2)* UN_HASH(h),
838                                                         qm->free_hash[h].first->size
839                                 );
840                 if (j!=qm->free_hash[h].no){
841                         LM_CRIT("BUG: fm_status - different free frag. count: %d!=%ld"
842                                         " for hash %3d\n", j, qm->free_hash[h].no, h);
843                 }
844                 /*
845                 {
846                         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
847                                         "   %5d.[%3d:%3d] %c  address=%x  size=%d(%x)\n",
848                                         i, h, j,
849                                         (f->u.reserved)?'a':'N',
850                                         (char*)f+sizeof(struct fm_frag), f->size, f->size);
851 #ifdef DBG_F_MALLOC
852                         DBG("            %s from %s: %s(%d)\n",
853                                 (f->u.reserved)?"freed":"alloc'd", f->file, f->func, f->line);
854 #endif
855                 }
856         */
857         }
858         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
859                         "TOTAL: %6d free fragments = %6lu free bytes\n", i, size);
860         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
861                         "-----------------------------\n");
862 }
863
864
865 /**
866  * \brief Fills a malloc info structure with info about the block
867  *
868  * Fills a malloc info structure with info about the block, if a
869  * parameter is not supported, it will be filled with 0
870  * \param qm memory block
871  * \param info memory information
872  */
873 void fm_info(void* qmp, struct mem_info* info)
874 {
875         struct fm_block* qm;
876
877         qm = (struct fm_block*)qmp;
878         memset(info,0, sizeof(*info));
879         info->total_size=qm->size;
880         info->min_frag=MIN_FRAG_SIZE;
881         info->free=qm->size-qm->real_used;
882         info->used=qm->used;
883         info->real_used=qm->real_used;
884         info->max_used=qm->max_real_used;
885         info->total_frags=qm->ffrags;
886 }
887
888
889 /**
890  * \brief Helper function for available memory report
891  * \param qm memory block
892  * \return Returns how much free memory is available, on error (not compiled
893  * with bookkeeping code) returns (unsigned long)(-1)
894  */
895 unsigned long fm_available(void* qmp)
896 {
897         struct fm_block* qm;
898
899         qm = (struct fm_block*)qmp;
900         return qm->size-qm->real_used;
901 }
902
903
904 #ifdef DBG_F_MALLOC
905
906 static mem_counter* get_mem_counter(mem_counter **root,struct fm_frag* f)
907 {
908         mem_counter *x;
909
910         if (!*root) goto make_new;
911         for(x=*root;x;x=x->next)
912                 if (x->file == f->file && x->func == f->func && x->line == f->line)
913                         return x;
914 make_new:
915         x = malloc(sizeof(mem_counter));
916         x->file = f->file;
917         x->func = f->func;
918         x->line = f->line;
919         x->mname = f->mname;
920         x->count = 0;
921         x->size = 0;
922         x->next = *root;
923         *root = x;
924         return x;
925 }
926
927
928 /**
929  * \brief Debugging helper, summary and logs all allocated memory blocks
930  * \param qm memory block
931  */
932 void fm_sums(void* qmp)
933 {
934         struct fm_block* qm;
935
936         qm = (struct fm_block*)qmp;
937         struct fm_frag* f;
938         int i;
939         int memlog;
940         mem_counter *root,*x;
941
942         root=0;
943         if (!qm) return;
944
945         memlog=cfg_get(core, core_cfg, memlog);
946         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
947                         "summarizing all alloc'ed. fragments:\n");
948
949         for (f=qm->first_frag, i=0; (char*)f<(char*)qm->last_frag;
950                         f=FRAG_NEXT(f), i++){
951                 if (!fm_is_free(f)){
952                         x = get_mem_counter(&root,f);
953                         x->count++;
954                         x->size+=f->size;
955                 }
956         }
957         x = root;
958         while(x){
959                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
960                                 " count=%6d size=%10lu bytes from %s: %s(%ld)\n",
961                         x->count,x->size,
962                         x->file, x->func, x->line
963                         );
964                 root = x->next;
965                 free(x);
966                 x = root;
967         }
968         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
969                         "-----------------------------\n");
970
971 }
972
973
974 void fm_mod_get_stats(void *qmp, void **fm_rootp)
975 {
976         if (!fm_rootp) {
977                 return;
978         }
979
980         LM_DBG("get fm memory statistics\n");
981
982         struct fm_block *qm = (struct fm_block *) qmp;
983         mem_counter **fm_root = (mem_counter **) fm_rootp;
984         struct fm_frag* f;
985         int i;
986         mem_counter *x;
987
988         if (!qm) return;
989
990         /* update fragment detail list */
991         for (f=qm->first_frag, i=0; (char*)f<(char*)qm->last_frag;
992                         f=FRAG_NEXT(f), i++){
993                 if (f->is_free==0){
994                         x = get_mem_counter(fm_root,f);
995                         x->count++;
996                         x->size+=f->size;
997                 }
998         }
999
1000         return;
1001 }
1002
1003 void fm_mod_free_stats(void *fm_rootp)
1004 {
1005         if (!fm_rootp) {
1006                 return ;
1007         }
1008
1009         LM_DBG("free fm memory statistics\n");
1010
1011         mem_counter *root = (mem_counter *) fm_rootp;
1012         mem_counter *new, *old;
1013         new = root;
1014         old = root;
1015
1016         while (new) {
1017                 old = new;
1018                 new = new->next;
1019                 free(old);
1020         }
1021 }
1022 #else
1023 void fm_sums(void *qmp)
1024 {
1025         struct fm_block* qm;
1026         int memlog;
1027
1028         qm = (struct fm_block*)qmp;
1029         memlog=cfg_get(core, core_cfg, memlog);
1030         LOG_(DEFAULT_FACILITY, memlog, "fm_sums: ", "not available (%p)\n", qm);
1031         return;
1032 }
1033
1034 void fm_mod_get_stats(void *qmp, void **fm_rootp)
1035 {
1036         LM_WARN("Enable DBG_F_MALLOC for getting statistics\n");
1037         return ;
1038 }
1039
1040 void fm_mod_free_stats(void *fm_rootp)
1041 {
1042         LM_WARN("Enable DBG_F_MALLOC for freeing statistics\n");
1043         return ;
1044 }
1045 #endif /* DBG_F_MALLOC */
1046
1047
1048 /*memory manager core api*/
1049 static char *_fm_mem_name = "f_malloc";
1050
1051 /* PKG - private memory API*/
1052 static char *_fm_pkg_pool = 0;
1053 static struct fm_block *_fm_pkg_block = 0;
1054
1055 /**
1056  * \brief Destroy memory pool
1057  */
1058 void fm_malloc_destroy_pkg_manager(void)
1059 {
1060         if (_fm_pkg_pool) {
1061                 free(_fm_pkg_pool);
1062                 _fm_pkg_pool = 0;
1063         }
1064         _fm_pkg_block = 0;
1065 }
1066
1067 /**
1068  * \brief Init memory pool
1069  */
1070 int fm_malloc_init_pkg_manager(void)
1071 {
1072         sr_pkg_api_t ma;
1073         _fm_pkg_pool = malloc(pkg_mem_size);
1074         if (_fm_pkg_pool)
1075                 _fm_pkg_block=fm_malloc_init(_fm_pkg_pool, pkg_mem_size, MEM_TYPE_PKG);
1076         if (_fm_pkg_block==0){
1077                 LM_CRIT("could not initialize fm pkg memory pool\n");
1078                 fprintf(stderr, "Too much fm pkg memory demanded: %ld bytes\n",
1079                                                 pkg_mem_size);
1080                 return -1;
1081         }
1082
1083         memset(&ma, 0, sizeof(sr_pkg_api_t));
1084         ma.mname      = _fm_mem_name;
1085         ma.mem_pool   = _fm_pkg_pool;
1086         ma.mem_block  = _fm_pkg_block;
1087         ma.xmalloc    = fm_malloc;
1088         ma.xfree      = fm_free;
1089         ma.xrealloc   = fm_realloc;
1090         ma.xstatus    = fm_status;
1091         ma.xinfo      = fm_info;
1092         ma.xavailable = fm_available;
1093         ma.xsums      = fm_sums;
1094         ma.xdestroy   = fm_malloc_destroy_pkg_manager;
1095         ma.xmodstats  = fm_mod_get_stats;
1096         ma.xfmodstats = fm_mod_free_stats;
1097
1098         return pkg_init_api(&ma);
1099 }
1100
1101
1102 /* SHM - shared memory API*/
1103 static void *_fm_shm_pool = 0;
1104 static struct fm_block *_fm_shm_block = 0;
1105
1106 /*SHM wrappers to sync the access to memory block*/
1107 #ifdef DBG_F_MALLOC
1108 void* fm_shm_malloc(void* qmp, size_t size,
1109                                         const char* file, const char* func, unsigned int line, const char* mname)
1110 {
1111         void *r;
1112         shm_lock();
1113         r = fm_malloc(qmp, size, file, func, line, mname);
1114         shm_unlock();
1115         return r;
1116 }
1117 void* fm_shm_realloc(void* qmp, void* p, size_t size,
1118                                         const char* file, const char* func, unsigned int line, const char* mname)
1119 {
1120         void *r;
1121         shm_lock();
1122         r = fm_realloc(qmp, p, size, file, func, line, mname);
1123         shm_unlock();
1124         return r;
1125 }
1126 void* fm_shm_resize(void* qmp, void* p, size_t size,
1127                                         const char* file, const char* func, unsigned int line, const char* mname)
1128 {
1129         void *r;
1130         shm_lock();
1131         if(p) fm_free(qmp, p, file, func, line, mname);
1132         r = fm_malloc(qmp, size, file, func, line, mname);
1133         shm_unlock();
1134         return r;
1135 }
1136 void fm_shm_free(void* qmp, void* p, const char* file, const char* func,
1137                                 unsigned int line, const char* mname)
1138 {
1139         shm_lock();
1140         fm_free(qmp, p, file, func, line, mname);
1141         shm_unlock();
1142 }
1143 #else
1144 void* fm_shm_malloc(void* qmp, size_t size)
1145 {
1146         void *r;
1147         shm_lock();
1148         r = fm_malloc(qmp, size);
1149         shm_unlock();
1150         return r;
1151 }
1152 void* fm_shm_realloc(void* qmp, void* p, size_t size)
1153 {
1154         void *r;
1155         shm_lock();
1156         r = fm_realloc(qmp, p, size);
1157         shm_unlock();
1158         return r;
1159 }
1160 void* fm_shm_resize(void* qmp, void* p, size_t size)
1161 {
1162         void *r;
1163         shm_lock();
1164         if(p) fm_free(qmp, p);
1165         r = fm_malloc(qmp, size);
1166         shm_unlock();
1167         return r;
1168 }
1169 void fm_shm_free(void* qmp, void* p)
1170 {
1171         shm_lock();
1172         fm_free(qmp, p);
1173         shm_unlock();
1174 }
1175 #endif
1176 void fm_shm_status(void* qmp)
1177 {
1178         shm_lock();
1179         fm_status(qmp);
1180         shm_unlock();
1181 }
1182 void fm_shm_info(void* qmp, struct mem_info* info)
1183 {
1184         shm_lock();
1185         fm_info(qmp, info);
1186         shm_unlock();
1187
1188 }
1189 unsigned long fm_shm_available(void* qmp)
1190 {
1191         unsigned long r;
1192         shm_lock();
1193         r = fm_available(qmp);
1194         shm_unlock();
1195         return r;
1196 }
1197 void fm_shm_sums(void* qmp)
1198 {
1199         shm_lock();
1200         fm_sums(qmp);
1201         shm_unlock();
1202 }
1203
1204
1205 /**
1206  * \brief Destroy memory pool
1207  */
1208 void fm_malloc_destroy_shm_manager(void)
1209 {
1210         /*shm pool from core - nothing to do*/
1211         _fm_shm_pool = 0;
1212         _fm_shm_block = 0;
1213 }
1214
1215 /**
1216  * \brief Init memory pool
1217  */
1218 int fm_malloc_init_shm_manager(void)
1219 {
1220         sr_shm_api_t ma;
1221         _fm_shm_pool = shm_core_get_pool();
1222         if (_fm_shm_pool)
1223                 _fm_shm_block=fm_malloc_init(_fm_shm_pool, shm_mem_size, MEM_TYPE_SHM);
1224         if (_fm_shm_block==0){
1225                 LM_CRIT("could not initialize fm shm memory pool\n");
1226                 fprintf(stderr, "Too much fm shm memory demanded: %ld bytes\n",
1227                                                 shm_mem_size);
1228                 return -1;
1229         }
1230
1231         memset(&ma, 0, sizeof(sr_shm_api_t));
1232         ma.mname          = _fm_mem_name;
1233         ma.mem_pool       = _fm_shm_pool;
1234         ma.mem_block      = _fm_shm_block;
1235         ma.xmalloc        = fm_shm_malloc;
1236         ma.xmalloc_unsafe = fm_malloc;
1237         ma.xfree          = fm_shm_free;
1238         ma.xfree_unsafe   = fm_free;
1239         ma.xrealloc       = fm_shm_realloc;
1240         ma.xresize        = fm_shm_resize;
1241         ma.xstatus        = fm_shm_status;
1242         ma.xinfo          = fm_shm_info;
1243         ma.xavailable     = fm_shm_available;
1244         ma.xsums          = fm_shm_sums;
1245         ma.xdestroy       = fm_malloc_destroy_shm_manager;
1246         ma.xmodstats      = fm_mod_get_stats;
1247         ma.xfmodstats     = fm_mod_free_stats;
1248
1249         if(shm_init_api(&ma)<0) {
1250                 LM_ERR("cannot initialize the core shm api\n");
1251                 return -1;
1252         }
1253         if(shm_core_lock_init()<0) {
1254                 LM_ERR("cannot initialize the core shm lock\n");
1255                 return -1;
1256         }
1257         return 0;
1258 }
1259
1260 #endif