f_malloc.c

Go to the documentation of this file.
00001 /* $Id: f_malloc.c 5720 2009-03-18 12:55:53Z henningw $
00002  *
00003  * Copyright (C) 2001-2003 FhG Fokus
00004  *
00005  * This file is part of Kamailio, a free SIP server.
00006  *
00007  * Kamailio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version
00011  *
00012  * Kamailio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License 
00018  * along with this program; if not, write to the Free Software 
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  * History:
00022  * --------
00023  *              created by andrei
00024  *  2003-07-06  added fm_realloc (andrei)
00025  *  2004-07-19  fragments book keeping code and support for 64 bits
00026  *               memory blocks (64 bits machine & size >=2^32) 
00027  *              GET_HASH s/</<=/ (avoids waste of 1 hash cell)   (andrei)
00028  *  2004-11-10  support for > 4Gb mem., switched to long (andrei)
00029  *  2005-03-02  added fm_info() (andrei)
00030  *  2005-12-12  fixed realloc shrink real_used accounting (andrei)
00031  *              fixed initial size (andrei)
00032  *  2006-02-03  fixed realloc out of mem. free bug (andrei)
00033  *  2006-04-07  s/DBG/MDBG (andrei)
00034  *  2007-02-23  added fm_available() (andrei)
00035  *  2007-06-23  added hash bitmap (andrei)
00036  */
00037 
00038 
00039 #if !defined(q_malloc) && (defined F_MALLOC)
00040 
00041 #include <string.h>
00042 #include <stdlib.h>
00043 
00044 #include "f_malloc.h"
00045 #include "../dprint.h"
00046 #include "../globals.h"
00047 #include "../statistics.h"
00048 #include "../compiler_opt.h"
00049 #include "../bit_scan.h"
00050 
00051 
00052 /*useful macros*/
00053 
00054 #define FRAG_NEXT(f) \
00055    ((struct fm_frag*)((char*)(f)+sizeof(struct fm_frag)+(f)->size ))
00056 
00057 #define FRAG_OVERHEAD   (sizeof(struct fm_frag))
00058 #define INIT_OVERHEAD   \
00059    (ROUNDUP(sizeof(struct fm_block))+sizeof(struct fm_frag))
00060 
00061 
00062 
00063 /* ROUNDTO= 2^k so the following works */
00064 #define ROUNDTO_MASK (~((unsigned long)ROUNDTO-1))
00065 #define ROUNDUP(s)      (((s)+(ROUNDTO-1))&ROUNDTO_MASK)
00066 #define ROUNDDOWN(s) ((s)&ROUNDTO_MASK)
00067 
00068 /*
00069  #define ROUNDUP(s)     (((s)%ROUNDTO)?((s)+ROUNDTO)/ROUNDTO*ROUNDTO:(s))
00070  #define ROUNDDOWN(s)   (((s)%ROUNDTO)?((s)-ROUNDTO)/ROUNDTO*ROUNDTO:(s))
00071 */
00072 
00073 
00074 
00075    /* finds the hash value for s, s=ROUNDTO multiple*/
00076 #define GET_HASH(s)   ( ((unsigned long)(s)<=F_MALLOC_OPTIMIZE)?\
00077                      (unsigned long)(s)/ROUNDTO: \
00078                      F_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
00079                         F_MALLOC_OPTIMIZE_FACTOR+1 )
00080 
00081 #define UN_HASH(h)   ( ((unsigned long)(h)<=(F_MALLOC_OPTIMIZE/ROUNDTO))?\
00082                   (unsigned long)(h)*ROUNDTO: \
00083                   1UL<<((unsigned long)(h)-F_MALLOC_OPTIMIZE/ROUNDTO+\
00084                      F_MALLOC_OPTIMIZE_FACTOR-1)\
00085                )
00086 
00087 #ifdef F_MALLOC_HASH_BITMAP
00088 
00089 #define fm_bmp_set(qm, b) \
00090    do{ \
00091       (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] |= \
00092                                  1UL<<((b)%FM_HASH_BMP_BITS); \
00093    }while(0)
00094 
00095 #define fm_bmp_reset(qm, b) \
00096    do{ \
00097       (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] &= \
00098                                  ~(1UL<<((b)%FM_HASH_BMP_BITS)); \
00099    }while(0)
00100 
00101 /* returns 0 if not set, !=0 if set */
00102 #define fm_bmp_is_set(qm, b) \
00103    ((qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] & (1UL<<((b)%FM_HASH_BMP_BITS)))
00104 
00105 inline static int fm_bmp_first_set(struct fm_block* qm, int start)
00106 {
00107    int bmp_idx;
00108    int bit;
00109    int r;
00110    fm_hash_bitmap_t test_val;
00111    fm_hash_bitmap_t v;
00112    
00113    bmp_idx=start/FM_HASH_BMP_BITS;
00114    bit=start%FM_HASH_BMP_BITS;
00115    test_val=1UL <<((unsigned long)bit);
00116    if (qm->free_bitmap[bmp_idx] & test_val)
00117       return start;
00118    else if (qm->free_bitmap[bmp_idx] & ~(test_val-1)){
00119 #if 0
00120       test_val<<=1;
00121       for (r=bit+1; r<FM_HASH_BMP_BITS; r++, test_val<<=1){
00122          if (qm->free_bitmap[bmp_idx] & test_val)
00123             return (start-bit+r);
00124       }
00125 #endif
00126       v=qm->free_bitmap[bmp_idx]>>(bit+1);
00127       return start+1+bit_scan_forward((unsigned long)v);
00128    }
00129    for (r=bmp_idx+1;r<FM_HASH_BMP_SIZE; r++){
00130       if (qm->free_bitmap[r]){
00131          /* find first set bit */
00132          return r*FM_HASH_BMP_BITS+
00133                   bit_scan_forward((unsigned long)qm->free_bitmap[r]);
00134       }
00135    }
00136    /* not found, nothing free */
00137    return -1;
00138 }
00139 #endif /* F_MALLOC_HASH_BITMAP */
00140 
00141 
00142 
00143 /* mark/test used/unused frags */
00144 #define FRAG_MARK_USED(f)
00145 #define FRAG_CLEAR_USED(f)
00146 #define FRAG_WAS_USED(f)   (1)
00147 
00148 /* other frag related defines:
00149  * MEM_COALESCE_FRAGS 
00150  * MEM_FRAG_AVOIDANCE
00151  */
00152 #define MEM_FRAG_AVOIDANCE
00153 
00154 
00155 /* computes hash number for big buckets*/
00156 #if 0
00157 inline static unsigned long big_hash_idx(unsigned long s)
00158 {
00159    unsigned long idx;
00160    /* s is rounded => s = k*2^n (ROUNDTO=2^n) 
00161     * index= i such that 2^(i+1) > s >= 2^i
00162     *
00163     * => index = number of the first non null bit in s*/
00164    idx=sizeof(long)*8-1;
00165    for (; !(s&(1UL<<(sizeof(long)*8-1))) ; s<<=1, idx--);
00166    return idx;
00167 }
00168 #else
00169 #define big_hash_idx(s) ((unsigned long)bit_scan_reverse((unsigned long)(s)))
00170 #endif
00171 
00172 
00173 #ifdef DBG_F_MALLOC
00174 #define ST_CHECK_PATTERN   0xf0f0f0f0
00175 #define END_CHECK_PATTERN1 0xc0c0c0c0
00176 #define END_CHECK_PATTERN2 0xabcdefed
00177 #endif
00178 
00179 
00180 
00181 static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag)
00182 {
00183    struct fm_frag** f;
00184    int hash;
00185    
00186    hash=GET_HASH(frag->size);
00187    f=&(qm->free_hash[hash].first);
00188    if (frag->size > F_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH,
00189                                  (different from 0.8.1[24] on
00190                                   purpose --andrei ) */
00191       for(; *f; f=&((*f)->u.nxt_free)){
00192          if (frag->size <= (*f)->size) break;
00193       }
00194    }
00195    
00196    /*insert it here*/
00197    frag->u.nxt_free=*f;
00198    *f=frag;
00199    qm->free_hash[hash].no++;
00200 #ifdef F_MALLOC_HASH_BITMAP
00201    fm_bmp_set(qm, hash);
00202 #endif /* F_MALLOC_HASH_BITMAP */
00203 }
00204 
00205 
00206 
00207  /* size should be already rounded-up */
00208 static inline
00209 #ifdef DBG_F_MALLOC 
00210 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
00211                unsigned long size,
00212                const char* file, const char* func, unsigned int line)
00213 #else
00214 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
00215                unsigned long size)
00216 #endif
00217 {
00218    unsigned long rest;
00219    struct fm_frag* n;
00220    
00221    rest=frag->size-size;
00222 #ifdef MEM_FRAG_AVOIDANCE
00223    if ((rest> (FRAG_OVERHEAD+F_MALLOC_OPTIMIZE))||
00224       (rest>=(FRAG_OVERHEAD+size))){ /* the residue fragm. is big enough*/
00225 #else
00226    if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
00227 #endif
00228       frag->size=size;
00229       /*split the fragment*/
00230       n=FRAG_NEXT(frag);
00231       n->size=rest-FRAG_OVERHEAD;
00232       FRAG_CLEAR_USED(n); /* never used */
00233 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00234       qm->real_used+=FRAG_OVERHEAD;
00235 #endif
00236 #ifdef DBG_F_MALLOC
00237       /* frag created by malloc, mark it*/
00238       n->file=file;
00239       n->func="frag. from fm_malloc";
00240       n->line=line;
00241       n->check=ST_CHECK_PATTERN;
00242 #endif
00243       /* reinsert n in free list*/
00244       fm_insert_free(qm, n);
00245    }else{
00246       /* we cannot split this fragment any more => alloc all of it*/
00247    }
00248 }
00249 
00250 
00251 
00252 /* init malloc and return a fm_block*/
00253 struct fm_block* fm_malloc_init(char* address, unsigned long size)
00254 {
00255    char* start;
00256    char* end;
00257    struct fm_block* qm;
00258    unsigned long init_overhead;
00259    
00260    /* make address and size multiple of 8*/
00261    start=(char*)ROUNDUP((unsigned long) address);
00262    LM_DBG("F_OPTIMIZE=%lu, /ROUNDTO=%lu\n",
00263          F_MALLOC_OPTIMIZE, F_MALLOC_OPTIMIZE/ROUNDTO);
00264    LM_DBG("F_HASH_SIZE=%lu, fm_block size=%lu\n",
00265          F_HASH_SIZE, (long)sizeof(struct fm_block));
00266    LM_DBG("params (%p, %lu), start=%p\n", address, size, start);
00267 
00268    if (size<(unsigned long)(start-address)) return 0;
00269    size-=(start-address);
00270    if (size <(MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0;
00271    size=ROUNDDOWN(size);
00272 
00273    init_overhead=INIT_OVERHEAD;
00274    
00275    
00276    if (size < init_overhead)
00277    {
00278       /* not enough mem to create our control structures !!!*/
00279       return 0;
00280    }
00281    end=start+size;
00282    qm=(struct fm_block*)start;
00283    memset(qm, 0, sizeof(struct fm_block));
00284    qm->size=size;
00285 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00286    qm->real_used=init_overhead;
00287    qm->max_real_used=qm->real_used;
00288 #endif
00289    size-=init_overhead;
00290    
00291    qm->first_frag=(struct fm_frag*)(start+ROUNDUP(sizeof(struct fm_block)));
00292    qm->last_frag=(struct fm_frag*)(end-sizeof(struct fm_frag));
00293    /* init initial fragment*/
00294    qm->first_frag->size=size;
00295    qm->last_frag->size=0;
00296    
00297 #ifdef DBG_F_MALLOC
00298    qm->first_frag->check=ST_CHECK_PATTERN;
00299    qm->last_frag->check=END_CHECK_PATTERN1;
00300 #endif
00301    
00302    /* link initial fragment into the free list*/
00303    
00304    fm_insert_free(qm, qm->first_frag);
00305    
00306    
00307    return qm;
00308 }
00309 
00310 
00311 
00312 #ifdef DBG_F_MALLOC
00313 void* fm_malloc(struct fm_block* qm, unsigned long size,
00314                const char* file, const char* func, unsigned int line)
00315 #else
00316 void* fm_malloc(struct fm_block* qm, unsigned long size)
00317 #endif
00318 {
00319    struct fm_frag** f;
00320    struct fm_frag* frag;
00321    int hash;
00322    
00323 #ifdef DBG_F_MALLOC
00324    LM_DBG("params (%p, %lu), called from %s: %s(%d)\n", qm, size, file, func,
00325          line);
00326 #endif
00327    /*size must be a multiple of 8*/
00328    size=ROUNDUP(size);
00329 /* if (size>(qm->size-qm->real_used)) return 0; */
00330 
00331    
00332    /*search for a suitable free frag*/
00333 
00334 #ifdef F_MALLOC_HASH_BITMAP
00335    hash=fm_bmp_first_set(qm, GET_HASH(size));
00336    if (likely(hash>=0)){
00337       f=&(qm->free_hash[hash].first);
00338    if (likely(hash<=F_MALLOC_OPTIMIZE)) /* return first match */
00339          goto found; 
00340       for(;(*f); f=&((*f)->u.nxt_free))
00341          if ((*f)->size>=size) goto found;
00342    }
00343 #else /* F_MALLOC_HASH_BITMAP */
00344    for(hash=GET_HASH(size);hash<F_HASH_SIZE;hash++){
00345       f=&(qm->free_hash[hash].first);
00346 #if 0
00347       if (likely(hash<=F_MALLOC_OPTIMIZE)) /* return first match */
00348             goto found; 
00349 #endif
00350       for(;(*f); f=&((*f)->u.nxt_free))
00351          if ((*f)->size>=size) goto found;
00352       /* try in a bigger bucket */
00353    }
00354 #endif /* F_MALLOC_HASH_BITMAP */
00355    /* not found, bad! */
00356    return 0;
00357 
00358 found:
00359    /* we found it!*/
00360    /* detach it from the free list*/
00361    frag=*f;
00362    *f=frag->u.nxt_free;
00363    frag->u.nxt_free=0; /* mark it as 'taken' */
00364    qm->free_hash[hash].no--;
00365 #ifdef F_MALLOC_HASH_BITMAP
00366    if (qm->free_hash[hash].no==0)
00367       fm_bmp_reset(qm, hash);
00368 #endif /* F_MALLOC_HASH_BITMAP */
00369    
00370    /*see if we'll use full frag, or we'll split it in 2*/
00371    
00372 #ifdef DBG_F_MALLOC
00373    fm_split_frag(qm, frag, size, file, func, line);
00374 
00375    frag->file=file;
00376    frag->func=func;
00377    frag->line=line;
00378    frag->check=ST_CHECK_PATTERN;
00379    LM_DBG("params(%p, %lu), returns address %p \n", qm, size,
00380       (char*)frag+sizeof(struct fm_frag));
00381 #else
00382    fm_split_frag(qm, frag, size);
00383 #endif
00384 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00385    qm->real_used+=frag->size;
00386    qm->used+=frag->size;
00387    if (qm->max_real_used<qm->real_used)
00388       qm->max_real_used=qm->real_used;
00389 #endif
00390    FRAG_MARK_USED(frag); /* mark it as used */
00391    return (char*)frag+sizeof(struct fm_frag);
00392 }
00393 
00394 
00395 
00396 #ifdef DBG_F_MALLOC
00397 void fm_free(struct fm_block* qm, void* p, const char* file, const char* func, 
00398             unsigned int line)
00399 #else
00400 void fm_free(struct fm_block* qm, void* p)
00401 #endif
00402 {
00403    struct fm_frag* f;
00404    unsigned long size;
00405 
00406 #ifdef DBG_F_MALLOC
00407    LM_DBG("params(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line);
00408    if (p>(void*)qm->last_frag || p<(void*)qm->first_frag){
00409       LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
00410       abort();
00411    }
00412 #endif
00413    if (p==0) {
00414       LM_WARN("free(0) called\n");
00415       return;
00416    }
00417    f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
00418 #ifdef DBG_F_MALLOC
00419    LM_DBG("freeing block alloc'ed from %s: %s(%ld)\n", f->file, f->func,
00420          f->line);
00421 #endif
00422    size=f->size;
00423 
00424 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00425    qm->used-=size;
00426    qm->real_used-=size;
00427 #endif
00428 #ifdef DBG_F_MALLOC
00429    f->file=file;
00430    f->func=func;
00431    f->line=line;
00432 #endif
00433    fm_insert_free(qm, f);
00434 }
00435 
00436 
00437 #ifdef DBG_F_MALLOC
00438 void* fm_realloc(struct fm_block* qm, void* p, unsigned long size,
00439                const char* file, const char* func, unsigned int line)
00440 #else
00441 void* fm_realloc(struct fm_block* qm, void* p, unsigned long size)
00442 #endif
00443 {
00444    struct fm_frag *f;
00445    struct fm_frag **pf;
00446    unsigned long diff;
00447    unsigned long orig_size;
00448    struct fm_frag *n;
00449    void *ptr;
00450    int hash;
00451    
00452 #ifdef DBG_F_MALLOC
00453    LM_DBG("params(%p, %p, %lu), called from %s: %s(%d)\n", qm, p, size,
00454          file, func, line);
00455    if ((p)&&(p>(void*)qm->last_frag || p<(void*)qm->first_frag)){
00456       LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p);
00457       abort();
00458    }
00459 #endif
00460    if (size==0) {
00461       if (p)
00462 #ifdef DBG_F_MALLOC
00463          fm_free(qm, p, file, func, line);
00464 #else
00465          fm_free(qm, p);
00466 #endif
00467       return 0;
00468    }
00469    if (p==0)
00470 #ifdef DBG_F_MALLOC
00471       return fm_malloc(qm, size, file, func, line);
00472 #else
00473       return fm_malloc(qm, size);
00474 #endif
00475    f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
00476 #ifdef DBG_F_MALLOC
00477    LM_DBG("realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
00478          f, f->file, f->func, f->line);
00479 #endif
00480    size=ROUNDUP(size);
00481    orig_size=f->size;
00482    if (f->size > size){
00483       /* shrink */
00484 #ifdef DBG_F_MALLOC
00485       LM_DBG("shrinking from %lu to %lu\n", f->size, size);
00486       fm_split_frag(qm, f, size, file, "frag. from fm_realloc", line);
00487 #else
00488       fm_split_frag(qm, f, size);
00489 #endif
00490 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00491       qm->real_used-=(orig_size-f->size-FRAG_OVERHEAD);
00492       qm->used-=(orig_size-f->size);
00493 #endif
00494    }else if (f->size<size){
00495       /* grow */
00496 #ifdef DBG_F_MALLOC
00497       LM_DBG("growing from %lu to %lu\n", f->size, size);
00498 #endif
00499       diff=size-f->size;
00500       n=FRAG_NEXT(f);
00501       if (((char*)n < (char*)qm->last_frag) && 
00502             (n->u.nxt_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
00503          /* join  */
00504          /* detach n from the free list */
00505          hash=GET_HASH(n->size);
00506          pf=&(qm->free_hash[hash].first);
00507          /* find it */
00508          for(;(*pf)&&(*pf!=n); pf=&((*pf)->u.nxt_free)); /*FIXME slow */
00509          if (*pf==0){
00510             /* not found, bad! */
00511             LM_CRIT("could not find %p in free "
00512                   "list (hash=%ld)\n", n, GET_HASH(n->size));
00513             abort();
00514          }
00515          /* detach */
00516          *pf=n->u.nxt_free;
00517          qm->free_hash[hash].no--;
00518 #ifdef F_MALLOC_HASH_BITMAP
00519          if (qm->free_hash[hash].no==0)
00520             fm_bmp_reset(qm, hash);
00521 #endif /* F_MALLOC_HASH_BITMAP */
00522          /* join */
00523          f->size+=n->size+FRAG_OVERHEAD;
00524       #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00525          qm->real_used-=FRAG_OVERHEAD;
00526       #endif
00527          /* split it if necessary */
00528          if (f->size > size){
00529       #ifdef DBG_F_MALLOC
00530             fm_split_frag(qm, f, size, file, "fragm. from fm_realloc",
00531                   line);
00532       #else
00533             fm_split_frag(qm, f, size);
00534       #endif
00535          }
00536       #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00537          qm->real_used+=(f->size-orig_size);
00538          qm->used+=(f->size-orig_size);
00539       #endif
00540       }else{
00541          /* could not join => realloc */
00542    #ifdef DBG_F_MALLOC
00543          ptr=fm_malloc(qm, size, file, func, line);
00544    #else
00545          ptr=fm_malloc(qm, size);
00546    #endif
00547          if (ptr){
00548             /* copy, need by libssl */
00549             memcpy(ptr, p, orig_size);
00550    #ifdef DBG_F_MALLOC
00551             fm_free(qm, p, file, func, line);
00552    #else
00553             fm_free(qm, p);
00554    #endif
00555          }
00556          p=ptr;
00557       }
00558    }else{
00559       /* do nothing */
00560 #ifdef DBG_F_MALLOC
00561       LM_DBG("doing nothing, same size: %lu - %lu\n", f->size, size);
00562 #endif
00563    }
00564 #ifdef DBG_F_MALLOC
00565    LM_DBG("returning %p\n", p);
00566 #endif
00567    return p;
00568 }
00569 
00570 
00571 
00572 void fm_status(struct fm_block* qm)
00573 {
00574    struct fm_frag* f;
00575    int i,j;
00576    int h;
00577    int unused;
00578    unsigned long size;
00579 
00580    LM_GEN1(memlog, "fm_status (%p):\n", qm);
00581    if (!qm) return;
00582 
00583    LM_GEN1(memlog, " heap size= %ld\n", qm->size);
00584 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00585    LM_GEN1(memlog, " used= %lu, used+overhead=%lu, free=%lu\n",
00586          qm->used, qm->real_used, qm->size-qm->real_used);
00587    LM_GEN1(memlog, " max used (+overhead)= %lu\n", qm->max_real_used);
00588 #endif
00589    /*
00590    LM_GEN1(memlog, "dumping all fragments:\n");
00591    for (f=qm->first_frag, i=0;((char*)f<(char*)qm->last_frag) && (i<10);
00592          f=FRAG_NEXT(f), i++){
00593       LM_GEN1(memlog, "    %3d. %c  address=%x  size=%d\n", i, 
00594             (f->u.reserved)?'a':'N',
00595             (char*)f+sizeof(struct fm_frag), f->size);
00596 #ifdef DBG_F_MALLOC
00597       LM_GEN1(memlog, "            %s from %s: %s(%d)\n",
00598             (f->u.is_free)?"freed":"alloc'd", f->file, f->func, f->line);
00599 #endif
00600    }
00601 */
00602    LM_GEN1(memlog, "dumping free list:\n");
00603    for(h=0,i=0,size=0;h<F_HASH_SIZE;h++){
00604       unused=0;
00605       for (f=qm->free_hash[h].first,j=0; f;
00606             size+=f->size,f=f->u.nxt_free,i++,j++){
00607          if (!FRAG_WAS_USED(f)){
00608             unused++;
00609 #ifdef DBG_F_MALLOC
00610             LM_GEN1(memlog, "unused fragm.: hash = %3d, fragment %p,"
00611                      " address %p size %lu, created from %s: %s(%ld)\n",
00612                       h, f, (char*)f+sizeof(struct fm_frag), f->size,
00613                      f->file, f->func, f->line);
00614 #endif
00615          };
00616       }
00617       if (j) LM_GEN1(memlog,"hash = %3d fragments no.: %5d, unused: %5d\n\t\t"
00618                      " bucket size: %9lu - %9lu (first %9lu)\n",
00619                      h, j, unused, UN_HASH(h),
00620                   ((h<=F_MALLOC_OPTIMIZE/ROUNDTO)?1:2)* UN_HASH(h),
00621                      qm->free_hash[h].first->size
00622             );
00623       if (j!=qm->free_hash[h].no){
00624          LM_CRIT("different free frag. count: %d!=%ld"
00625                " for hash %3d\n", j, qm->free_hash[h].no, h);
00626       }
00627       /*
00628       {
00629          LM_GEN1(memlog, "   %5d.[%3d:%3d] %c  address=%x  size=%d(%x)\n",
00630                i, h, j,
00631                (f->u.reserved)?'a':'N',
00632                (char*)f+sizeof(struct fm_frag), f->size, f->size);
00633 #ifdef DBG_F_MALLOC
00634          LM_DBG("            %s from %s: %s(%d)\n", 
00635             (f->u.reserved)?"freed":"alloc'd", f->file, f->func, f->line);
00636 #endif
00637       }
00638    */
00639    }
00640    LM_GEN1(memlog, "TOTAL: %6d free fragments = %6lu free bytes\n", i, size);
00641    LM_GEN1(memlog, "-----------------------------\n");
00642 }
00643 
00644 
00645 
00646 /* fills a malloc info structure with info about the block
00647  * if a parameter is not supported, it will be filled with 0 */
00648 void fm_info(struct fm_block* qm, struct mem_info* info)
00649 {
00650    int r;
00651    long total_frags;
00652 #if !defined(DBG_F_MALLOC) && !defined(STATISTICS)
00653    struct fm_frag* f;
00654 #endif
00655    
00656    memset(info,0, sizeof(*info));
00657    total_frags=0;
00658    info->total_size=qm->size;
00659    info->min_frag=MIN_FRAG_SIZE;
00660 #if defined(DBG_F_MALLOC) || defined(STATISTICS)
00661    info->free=qm->size-qm->real_used;
00662    info->used=qm->used;
00663    info->real_used=qm->real_used;
00664    info->max_used=qm->max_real_used;
00665    for(r=0;r<F_HASH_SIZE; r++){
00666       total_frags+=qm->free_hash[r].no;
00667    }
00668 #else
00669    /* we'll have to compute it all */
00670    for (r=0; r<=F_MALLOC_OPTIMIZE/ROUNDTO; r++){
00671       info->free+=qm->free_hash[r].no*UN_HASH(r);
00672       total_frags+=qm->free_hash[r].no;
00673    }
00674    for(;r<F_HASH_SIZE; r++){
00675       total_frags+=qm->free_hash[r].no;
00676       for(f=qm->free_hash[r].first;f;f=f->u.nxt_free){
00677          info->free+=f->size;
00678       }
00679    }
00680    info->real_used=info->total_size-info->free;
00681    info->used=0; /* we don't really now */
00682    info->used=info->real_used-total_frags*FRAG_OVERHEAD-INIT_OVERHEAD-
00683                FRAG_OVERHEAD;
00684    info->max_used=0; /* we don't really now */
00685 #endif
00686    info->total_frags=total_frags;
00687 }
00688 
00689 
00690 
00691 /* returns how much free memory is available
00692  * on error (not compiled with bookkeeping code) returns (unsigned long)(-1) */
00693 unsigned long fm_available(struct fm_block* qm)
00694 {
00695 
00696 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00697    return qm->size-qm->real_used;
00698 #else
00699    /* we don't know how much free memory we have and it's to expensive
00700     * to compute it */
00701    return ((unsigned long)-1);
00702 #endif
00703 }
00704 
00705 #endif

Generated on Wed May 23 06:00:45 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6