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