q_malloc.c

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

Generated on Thu May 24 08:00:53 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6