f_malloc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2003 FhG Fokus
00003  *
00004  * This file is part of sip-router, a free SIP server.
00005  *
00006  * Permission to use, copy, modify, and distribute this software for any
00007  * purpose with or without fee is hereby granted, provided that the above
00008  * copyright notice and this permission notice appear in all copies.
00009  *
00010  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00011  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00012  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00013  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00014  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00015  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00016  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00017  */
00018 
00019 /*
00020  * History:
00021  * --------
00022  *              created by andrei
00023  *  2003-07-06  added fm_realloc (andrei)
00024  *  2004-07-19  fragments book keeping code and support for 64 bits
00025  *               memory blocks (64 bits machine & size >=2^32) 
00026  *              GET_HASH s/</<=/ (avoids waste of 1 hash cell)   (andrei)
00027  *  2004-11-10  support for > 4Gb mem., switched to long (andrei)
00028  *  2005-03-02  added fm_info() (andrei)
00029  *  2005-12-12  fixed realloc shrink real_used accounting (andrei)
00030  *              fixed initial size (andrei)
00031  *  2006-02-03  fixed realloc out of mem. free bug (andrei)
00032  *  2006-04-07  s/DBG/MDBG (andrei)
00033  *  2007-02-23  added fm_available() (andrei)
00034  *  2007-06-23  added hash bitmap (andrei)
00035  *  2009-09-28  added fm_sums() (patch from Dragos Vingarzan)
00036  *  2010-03-11  fix big fragments bug (smaller fragment was wrongly
00037  *               returned sometimes) (andrei)
00038  *  2010-03-12  fix real_used stats for realloc: a realloc that shrank an
00039  *               allocation accounted twice fro the frag. overhead (andrei)
00040  *  2010-09-30  fixed search for big fragments using the hash bitmap
00041  *               (only the first bucket was tried) (andrei)
00042  */
00043 
00051 #if !defined(q_malloc)  && (defined F_MALLOC)
00052 
00053 #include <string.h>
00054 #include <stdlib.h>
00055 
00056 #include "f_malloc.h"
00057 #include "../dprint.h"
00058 #include "../globals.h"
00059 #include "../compiler_opt.h"
00060 #include "memdbg.h"
00061 #include "../bit_scan.h"
00062 #include "../cfg/cfg.h" /* memlog */
00063 #ifdef MALLOC_STATS
00064 #include "../events.h"
00065 #endif
00066 
00067 
00068 /* useful macros */
00069 
00070 #define FRAG_NEXT(f) \
00071         ((struct fm_frag*)((char*)(f)+sizeof(struct fm_frag)+(f)->size ))
00072 
00073 #define FRAG_OVERHEAD   (sizeof(struct fm_frag))
00074 #define INIT_OVERHEAD   \
00075         (ROUNDUP(sizeof(struct fm_block))+sizeof(struct fm_frag))
00076 
00077 
00078 
00080 #define ROUNDTO_MASK    (~((unsigned long)ROUNDTO-1))
00081 #define ROUNDUP(s)              (((s)+(ROUNDTO-1))&ROUNDTO_MASK)
00082 #define ROUNDDOWN(s)    ((s)&ROUNDTO_MASK)
00083 
00084 
00085 
00087 #define GET_HASH(s)   ( ((unsigned long)(s)<=F_MALLOC_OPTIMIZE)?\
00088                                                         (unsigned long)(s)/ROUNDTO: \
00089                                                         F_MALLOC_OPTIMIZE/ROUNDTO+big_hash_idx((s))- \
00090                                                                 F_MALLOC_OPTIMIZE_FACTOR+1 )
00091 
00092 #define UN_HASH(h)      ( ((unsigned long)(h)<=(F_MALLOC_OPTIMIZE/ROUNDTO))?\
00093                                                 (unsigned long)(h)*ROUNDTO: \
00094                                                 1UL<<((unsigned long)(h)-F_MALLOC_OPTIMIZE/ROUNDTO+\
00095                                                         F_MALLOC_OPTIMIZE_FACTOR-1)\
00096                                         )
00097 
00098 
00099 #ifdef F_MALLOC_HASH_BITMAP
00100 
00101 #define fm_bmp_set(qm, b) \
00102         do{ \
00103                 (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] |= \
00104                                                                                         1UL<<((b)%FM_HASH_BMP_BITS); \
00105         }while(0)
00106 
00107 #define fm_bmp_reset(qm, b) \
00108         do{ \
00109                 (qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] &= \
00110                                                                                         ~(1UL<<((b)%FM_HASH_BMP_BITS)); \
00111         }while(0)
00112 
00114 #define fm_bmp_is_set(qm, b) \
00115         ((qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] & (1UL<<((b)%FM_HASH_BMP_BITS)))
00116 
00117 
00118 
00127 inline static int fm_bmp_first_set(struct fm_block* qm, int start)
00128 {
00129         int bmp_idx;
00130         int bit;
00131         int r;
00132         fm_hash_bitmap_t test_val;
00133         fm_hash_bitmap_t v;
00134         
00135         bmp_idx=start/FM_HASH_BMP_BITS;
00136         bit=start%FM_HASH_BMP_BITS;
00137         test_val=1UL <<((unsigned long)bit);
00138         if (qm->free_bitmap[bmp_idx] & test_val)
00139                 return start;
00140         else if (qm->free_bitmap[bmp_idx] & ~(test_val-1)){
00141 #if 0
00142                 test_val<<=1;
00143                 for (r=bit+1; r<FM_HASH_BMP_BITS; r++, test_val<<=1){
00144                         if (qm->free_bitmap[bmp_idx] & test_val)
00145                                 return (start-bit+r);
00146                 }
00147 #endif
00148                 v=qm->free_bitmap[bmp_idx]>>(bit+1);
00149                 return start+1+bit_scan_forward((unsigned long)v);
00150         }
00151         for (r=bmp_idx+1;r<FM_HASH_BMP_SIZE; r++){
00152                 if (qm->free_bitmap[r]){
00153                         /* find first set bit */
00154                         return r*FM_HASH_BMP_BITS+
00155                                                 bit_scan_forward((unsigned long)qm->free_bitmap[r]);
00156                 }
00157         }
00158         /* not found, nothing free */
00159         return -1;
00160 }
00161 #endif /* F_MALLOC_HASH_BITMAP */
00162 
00163 
00164 
00165 /* mark/test used/unused frags */
00166 #define FRAG_MARK_USED(f)
00167 #define FRAG_CLEAR_USED(f)
00168 #define FRAG_WAS_USED(f)   (1)
00169 
00170 /* other frag related defines:
00171  * MEM_COALESCE_FRAGS 
00172  * MEM_FRAG_AVOIDANCE
00173  */
00174 #define MEM_FRAG_AVOIDANCE
00175 
00176 
00178 #define big_hash_idx(s) ((unsigned long)bit_scan_reverse((unsigned long)(s)))
00179 
00180 
00184 
00185 #ifdef DBG_F_MALLOC
00186 #define ST_CHECK_PATTERN   0xf0f0f0f0 
00187 #define END_CHECK_PATTERN1 0xc0c0c0c0 
00188 #define END_CHECK_PATTERN2 0xabcdefed 
00189 
00190 #endif
00191 
00192 
00198 static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag)
00199 {
00200         struct fm_frag** f;
00201         int hash;
00202         
00203         hash=GET_HASH(frag->size);
00204         f=&(qm->free_hash[hash].first);
00205         if (frag->size > F_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH,
00206                                                                                         (different from 0.8.1[24] on
00207                                                                                          purpose --andrei ) */
00208                 for(; *f; f=&((*f)->u.nxt_free)){
00209                         if (frag->size <= (*f)->size) break;
00210                 }
00211         }
00212         
00213         /*insert it here*/
00214         frag->u.nxt_free=*f;
00215         *f=frag;
00216         qm->free_hash[hash].no++;
00217 #ifdef F_MALLOC_HASH_BITMAP
00218         fm_bmp_set(qm, hash);
00219 #endif /* F_MALLOC_HASH_BITMAP */
00220 }
00221 
00222 
00231 static inline
00232 #ifdef DBG_F_MALLOC 
00233 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
00234                                         unsigned long size,
00235                                         const char* file, const char* func, unsigned int line)
00236 #else
00237 void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
00238                                         unsigned long size)
00239 #endif
00240 {
00241         unsigned long rest;
00242         struct fm_frag* n;
00243         
00244         rest=frag->size-size;
00245 #ifdef MEM_FRAG_AVOIDANCE
00246         if ((rest> (FRAG_OVERHEAD+F_MALLOC_OPTIMIZE))||
00247                 (rest>=(FRAG_OVERHEAD+size))){ /* the residue fragm. is big enough*/
00248 #else
00249         if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
00250 #endif
00251                 frag->size=size;
00252                 /*split the fragment*/
00253                 n=FRAG_NEXT(frag);
00254                 n->size=rest-FRAG_OVERHEAD;
00255                 FRAG_CLEAR_USED(n); /* never used */
00256 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00257                 qm->real_used+=FRAG_OVERHEAD;
00258 #ifdef MALLOC_STATS
00259                 sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00260 #endif
00261 #endif
00262 #ifdef DBG_F_MALLOC
00263                 /* frag created by malloc, mark it*/
00264                 n->file=file;
00265                 n->func="frag. from fm_malloc";
00266                 n->line=line;
00267                 n->check=ST_CHECK_PATTERN;
00268 #endif
00269                 /* reinsert n in free list*/
00270                 fm_insert_free(qm, n);
00271         }else{
00272                 /* we cannot split this fragment any more => alloc all of it*/
00273         }
00274 }
00275 
00276 
00283 struct fm_block* fm_malloc_init(char* address, unsigned long size)
00284 {
00285         char* start;
00286         char* end;
00287         struct fm_block* qm;
00288         unsigned long init_overhead;
00289         
00290         /* make address and size multiple of 8*/
00291         start=(char*)ROUNDUP((unsigned long) address);
00292         DBG("fm_malloc_init: F_OPTIMIZE=%lu, /ROUNDTO=%lu\n",
00293                         F_MALLOC_OPTIMIZE, F_MALLOC_OPTIMIZE/ROUNDTO);
00294         DBG("fm_malloc_init: F_HASH_SIZE=%lu, fm_block size=%lu\n",
00295                         F_HASH_SIZE, (long)sizeof(struct fm_block));
00296         DBG("fm_malloc_init(%p, %lu), start=%p\n", address, size, start);
00297 
00298         if (size<start-address) return 0;
00299         size-=(start-address);
00300         if (size <(MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0;
00301         size=ROUNDDOWN(size);
00302 
00303         init_overhead=INIT_OVERHEAD;
00304         
00305         
00306         if (size < init_overhead)
00307         {
00308                 /* not enough mem to create our control structures !!!*/
00309                 return 0;
00310         }
00311         end=start+size;
00312         qm=(struct fm_block*)start;
00313         memset(qm, 0, sizeof(struct fm_block));
00314         qm->size=size;
00315 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00316         qm->real_used=init_overhead;
00317         qm->max_real_used=qm->real_used;
00318 #endif
00319         size-=init_overhead;
00320         
00321         qm->first_frag=(struct fm_frag*)(start+ROUNDUP(sizeof(struct fm_block)));
00322         qm->last_frag=(struct fm_frag*)(end-sizeof(struct fm_frag));
00323         /* init initial fragment*/
00324         qm->first_frag->size=size;
00325         qm->last_frag->size=0;
00326         
00327 #ifdef DBG_F_MALLOC
00328         qm->first_frag->check=ST_CHECK_PATTERN;
00329         qm->last_frag->check=END_CHECK_PATTERN1;
00330 #endif
00331         
00332         /* link initial fragment into the free list*/
00333         
00334         fm_insert_free(qm, qm->first_frag);
00335         
00336         
00337         return qm;
00338 }
00339 
00340 
00349 #ifdef DBG_F_MALLOC
00350 void* fm_malloc(struct fm_block* qm, unsigned long size,
00351                                         const char* file, const char* func, unsigned int line)
00352 #else
00353 void* fm_malloc(struct fm_block* qm, unsigned long size)
00354 #endif
00355 {
00356         struct fm_frag** f;
00357         struct fm_frag* frag;
00358         int hash;
00359         
00360 #ifdef DBG_F_MALLOC
00361         MDBG("fm_malloc(%p, %lu) called from %s: %s(%d)\n", qm, size, file, func,
00362                         line);
00363 #endif
00364         /*size must be a multiple of 8*/
00365         size=ROUNDUP(size);
00366 /*      if (size>(qm->size-qm->real_used)) return 0; */
00367 
00368         
00369         /*search for a suitable free frag*/
00370 
00371 #ifdef F_MALLOC_HASH_BITMAP
00372         hash=fm_bmp_first_set(qm, GET_HASH(size));
00373         if (likely(hash>=0)){
00374                 if (likely(hash<=F_MALLOC_OPTIMIZE/ROUNDTO)) { /* return first match */
00375                         f=&(qm->free_hash[hash].first);
00376                         goto found;
00377                 }
00378                 /* if we are here we are searching for a "big" fragment
00379                    between F_MALLOC_OPTIMIZE/ROUNDTO+1
00380                    and F_MALLOC_OPTIMIZE/ROUNDTO + (32|64) - F_MALLOC_OPTIMIZE_FACTOR
00381                    => 18 hash buckets on 32 bits and 50 buckets on 64 bits
00382                    The free hash bitmap is used to jump directly to non-empty
00383                    hash buckets.
00384                 */
00385                 do {
00386                         for(f=&(qm->free_hash[hash].first);(*f); f=&((*f)->u.nxt_free))
00387                                 if ((*f)->size>=size) goto found;
00388                         hash++; /* try in next hash cell */
00389                 }while((hash < F_HASH_SIZE) &&
00390                                 ((hash=fm_bmp_first_set(qm, hash)) >= 0));
00391         }
00392 #else /* F_MALLOC_HASH_BITMAP */
00393         for(hash=GET_HASH(size);hash<F_HASH_SIZE;hash++){
00394                 f=&(qm->free_hash[hash].first);
00395 #if 0
00396                 if (likely(hash<=F_MALLOC_OPTIMIZE/ROUNDTO)) /* return first match */
00397                                 goto found; 
00398 #endif
00399                 for(;(*f); f=&((*f)->u.nxt_free))
00400                         if ((*f)->size>=size) goto found;
00401                 /* try in a bigger bucket */
00402         }
00403 #endif /* F_MALLOC_HASH_BITMAP */
00404         /* not found, bad! */
00405         return 0;
00406 
00407 found:
00408         /* we found it!*/
00409         /* detach it from the free list*/
00410         frag=*f;
00411         *f=frag->u.nxt_free;
00412         frag->u.nxt_free=0; /* mark it as 'taken' */
00413         qm->free_hash[hash].no--;
00414 #ifdef F_MALLOC_HASH_BITMAP
00415         if (qm->free_hash[hash].no==0)
00416                 fm_bmp_reset(qm, hash);
00417 #endif /* F_MALLOC_HASH_BITMAP */
00418         
00419         /*see if we'll use full frag, or we'll split it in 2*/
00420         
00421 #ifdef DBG_F_MALLOC
00422         fm_split_frag(qm, frag, size, file, func, line);
00423 
00424         frag->file=file;
00425         frag->func=func;
00426         frag->line=line;
00427         frag->check=ST_CHECK_PATTERN;
00428         MDBG("fm_malloc(%p, %lu) returns address %p \n", qm, size,
00429                 (char*)frag+sizeof(struct fm_frag));
00430 #else
00431         fm_split_frag(qm, frag, size);
00432 #endif
00433 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00434         qm->real_used+=frag->size;
00435         qm->used+=frag->size;
00436         if (qm->max_real_used<qm->real_used)
00437                 qm->max_real_used=qm->real_used;
00438 #ifdef MALLOC_STATS
00439         sr_event_exec(SREV_PKG_SET_USED, (void*)qm->used);
00440         sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00441 #endif
00442 #endif
00443         FRAG_MARK_USED(frag); /* mark it as used */
00444         return (char*)frag+sizeof(struct fm_frag);
00445 }
00446 
00447 
00448 #ifdef MEM_JOIN_FREE
00449 
00452 static void fm_join_frag(struct fm_block* qm, struct fm_frag* f)
00453 {
00454         int hash;
00455         struct fm_frag **pf;
00456         struct fm_frag* n;
00457 
00458         n=FRAG_NEXT(f);
00459         /* check if valid and if in free list */
00460         if (((char*)n >= (char*)qm->last_frag) || (n->u.nxt_free==NULL))
00461                 return;
00462 
00463         /* detach n from the free list */
00464         hash=GET_HASH(n->size);
00465         pf=&(qm->free_hash[hash].first);
00466         /* find it */
00467         for(;(*pf)&&(*pf!=n); pf=&((*pf)->u.nxt_free)); /*FIXME slow */
00468         if (*pf==0){
00469                 /* not found, bad! */
00470                 LM_WARN("could not find %p in free list (hash=%ld)\n", n, GET_HASH(n->size));
00471                 return;
00472         }
00473         /* detach */
00474         *pf=n->u.nxt_free;
00475         qm->free_hash[hash].no--;
00476 #ifdef F_MALLOC_HASH_BITMAP
00477         if (qm->free_hash[hash].no==0)
00478                 fm_bmp_reset(qm, hash);
00479 #endif /* F_MALLOC_HASH_BITMAP */
00480         /* join */
00481         f->size+=n->size+FRAG_OVERHEAD;
00482 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00483         qm->real_used-=FRAG_OVERHEAD;
00484 #ifdef MALLOC_STATS
00485         sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00486 #endif /* MALLOC_STATS */
00487 #endif /* DBG_F_MALLOC || MALLOC_STATS*/
00488 }
00489 #endif /*MEM_JOIN_FREE*/
00490 
00498 #ifdef DBG_F_MALLOC
00499 void fm_free(struct fm_block* qm, void* p, const char* file, const char* func, 
00500                                 unsigned int line)
00501 #else
00502 void fm_free(struct fm_block* qm, void* p)
00503 #endif
00504 {
00505         struct fm_frag* f;
00506         unsigned long size;
00507 
00508 #ifdef DBG_F_MALLOC
00509         MDBG("fm_free(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line);
00510         if (p>(void*)qm->last_frag || p<(void*)qm->first_frag){
00511                 LOG(L_CRIT, "BUG: fm_free: bad pointer %p (out of memory block!),"
00512                                 " called from %s: %s(%d) - aborting\n", p,
00513                                 file, func, line);
00514                 if(likely(cfg_get(core, core_cfg, mem_safety)==0))
00515                         abort();
00516         }
00517 #endif
00518         if (p==0) {
00519                 LOG(L_WARN, "WARNING:fm_free: free(0) called\n");
00520                 return;
00521         }
00522         f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
00523 #ifdef DBG_F_MALLOC
00524         MDBG("fm_free: freeing block alloc'ed from %s: %s(%ld)\n",
00525                         f->file, f->func, f->line);
00526 #endif
00527         if(unlikely(f->u.nxt_free!=NULL)) {
00528                 LM_INFO("freeing a free fragment (%p/%p) - ignore\n",
00529                                 f, p);
00530                 return;
00531         }
00532         size=f->size;
00533 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00534         qm->used-=size;
00535         qm->real_used-=size;
00536 #ifdef MALLOC_STATS
00537         sr_event_exec(SREV_PKG_SET_USED, (void*)qm->used);
00538         sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00539 #endif
00540 #endif
00541 #ifdef DBG_F_MALLOC
00542         f->file=file;
00543         f->func=func;
00544         f->line=line;
00545 #endif
00546 #ifdef MEM_JOIN_FREE
00547         if(unlikely(cfg_get(core, core_cfg, mem_join)!=0))
00548                 fm_join_frag(qm, f);
00549 #endif /*MEM_JOIN_FREE*/
00550         fm_insert_free(qm, f);
00551 }
00552 
00553 
00563 #ifdef DBG_F_MALLOC
00564 void* fm_realloc(struct fm_block* qm, void* p, unsigned long size,
00565                                         const char* file, const char* func, unsigned int line)
00566 #else
00567 void* fm_realloc(struct fm_block* qm, void* p, unsigned long size)
00568 #endif
00569 {
00570         struct fm_frag *f;
00571         struct fm_frag **pf;
00572         unsigned long diff;
00573         unsigned long orig_size;
00574         struct fm_frag *n;
00575         void *ptr;
00576         int hash;
00577         
00578 #ifdef DBG_F_MALLOC
00579         MDBG("fm_realloc(%p, %p, %lu) called from %s: %s(%d)\n", qm, p, size,
00580                         file, func, line);
00581         if ((p)&&(p>(void*)qm->last_frag || p<(void*)qm->first_frag)){
00582                 LOG(L_CRIT, "BUG: fm_free: bad pointer %p (out of memory block!) - "
00583                                 "aborting\n", p);
00584                 abort();
00585         }
00586 #endif
00587         if (size==0) {
00588                 if (p)
00589 #ifdef DBG_F_MALLOC
00590                         fm_free(qm, p, file, func, line);
00591 #else
00592                         fm_free(qm, p);
00593 #endif
00594                 return 0;
00595         }
00596         if (p==0)
00597 #ifdef DBG_F_MALLOC
00598                 return fm_malloc(qm, size, file, func, line);
00599 #else
00600                 return fm_malloc(qm, size);
00601 #endif
00602         f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));
00603 #ifdef DBG_F_MALLOC
00604         MDBG("fm_realloc: realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
00605                         f, f->file, f->func, f->line);
00606 #endif
00607         size=ROUNDUP(size);
00608         orig_size=f->size;
00609         if (f->size > size){
00610                 /* shrink */
00611 #ifdef DBG_F_MALLOC
00612                 MDBG("fm_realloc: shrinking from %lu to %lu\n", f->size, size);
00613                 fm_split_frag(qm, f, size, file, "frag. from fm_realloc", line);
00614 #else
00615                 fm_split_frag(qm, f, size);
00616 #endif
00617 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00618                 /* fm_split frag already adds FRAG_OVERHEAD for the newly created
00619                    free frag, so here we only need orig_size-f->size for real used */
00620                 qm->real_used-=(orig_size-f->size);
00621                 qm->used-=(orig_size-f->size);
00622 #ifdef MALLOC_STATS
00623                 sr_event_exec(SREV_PKG_SET_USED, (void*)qm->used);
00624                 sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00625 #endif
00626 #endif
00627         }else if (f->size<size){
00628                 /* grow */
00629 #ifdef DBG_F_MALLOC
00630                 MDBG("fm_realloc: growing from %lu to %lu\n", f->size, size);
00631 #endif
00632                 diff=size-f->size;
00633                 n=FRAG_NEXT(f);
00634                 if (((char*)n < (char*)qm->last_frag) && 
00635                                 (n->u.nxt_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
00636                         /* join  */
00637                         /* detach n from the free list */
00638                         hash=GET_HASH(n->size);
00639                         pf=&(qm->free_hash[hash].first);
00640                         /* find it */
00641                         for(;(*pf)&&(*pf!=n); pf=&((*pf)->u.nxt_free)); /*FIXME slow */
00642                         if (*pf==0){
00643                                 /* not found, bad! */
00644                                 LOG(L_CRIT, "BUG: fm_realloc: could not find %p in free "
00645                                                 "list (hash=%ld)\n", n, GET_HASH(n->size));
00646                                 abort();
00647                         }
00648                         /* detach */
00649                         *pf=n->u.nxt_free;
00650                         qm->free_hash[hash].no--;
00651 #ifdef F_MALLOC_HASH_BITMAP
00652                         if (qm->free_hash[hash].no==0)
00653                                 fm_bmp_reset(qm, hash);
00654 #endif /* F_MALLOC_HASH_BITMAP */
00655                         /* join */
00656                         f->size+=n->size+FRAG_OVERHEAD;
00657                 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00658                         qm->real_used-=FRAG_OVERHEAD;
00659 #ifdef MALLOC_STATS
00660                         sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00661 #endif
00662                 #endif
00663                         /* split it if necessary */
00664                         if (f->size > size){
00665                 #ifdef DBG_F_MALLOC
00666                                 fm_split_frag(qm, f, size, file, "fragm. from fm_realloc",
00667                                                 line);
00668                 #else
00669                                 fm_split_frag(qm, f, size);
00670                 #endif
00671                         }
00672                 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00673                         qm->real_used+=(f->size-orig_size);
00674                         qm->used+=(f->size-orig_size);
00675 #ifdef MALLOC_STATS
00676                         sr_event_exec(SREV_PKG_SET_USED, (void*)qm->used);
00677                         sr_event_exec(SREV_PKG_SET_REAL_USED, (void*)qm->real_used);
00678 #endif
00679                 #endif
00680                 }else{
00681                         /* could not join => realloc */
00682         #ifdef DBG_F_MALLOC
00683                         ptr=fm_malloc(qm, size, file, func, line);
00684         #else
00685                         ptr=fm_malloc(qm, size);
00686         #endif
00687                         if (ptr){
00688                                 /* copy, need by libssl */
00689                                 memcpy(ptr, p, orig_size);
00690         #ifdef DBG_F_MALLOC
00691                                 fm_free(qm, p, file, func, line);
00692         #else
00693                                 fm_free(qm, p);
00694         #endif
00695                         }
00696                         p=ptr;
00697                 }
00698         }else{
00699                 /* do nothing */
00700 #ifdef DBG_F_MALLOC
00701                 MDBG("fm_realloc: doing nothing, same size: %lu - %lu\n", 
00702                                 f->size, size);
00703 #endif
00704         }
00705 #ifdef DBG_F_MALLOC
00706         MDBG("fm_realloc: returning %p\n", p);
00707 #endif
00708         return p;
00709 }
00710 
00711 
00716 void fm_status(struct fm_block* qm)
00717 {
00718         struct fm_frag* f;
00719         int i,j;
00720         int h;
00721         int unused;
00722         unsigned long size;
00723         int memlog;
00724         int mem_summary;
00725 
00726         memlog=cfg_get(core, core_cfg, memlog);
00727         mem_summary=cfg_get(core, core_cfg, mem_summary);
00728         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", "fm_status (%p):\n", qm);
00729         if (!qm) return;
00730 
00731         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", " heap size= %ld\n",
00732                         qm->size);
00733 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00734         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00735                         " used= %lu, used+overhead=%lu, free=%lu\n",
00736                         qm->used, qm->real_used, qm->size-qm->real_used);
00737         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00738                         " max used (+overhead)= %lu\n", qm->max_real_used);
00739 #endif
00740 
00741         if (mem_summary & 16) return;
00742 
00743         /*
00744         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", "dumping all fragments:\n");
00745         for (f=qm->first_frag, i=0;((char*)f<(char*)qm->last_frag) && (i<10);
00746                         f=FRAG_NEXT(f), i++){
00747                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00748                                 "    %3d. %c  address=%x  size=%d\n", i,
00749                                 (f->u.reserved)?'a':'N',
00750                                 (char*)f+sizeof(struct fm_frag), f->size);
00751 #ifdef DBG_F_MALLOC
00752                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00753                                 "            %s from %s: %s(%d)\n",
00754                                 (f->u.is_free)?"freed":"alloc'd", f->file, f->func, f->line);
00755 #endif
00756         }
00757 */
00758         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ", "dumping free list:\n");
00759         for(h=0,i=0,size=0;h<F_HASH_SIZE;h++){
00760                 unused=0;
00761                 for (f=qm->free_hash[h].first,j=0; f;
00762                                 size+=f->size,f=f->u.nxt_free,i++,j++){
00763                         if (!FRAG_WAS_USED(f)){
00764                                 unused++;
00765 #ifdef DBG_F_MALLOC
00766                                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00767                                                         "unused fragm.: hash = %3d, fragment %p,"
00768                                                         " address %p size %lu, created from %s: %s(%ld)\n",
00769                                                     h, f, (char*)f+sizeof(struct fm_frag), f->size,
00770                                                         f->file, f->func, f->line);
00771 #endif
00772                         };
00773                 }
00774                 if (j) LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00775                                                         "hash = %3d fragments no.: %5d, unused: %5d\n\t\t"
00776                                                         " bucket size: %9lu - %9lu (first %9lu)\n",
00777                                                         h, j, unused, UN_HASH(h),
00778                                                 ((h<=F_MALLOC_OPTIMIZE/ROUNDTO)?1:2)* UN_HASH(h),
00779                                                         qm->free_hash[h].first->size
00780                                 );
00781                 if (j!=qm->free_hash[h].no){
00782                         LOG(L_CRIT, "BUG: fm_status: different free frag. count: %d!=%ld"
00783                                         " for hash %3d\n", j, qm->free_hash[h].no, h);
00784                 }
00785                 /*
00786                 {
00787                         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00788                                         "   %5d.[%3d:%3d] %c  address=%x  size=%d(%x)\n",
00789                                         i, h, j,
00790                                         (f->u.reserved)?'a':'N',
00791                                         (char*)f+sizeof(struct fm_frag), f->size, f->size);
00792 #ifdef DBG_F_MALLOC
00793                         DBG("            %s from %s: %s(%d)\n", 
00794                                 (f->u.reserved)?"freed":"alloc'd", f->file, f->func, f->line);
00795 #endif
00796                 }
00797         */
00798         }
00799         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00800                         "TOTAL: %6d free fragments = %6lu free bytes\n", i, size);
00801         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00802                         "-----------------------------\n");
00803 }
00804 
00805 
00814 void fm_info(struct fm_block* qm, struct mem_info* info)
00815 {
00816         int r;
00817         long total_frags;
00818 #if !defined(DBG_F_MALLOC) && !defined(MALLOC_STATS)
00819         struct fm_frag* f;
00820 #endif
00821         
00822         memset(info,0, sizeof(*info));
00823         total_frags=0;
00824         info->total_size=qm->size;
00825         info->min_frag=MIN_FRAG_SIZE;
00826 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00827         info->free=qm->size-qm->real_used;
00828         info->used=qm->used;
00829         info->real_used=qm->real_used;
00830         info->max_used=qm->max_real_used;
00831         for(r=0;r<F_HASH_SIZE; r++){
00832                 total_frags+=qm->free_hash[r].no;
00833         }
00834 #else
00835         /* we'll have to compute it all */
00836         for (r=0; r<=F_MALLOC_OPTIMIZE/ROUNDTO; r++){
00837                 info->free+=qm->free_hash[r].no*UN_HASH(r);
00838                 total_frags+=qm->free_hash[r].no;
00839         }
00840         for(;r<F_HASH_SIZE; r++){
00841                 total_frags+=qm->free_hash[r].no;
00842                 for(f=qm->free_hash[r].first;f;f=f->u.nxt_free){
00843                         info->free+=f->size;
00844                 }
00845         }
00846         info->real_used=info->total_size-info->free;
00847         info->used=0; /* we don't really now */
00848         info->used=info->real_used-total_frags*FRAG_OVERHEAD-INIT_OVERHEAD-
00849                                         FRAG_OVERHEAD;
00850         info->max_used=0; /* we don't really now */
00851 #endif
00852         info->total_frags=total_frags;
00853 }
00854 
00855 
00862 unsigned long fm_available(struct fm_block* qm)
00863 {
00864 
00865 #if defined(DBG_F_MALLOC) || defined(MALLOC_STATS)
00866         return qm->size-qm->real_used;
00867 #else
00868         /* we don't know how much free memory we have and it's to expensive
00869          * to compute it */
00870         return ((unsigned long)-1);
00871 #endif
00872 }
00873 
00874 
00875 #ifdef DBG_F_MALLOC
00876 
00877 typedef struct _mem_counter{
00878         const char *file;
00879         const char *func;
00880         unsigned long line;
00881         
00882         unsigned long size;
00883         int count;
00884         
00885         struct _mem_counter *next;
00886 } mem_counter;
00887 
00888 static mem_counter* get_mem_counter(mem_counter **root,struct fm_frag* f)
00889 {
00890         mem_counter *x;
00891         
00892         if (!*root) goto make_new;
00893         for(x=*root;x;x=x->next)
00894                 if (x->file == f->file && x->func == f->func && x->line == f->line)
00895                         return x;
00896 make_new:       
00897         x = malloc(sizeof(mem_counter));
00898         x->file = f->file;
00899         x->func = f->func;
00900         x->line = f->line;
00901         x->count = 0;
00902         x->size = 0;
00903         x->next = *root;
00904         *root = x;
00905         return x;
00906 }
00907 
00908 
00913 void fm_sums(struct fm_block* qm)
00914 {
00915         struct fm_frag* f;
00916         struct fm_frag* free_frag;
00917         int i, hash;
00918         int memlog;
00919         mem_counter *root,*x;
00920         
00921         root=0;
00922         if (!qm) return;
00923 
00924         memlog=cfg_get(core, core_cfg, memlog);
00925         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00926                         "summarizing all alloc'ed. fragments:\n");
00927         
00928         for (f=qm->first_frag, i=0; (char*)f<(char*)qm->last_frag;
00929                         f=FRAG_NEXT(f), i++){
00930                 if (f->u.nxt_free==0){
00931                         /* it might be in-use or the last free fragm. in a free list 
00932                            => search the free frags of the same size for a possible
00933                            match --andrei*/
00934                         hash=GET_HASH(f->size);
00935                         for(free_frag=qm->free_hash[hash].first;
00936                                         free_frag && (free_frag!=f);
00937                                         free_frag=free_frag->u.nxt_free);
00938                         if (free_frag==0){ /* not found among the free frag */
00939                                 x = get_mem_counter(&root,f);
00940                                 x->count++;
00941                                 x->size+=f->size;
00942                         }
00943                 }
00944         }
00945         x = root;
00946         while(x){
00947                 LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00948                                 " count=%6d size=%10lu bytes from %s: %s(%ld)\n",
00949                         x->count,x->size,
00950                         x->file, x->func, x->line
00951                         );
00952                 root = x->next;
00953                 free(x);
00954                 x = root;
00955         }
00956         LOG_(DEFAULT_FACILITY, memlog, "fm_status: ",
00957                         "-----------------------------\n");
00958 }
00959 #endif /* DBG_F_MALLOC */
00960 
00961 
00962 
00963 #endif