2c05fe6bb3474e26175b0c7b142f974f21ba1c20
[sip-router] / mem / f_malloc.c
1 /* $Id$
2  *
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of sip-router, a free SIP server.
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 /*
21  * History:
22  * --------
23  *              created by andrei
24  *  2003-07-06  added fm_realloc (andrei)
25  *  2004-07-19  fragments book keeping code and support for 64 bits
26  *               memory blocks (64 bits machine & size >=2^32) 
27  *              GET_HASH s/</<=/ (avoids waste of 1 hash cell)   (andrei)
28  *  2004-11-10  support for > 4Gb mem., switched to long (andrei)
29  *  2005-03-02  added fm_info() (andrei)
30  *  2005-12-12  fixed realloc shrink real_used accounting (andrei)
31  *              fixed initial size (andrei)
32  *  2006-02-03  fixed realloc out of mem. free bug (andrei)
33  *  2006-04-07  s/DBG/MDBG (andrei)
34  *  2007-02-23  added fm_available() (andrei)
35  *  2007-06-23  added hash bitmap (andrei)
36  *  2009-09-28  added fm_sums() (patch from Dragos Vingarzan)
37  */
38
39
40 #if !defined(q_malloc)  && (defined F_MALLOC)
41
42 #include <string.h>
43 #include <stdlib.h>
44
45 #include "f_malloc.h"
46 #include "../dprint.h"
47 #include "../globals.h"
48 #include "../compiler_opt.h"
49 #include "memdbg.h"
50 #include "../bit_scan.h"
51 #include "../cfg/cfg.h" /* memlog */
52
53
54 /*useful macros*/
55
56 #define FRAG_NEXT(f) \
57         ((struct fm_frag*)((char*)(f)+sizeof(struct fm_frag)+(f)->size ))
58
59 #define FRAG_OVERHEAD   (sizeof(struct fm_frag))
60 #define INIT_OVERHEAD   \
61         (ROUNDUP(sizeof(struct fm_block))+sizeof(struct fm_frag))
62
63
64
65 /* ROUNDTO= 2^k so the following works */
66 #define ROUNDTO_MASK    (~((unsigned long)ROUNDTO-1))
67 #define ROUNDUP(s)              (((s)+(ROUNDTO-1))&ROUNDTO_MASK)
68 #define ROUNDDOWN(s)    ((s)&ROUNDTO_MASK)
69
70 /*
71  #define ROUNDUP(s)             (((s)%ROUNDTO)?((s)+ROUNDTO)/ROUNDTO*ROUNDTO:(s))
72  #define ROUNDDOWN(s)   (((s)%ROUNDTO)?((s)-ROUNDTO)/ROUNDTO*ROUNDTO:(s))
73 */
74
75
76
77         /* finds the hash value for s, s=ROUNDTO multiple*/
78 #define GET_HASH(s)   ( ((unsigned long)(s)<=F_MALLOC_OPTIMIZE)?\
79                                                         (unsigned long)(s)/ROUNDTO: \
80                                                         F_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
81                                                                 F_MALLOC_OPTIMIZE_FACTOR+1 )
82
83 #define UN_HASH(h)      ( ((unsigned long)(h)<=(F_MALLOC_OPTIMIZE/ROUNDTO))?\
84                                                 (unsigned long)(h)*ROUNDTO: \
85                                                 1UL<<((unsigned long)(h)-F_MALLOC_OPTIMIZE/ROUNDTO+\
86                                                         F_MALLOC_OPTIMIZE_FACTOR-1)\
87                                         )
88
89 #ifdef F_MALLOC_HASH_BITMAP
90
91 #define fm_bmp_set(qm, b) \
92         do{ \
93                 (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] |= \
94                                                                                         1UL<<((b)%FM_HASH_BMP_BITS); \
95         }while(0)
96
97 #define fm_bmp_reset(qm, b) \
98         do{ \
99                 (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] &= \
100                                                                                         ~(1UL<<((b)%FM_HASH_BMP_BITS)); \
101         }while(0)
102
103 /* returns 0 if not set, !=0 if set */
104 #define fm_bmp_is_set(qm, b) \
105         ((qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] & (1UL<<((b)%FM_HASH_BMP_BITS)))
106
107 inline static int fm_bmp_first_set(struct fm_block* qm, int start)
108 {
109         int bmp_idx;
110         int bit;
111         int r;
112         fm_hash_bitmap_t test_val;
113         fm_hash_bitmap_t v;
114         
115         bmp_idx=start/FM_HASH_BMP_BITS;
116         bit=start%FM_HASH_BMP_BITS;
117         test_val=1UL <<((unsigned long)bit);
118         if (qm->free_bitmap[bmp_idx] & test_val)
119                 return start;
120         else if (qm->free_bitmap[bmp_idx] & ~(test_val-1)){
121 #if 0
122                 test_val<<=1;
123                 for (r=bit+1; r<FM_HASH_BMP_BITS; r++, test_val<<=1){
124                         if (qm->free_bitmap[bmp_idx] & test_val)
125                                 return (start-bit+r);
126                 }
127 #endif
128                 v=qm->free_bitmap[bmp_idx]>>(bit+1);
129                 return start+1+bit_scan_forward((unsigned long)v);
130         }
131         for (r=bmp_idx+1;r<FM_HASH_BMP_SIZE; r++){
132                 if (qm->free_bitmap[r]){
133                         /* find first set bit */
134                         return r*FM_HASH_BMP_BITS+
135                                                 bit_scan_forward((unsigned long)qm->free_bitmap[r]);
136                 }
137         }
138         /* not found, nothing free */
139         return -1;
140 }
141 #endif /* F_MALLOC_HASH_BITMAP */
142
143
144
145 /* mark/test used/unused frags */
146 #define FRAG_MARK_USED(f)
147 #define FRAG_CLEAR_USED(f)
148 #define FRAG_WAS_USED(f)   (1)
149
150 /* other frag related defines:
151  * MEM_COALESCE_FRAGS 
152  * MEM_FRAG_AVOIDANCE
153  */
154 #define MEM_FRAG_AVOIDANCE
155
156
157 /* computes hash number for big buckets*/
158 #if 0
159 inline static unsigned long big_hash_idx(unsigned long s)
160 {
161         unsigned long idx;
162         /* s is rounded => s = k*2^n (ROUNDTO=2^n) 
163          * index= i such that 2^(i+1) > s >= 2^i
164          *
165          * => index = number of the first non null bit in s*/
166         idx=sizeof(long)*8-1;
167         for (; !(s&(1UL<<(sizeof(long)*8-1))) ; s<<=1, idx--);
168         return idx;
169 }
170 #else
171 #define big_hash_idx(s) ((unsigned long)bit_scan_reverse((unsigned long)(s)))
172 #endif
173
174
175 #ifdef DBG_F_MALLOC
176 #define ST_CHECK_PATTERN   0xf0f0f0f0
177 #define END_CHECK_PATTERN1 0xc0c0c0c0
178 #define END_CHECK_PATTERN2 0xabcdefed
179 #endif
180
181
182
183 static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag)
184 {
185         struct fm_frag** f;
186         int hash;
187         
188         hash=GET_HASH(frag->size);
189         f=&(qm->free_hash[hash].first);
190         if (frag->size > F_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH,
191                                                                                         (different from 0.8.1[24] on
192                                                                                          purpose --andrei ) */
193                 for(; *f; f=&((*f)->u.nxt_free)){
194                         if (frag->size <= (*f)->size) break;
195                 }
196         }
197         
198         /*insert it here*/
199         frag->u.nxt_free=*f;
200         *f=frag;
201         qm->free_hash[hash].no++;
202 #ifdef F_MALLOC_HASH_BITMAP
203         fm_bmp_set(qm, hash);
204 #endif /* F_MALLOC_HASH_BITMAP */
205 }
206
207
208
209  /* size should be already rounded-up */
210 static inline
211 #ifdef DBG_F_MALLOC 
212 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
213                                         unsigned long size,
214                                         const char* file, const char* func, unsigned int line)
215 #else
216 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
217                                         unsigned long size)
218 #endif
219 {
220         unsigned long rest;
221         struct fm_frag* n;
222         
223         rest=frag->size-size;
224 #ifdef MEM_FRAG_AVOIDANCE
225         if ((rest> (FRAG_OVERHEAD+F_MALLOC_OPTIMIZE))||
226                 (rest>=(FRAG_OVERHEAD+size))){ /* the residue fragm. is big enough*/
227 #else
228         if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
229 #endif
230                 frag->size=size;
231                 /*split the fragment*/
232                 n=FRAG_NEXT(frag);
233                 n->size=rest-FRAG_OVERHEAD;
234                 FRAG_CLEAR_USED(n); /* never used */
235 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
236                 qm->real_used+=FRAG_OVERHEAD;
237 #endif
238 #ifdef DBG_F_MALLOC
239                 /* frag created by malloc, mark it*/
240                 n->file=file;
241                 n->func="frag. from fm_malloc";
242                 n->line=line;
243                 n->check=ST_CHECK_PATTERN;
244 #endif
245                 /* reinsert n in free list*/
246                 fm_insert_free(qm, n);
247         }else{
248                 /* we cannot split this fragment any more => alloc all of it*/
249         }
250 }
251
252
253
254 /* init malloc and return a fm_block*/
255 struct fm_block* fm_malloc_init(char* address, unsigned long size)
256 {
257         char* start;
258         char* end;
259         struct fm_block* qm;
260         unsigned long init_overhead;
261         
262         /* make address and size multiple of 8*/
263         start=(char*)ROUNDUP((unsigned long) address);
264         DBG("fm_malloc_init: F_OPTIMIZE=%lu, /ROUNDTO=%lu\n",
265                         F_MALLOC_OPTIMIZE, F_MALLOC_OPTIMIZE/ROUNDTO);
266         DBG("fm_malloc_init: F_HASH_SIZE=%lu, fm_block size=%lu\n",
267                         F_HASH_SIZE, (long)sizeof(struct fm_block));
268         DBG("fm_malloc_init(%p, %lu), start=%p\n", address, size, start);
269
270         if (size<start-address) return 0;
271         size-=(start-address);
272         if (size <(MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0;
273         size=ROUNDDOWN(size);
274
275         init_overhead=INIT_OVERHEAD;
276         
277         
278         if (size < init_overhead)
279         {
280                 /* not enough mem to create our control structures !!!*/
281                 return 0;
282         }
283         end=start+size;
284         qm=(struct fm_block*)start;
285         memset(qm, 0, sizeof(struct fm_block));
286         qm->size=size;
287 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
288         qm->real_used=init_overhead;
289         qm->max_real_used=qm->real_used;
290 #endif
291         size-=init_overhead;
292         
293         qm->first_frag=(struct fm_frag*)(start+ROUNDUP(sizeof(struct fm_block)));
294         qm->last_frag=(struct fm_frag*)(end-sizeof(struct fm_frag));
295         /* init initial fragment*/
296         qm->first_frag->size=size;
297         qm->last_frag->size=0;
298         
299 #ifdef DBG_F_MALLOC
300         qm->first_frag->check=ST_CHECK_PATTERN;
301         qm->last_frag->check=END_CHECK_PATTERN1;
302 #endif
303         
304         /* link initial fragment into the free list*/
305         
306         fm_insert_free(qm, qm->first_frag);
307         
308         
309         return qm;
310 }
311
312
313
314 #ifdef DBG_F_MALLOC
315 void* fm_malloc(struct fm_block* qm, unsigned long size,
316                                         const char* file, const char* func, unsigned int line)
317 #else
318 void* fm_malloc(struct fm_block* qm, unsigned long size)
319 #endif
320 {
321         struct fm_frag** f;
322         struct fm_frag* frag;
323         int hash;
324         
325 #ifdef DBG_F_MALLOC
326         MDBG("fm_malloc(%p, %lu) called from %s: %s(%d)\n", qm, size, file, func,
327                         line);
328 #endif
329         /*size must be a multiple of 8*/
330         size=ROUNDUP(size);
331 /*      if (size>(qm->size-qm->real_used)) return 0; */
332
333         
334         /*search for a suitable free frag*/
335
336 #ifdef F_MALLOC_HASH_BITMAP
337         hash=fm_bmp_first_set(qm, GET_HASH(size));
338         if (likely(hash>=0)){
339                 f=&(qm->free_hash[hash].first);
340         if (likely(hash<=F_MALLOC_OPTIMIZE/ROUNDTO)) /* return first match */
341                         goto found; 
342                 for(;(*f); f=&((*f)->u.nxt_free))
343                         if ((*f)->size>=size) goto found;
344         }
345 #else /* F_MALLOC_HASH_BITMAP */
346         for(hash=GET_HASH(size);hash<F_HASH_SIZE;hash++){
347                 f=&(qm->free_hash[hash].first);
348 #if 0
349                 if (likely(hash<=F_MALLOC_OPTIMIZE/ROUNDTO)) /* return first match */
350                                 goto found; 
351 #endif
352                 for(;(*f); f=&((*f)->u.nxt_free))
353                         if ((*f)->size>=size) goto found;
354                 /* try in a bigger bucket */
355         }
356 #endif /* F_MALLOC_HASH_BITMAP */
357         /* not found, bad! */
358         return 0;
359
360 found:
361         /* we found it!*/
362         /* detach it from the free list*/
363         frag=*f;
364         *f=frag->u.nxt_free;
365         frag->u.nxt_free=0; /* mark it as 'taken' */
366         qm->free_hash[hash].no--;
367 #ifdef F_MALLOC_HASH_BITMAP
368         if (qm->free_hash[hash].no==0)
369                 fm_bmp_reset(qm, hash);
370 #endif /* F_MALLOC_HASH_BITMAP */
371         
372         /*see if we'll use full frag, or we'll split it in 2*/
373         
374 #ifdef DBG_F_MALLOC
375         fm_split_frag(qm, frag, size, file, func, line);
376
377         frag->file=file;
378         frag->func=func;
379         frag->line=line;
380         frag->check=ST_CHECK_PATTERN;
381         MDBG("fm_malloc(%p, %lu) returns address %p \n", qm, size,
382                 (char*)frag+sizeof(struct fm_frag));
383 #else
384         fm_split_frag(qm, frag, size);
385 #endif
386 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
387         qm->real_used+=frag->size;
388         qm->used+=frag->size;
389         if (qm->max_real_used<qm->real_used)
390                 qm->max_real_used=qm->real_used;
391 #endif
392         FRAG_MARK_USED(frag); /* mark it as used */
393         return (char*)frag+sizeof(struct fm_frag);
394 }
395
396
397
398 #ifdef DBG_F_MALLOC
399 void fm_free(struct fm_block* qm, void* p, const char* file, const char* func, 
400                                 unsigned int line)
401 #else
402 void fm_free(struct fm_block* qm, void* p)
403 #endif
404 {
405         struct fm_frag* f;
406         unsigned long size;
407
408 #ifdef DBG_F_MALLOC
409         MDBG("fm_free(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line);
410         if (p>(void*)qm->last_frag || p<(void*)qm->first_frag){
411                 LOG(L_CRIT, "BUG: fm_free: bad pointer %p (out of memory block!) - "
412                                 "aborting\n", p);
413                 abort();
414         }
415 #endif
416         if (p==0) {
417                 LOG(L_WARN, "WARNING:fm_free: free(0) called\n");
418                 return;
419         }
420         f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
421 #ifdef DBG_F_MALLOC
422         MDBG("fm_free: freeing block alloc'ed from %s: %s(%ld)\n",
423                         f->file, f->func, f->line);
424 #endif
425         size=f->size;
426 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
427         qm->used-=size;
428         qm->real_used-=size;
429 #endif
430 #ifdef DBG_F_MALLOC
431         f->file=file;
432         f->func=func;
433         f->line=line;
434 #endif
435         fm_insert_free(qm, f);
436 }
437
438
439 #ifdef DBG_F_MALLOC
440 void* fm_realloc(struct fm_block* qm, void* p, unsigned long size,
441                                         const char* file, const char* func, unsigned int line)
442 #else
443 void* fm_realloc(struct fm_block* qm, void* p, unsigned long size)
444 #endif
445 {
446         struct fm_frag *f;
447         struct fm_frag **pf;
448         unsigned long diff;
449         unsigned long orig_size;
450         struct fm_frag *n;
451         void *ptr;
452         int hash;
453         
454 #ifdef DBG_F_MALLOC
455         MDBG("fm_realloc(%p, %p, %lu) called from %s: %s(%d)\n", qm, p, size,
456                         file, func, line);
457         if ((p)&&(p>(void*)qm->last_frag || p<(void*)qm->first_frag)){
458                 LOG(L_CRIT, "BUG: fm_free: bad pointer %p (out of memory block!) - "
459                                 "aborting\n", p);
460                 abort();
461         }
462 #endif
463         if (size==0) {
464                 if (p)
465 #ifdef DBG_F_MALLOC
466                         fm_free(qm, p, file, func, line);
467 #else
468                         fm_free(qm, p);
469 #endif
470                 return 0;
471         }
472         if (p==0)
473 #ifdef DBG_F_MALLOC
474                 return fm_malloc(qm, size, file, func, line);
475 #else
476                 return fm_malloc(qm, size);
477 #endif
478         f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
479 #ifdef DBG_F_MALLOC
480         MDBG("fm_realloc: realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
481                         f, f->file, f->func, f->line);
482 #endif
483         size=ROUNDUP(size);
484         orig_size=f->size;
485         if (f->size > size){
486                 /* shrink */
487 #ifdef DBG_F_MALLOC
488                 MDBG("fm_realloc: shrinking from %lu to %lu\n", f->size, size);
489                 fm_split_frag(qm, f, size, file, "frag. from fm_realloc", line);
490 #else
491                 fm_split_frag(qm, f, size);
492 #endif
493 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
494                 qm->real_used-=(orig_size-f->size-FRAG_OVERHEAD);
495                 qm->used-=(orig_size-f->size);
496 #endif
497         }else if (f->size<size){
498                 /* grow */
499 #ifdef DBG_F_MALLOC
500                 MDBG("fm_realloc: growing from %lu to %lu\n", f->size, size);
501 #endif
502                 diff=size-f->size;
503                 n=FRAG_NEXT(f);
504                 if (((char*)n < (char*)qm->last_frag) && 
505                                 (n->u.nxt_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
506                         /* join  */
507                         /* detach n from the free list */
508                         hash=GET_HASH(n->size);
509                         pf=&(qm->free_hash[hash].first);
510                         /* find it */
511                         for(;(*pf)&&(*pf!=n); pf=&((*pf)->u.nxt_free)); /*FIXME slow */
512                         if (*pf==0){
513                                 /* not found, bad! */
514                                 LOG(L_CRIT, "BUG: fm_realloc: could not find %p in free "
515                                                 "list (hash=%ld)\n", n, GET_HASH(n->size));
516                                 abort();
517                         }
518                         /* detach */
519                         *pf=n->u.nxt_free;
520                         qm->free_hash[hash].no--;
521 #ifdef F_MALLOC_HASH_BITMAP
522                         if (qm->free_hash[hash].no==0)
523                                 fm_bmp_reset(qm, hash);
524 #endif /* F_MALLOC_HASH_BITMAP */
525                         /* join */
526                         f->size+=n->size+FRAG_OVERHEAD;
527                 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
528                         qm->real_used-=FRAG_OVERHEAD;
529                 #endif
530                         /* split it if necessary */
531                         if (f->size > size){
532                 #ifdef DBG_F_MALLOC
533                                 fm_split_frag(qm, f, size, file, "fragm. from fm_realloc",
534                                                 line);
535                 #else
536                                 fm_split_frag(qm, f, size);
537                 #endif
538                         }
539                 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
540                         qm->real_used+=(f->size-orig_size);
541                         qm->used+=(f->size-orig_size);
542                 #endif
543                 }else{
544                         /* could not join => realloc */
545         #ifdef DBG_F_MALLOC
546                         ptr=fm_malloc(qm, size, file, func, line);
547         #else
548                         ptr=fm_malloc(qm, size);
549         #endif
550                         if (ptr){
551                                 /* copy, need by libssl */
552                                 memcpy(ptr, p, orig_size);
553         #ifdef DBG_F_MALLOC
554                                 fm_free(qm, p, file, func, line);
555         #else
556                                 fm_free(qm, p);
557         #endif
558                         }
559                         p=ptr;
560                 }
561         }else{
562                 /* do nothing */
563 #ifdef DBG_F_MALLOC
564                 MDBG("fm_realloc: doing nothing, same size: %lu - %lu\n", 
565                                 f->size, size);
566 #endif
567         }
568 #ifdef DBG_F_MALLOC
569         MDBG("fm_realloc: returning %p\n", p);
570 #endif
571         return p;
572 }
573
574
575
576 void fm_status(struct fm_block* qm)
577 {
578         struct fm_frag* f;
579         int i,j;
580         int h;
581         int unused;
582         unsigned long size;
583         int memlog;
584
585         memlog=cfg_get(core, core_cfg, memlog);
586         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", "fm_status (%p):\n", qm);
587         if (!qm) return;
588
589         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", " heap size= %ld\n",
590                         qm->size);
591 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
592         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
593                         " used= %lu, used+overhead=%lu, free=%lu\n",
594                         qm->used, qm->real_used, qm->size-qm->real_used);
595         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
596                         " max used (+overhead)= %lu\n", qm->max_real_used);
597 #endif
598         /*
599         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", "dumping all fragments:\n");
600         for (f=qm->first_frag, i=0;((char*)f<(char*)qm->last_frag) && (i<10);
601                         f=FRAG_NEXT(f), i++){
602                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
603                                 "    %3d. %c  address=%x  size=%d\n", i,
604                                 (f->u.reserved)?'a':'N',
605                                 (char*)f+sizeof(struct fm_frag), f->size);
606 #ifdef DBG_F_MALLOC
607                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
608                                 "            %s from %s: %s(%d)\n",
609                                 (f->u.is_free)?"freed":"alloc'd", f->file, f->func, f->line);
610 #endif
611         }
612 */
613         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", "dumping free list:\n");
614         for(h=0,i=0,size=0;h<F_HASH_SIZE;h++){
615                 unused=0;
616                 for (f=qm->free_hash[h].first,j=0; f;
617                                 size+=f->size,f=f->u.nxt_free,i++,j++){
618                         if (!FRAG_WAS_USED(f)){
619                                 unused++;
620 #ifdef DBG_F_MALLOC
621                                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
622                                                         "unused fragm.: hash = %3d, fragment %p,"
623                                                         " address %p size %lu, created from %s: %s(%ld)\n",
624                                                     h, f, (char*)f+sizeof(struct fm_frag), f->size,
625                                                         f->file, f->func, f->line);
626 #endif
627                         };
628                 }
629                 if (j) LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
630                                                         "hash = %3d fragments no.: %5d, unused: %5d\n\t\t"
631                                                         " bucket size: %9lu - %9lu (first %9lu)\n",
632                                                         h, j, unused, UN_HASH(h),
633                                                 ((h<=F_MALLOC_OPTIMIZE/ROUNDTO)?1:2)* UN_HASH(h),
634                                                         qm->free_hash[h].first->size
635                                 );
636                 if (j!=qm->free_hash[h].no){
637                         LOG(L_CRIT, "BUG: fm_status: different free frag. count: %d!=%ld"
638                                         " for hash %3d\n", j, qm->free_hash[h].no, h);
639                 }
640                 /*
641                 {
642                         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
643                                         "   %5d.[%3d:%3d] %c  address=%x  size=%d(%x)\n",
644                                         i, h, j,
645                                         (f->u.reserved)?'a':'N',
646                                         (char*)f+sizeof(struct fm_frag), f->size, f->size);
647 #ifdef DBG_F_MALLOC
648                         DBG("            %s from %s: %s(%d)\n", 
649                                 (f->u.reserved)?"freed":"alloc'd", f->file, f->func, f->line);
650 #endif
651                 }
652         */
653         }
654         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
655                         "TOTAL: %6d free fragments = %6lu free bytes\n", i, size);
656         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
657                         "-----------------------------\n");
658 }
659
660
661
662 /* fills a malloc info structure with info about the block
663  * if a parameter is not supported, it will be filled with 0 */
664 void fm_info(struct fm_block* qm, struct mem_info* info)
665 {
666         int r;
667         long total_frags;
668 #if !defined(DBG_F_MALLOC) && !defined(MALLOC_STATS)
669         struct fm_frag* f;
670 #endif
671         
672         memset(info,0, sizeof(*info));
673         total_frags=0;
674         info->total_size=qm->size;
675         info->min_frag=MIN_FRAG_SIZE;
676 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
677         info->free=qm->size-qm->real_used;
678         info->used=qm->used;
679         info->real_used=qm->real_used;
680         info->max_used=qm->max_real_used;
681         for(r=0;r<F_HASH_SIZE; r++){
682                 total_frags+=qm->free_hash[r].no;
683         }
684 #else
685         /* we'll have to compute it all */
686         for (r=0; r<=F_MALLOC_OPTIMIZE/ROUNDTO; r++){
687                 info->free+=qm->free_hash[r].no*UN_HASH(r);
688                 total_frags+=qm->free_hash[r].no;
689         }
690         for(;r<F_HASH_SIZE; r++){
691                 total_frags+=qm->free_hash[r].no;
692                 for(f=qm->free_hash[r].first;f;f=f->u.nxt_free){
693                         info->free+=f->size;
694                 }
695         }
696         info->real_used=info->total_size-info->free;
697         info->used=0; /* we don't really now */
698         info->used=info->real_used-total_frags*FRAG_OVERHEAD-INIT_OVERHEAD-
699                                         FRAG_OVERHEAD;
700         info->max_used=0; /* we don't really now */
701 #endif
702         info->total_frags=total_frags;
703 }
704
705
706
707 /* returns how much free memory is available
708  * on error (not compiled with bookkeeping code) returns (unsigned long)(-1) */
709 unsigned long fm_available(struct fm_block* qm)
710 {
711
712 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
713         return qm->size-qm->real_used;
714 #else
715         /* we don't know how much free memory we have and it's to expensive
716          * to compute it */
717         return ((unsigned long)-1);
718 #endif
719 }
720
721
722 #ifdef DBG_F_MALLOC
723
724 typedef struct _mem_counter{
725         const char *file;
726         const char *func;
727         unsigned long line;
728         
729         unsigned long size;
730         int count;
731         
732         struct _mem_counter *next;
733 } mem_counter;
734
735 static mem_counter* get_mem_counter(mem_counter **root,struct fm_frag* f)
736 {
737         mem_counter *x;
738         
739         if (!*root) goto make_new;
740         for(x=*root;x;x=x->next)
741                 if (x->file == f->file && x->func == f->func && x->line == f->line)
742                         return x;
743 make_new:       
744         x = malloc(sizeof(mem_counter));
745         x->file = f->file;
746         x->func = f->func;
747         x->line = f->line;
748         x->count = 0;
749         x->size = 0;
750         x->next = *root;
751         *root = x;
752         return x;
753 }
754
755
756
757 void fm_sums(struct fm_block* qm)
758 {
759         struct fm_frag* f;
760         struct fm_frag* free_frag;
761         int i, hash;
762         int memlog;
763         mem_counter *root,*x;
764         
765         root=0;
766         if (!qm) return;
767
768         memlog=cfg_get(core, core_cfg, memlog);
769         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
770                         "summarizing all alloc'ed. fragments:\n");
771         
772         for (f=qm->first_frag, i=0; (char*)f<(char*)qm->last_frag;
773                         f=FRAG_NEXT(f), i++){
774                 if (f->u.nxt_free==0){
775                         /* it might be in-use or the last free fragm. in a free list 
776                            => search the free frags of the same size for a possible
777                            match --andrei*/
778                         hash=GET_HASH(f->size);
779                         for(free_frag=qm->free_hash[hash].first;
780                                         free_frag && (free_frag!=f);
781                                         free_frag=free_frag->u.nxt_free);
782                         if (free_frag==0){ /* not found among the free frag */
783                                 x = get_mem_counter(&root,f);
784                                 x->count++;
785                                 x->size+=f->size;
786                         }
787                 }
788         }
789         x = root;
790         while(x){
791                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
792                                 " count=%6d size=%10lu bytes from %s: %s(%ld)\n",
793                         x->count,x->size,
794                         x->file, x->func, x->line
795                         );
796                 root = x->next;
797                 free(x);
798                 x = root;
799         }
800         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
801                         "-----------------------------\n");
802 }
803 #endif /* DBG_F_MALLOC */
804
805
806
807 #endif