1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117 |
- /* $Id$
- *
- * shared memory, multi-process safe, pool based version of f_malloc
- *
- * Copyright (C) 2007 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- /*
- * History:
- * --------
- * created by andrei
- * 2003-07-06 added fm_realloc (andrei)
- * 2004-07-19 fragments book keeping code and support for 64 bits
- * memory blocks (64 bits machine & size >=2^32)
- * GET_HASH s/</<=/ (avoids waste of 1 hash cell) (andrei)
- * 2004-11-10 support for > 4Gb mem., switched to long (andrei)
- * 2005-03-02 added fm_info() (andrei)
- * 2005-12-12 fixed realloc shrink real_used accounting (andrei)
- * fixed initial size (andrei)
- * 2006-02-03 fixed realloc out of mem. free bug (andrei)
- * 2006-04-07 s/DBG/MDBG (andrei)
- * 2007-02-23 added fm_available() (andrei)
- * 2007-06-09 forked from the fm_maloc code (andrei)
- */
- #ifdef SF_MALLOC
- #include <string.h>
- #include <stdlib.h>
- #include "sf_malloc.h"
- #include "../dprint.h"
- #include "../globals.h"
- #include "memdbg.h"
- #include "../cfg/cfg.h" /* memlog */
- #define MAX_POOL_FRAGS 10000 /* max fragments per pool hash bucket */
- #define MIN_POOL_FRAGS 10 /* min fragments per pool hash bucket */
- /*useful macros*/
- #define FRAG_NEXT(f) \
- ((struct sfm_frag*)((char*)(f)+sizeof(struct sfm_frag)+(f)->size ))
- /* SF_ROUNDTO= 2^k so the following works */
- #define ROUNDTO_MASK (~((unsigned long)SF_ROUNDTO-1))
- #define ROUNDUP(s) (((s)+(SF_ROUNDTO-1))&ROUNDTO_MASK)
- #define ROUNDDOWN(s) ((s)&ROUNDTO_MASK)
- #define FRAG_OVERHEAD (sizeof(struct sfm_frag))
- #define INIT_OVERHEAD \
- (ROUNDUP(sizeof(struct sfm_block))+sizeof(struct sfm_frag))
- /* finds hash if s <=SF_MALLOC_OPTIMIZE */
- #define GET_SMALL_HASH(s) (unsigned long)(s)/SF_ROUNDTO
- /* finds hash if s > SF_MALLOC_OPTIMIZE */
- #define GET_BIG_HASH(s) \
- (SF_MALLOC_OPTIMIZE/SF_ROUNDTO+big_hash_idx((s))-SF_MALLOC_OPTIMIZE_FACTOR+1)
- /* finds the hash value for s, s=SF_ROUNDTO multiple*/
- #define GET_HASH(s) ( ((unsigned long)(s)<=SF_MALLOC_OPTIMIZE)?\
- GET_SMALL_HASH(s): GET_BIG_HASH(s) )
- #define UN_HASH_SMALL(h) ((unsigned long)(h)*SF_ROUNDTO)
- #define UN_HASH_BIG(h) (1UL<<((unsigned long)(h)-SF_MALLOC_OPTIMIZE/SF_ROUNDTO+\
- SF_MALLOC_OPTIMIZE_FACTOR-1))
- #define UN_HASH(h) ( ((unsigned long)(h)<=(SF_MALLOC_OPTIMIZE/SF_ROUNDTO))?\
- UN_HASH_SMALL(h): UN_HASH_BIG(h) )
- #define BITMAP_BITS (sizeof(((struct sfm_block*)0)->bitmap)*8)
- #define BITMAP_BLOCK_SIZE ((SF_MALLOC_OPTIMIZE/SF_ROUNDTO)/ BITMAP_BITS)
- /* only for "small" hashes (up to HASH(SF_MALLOC_OPTIMIZE) */
- #define HASH_BIT_POS(h) (((unsigned long)(h))/BITMAP_BLOCK_SIZE)
- #define HASH_TO_BITMAP(h) (1UL<<HASH_BIT_POS(h))
- #define BIT_TO_HASH(b) ((b)*BITMAP_BLOCK_SIZE)
- /* mark/test used/unused frags */
- #define FRAG_MARK_USED(f)
- #define FRAG_CLEAR_USED(f)
- #define FRAG_WAS_USED(f) (1)
- /* other frag related defines:
- * MEM_COALESCE_FRAGS
- * MEM_FRAG_AVOIDANCE
- */
- #define MEM_FRAG_AVOIDANCE
- #define SFM_REALLOC_REMALLOC
- /* computes hash number for big buckets*/
- inline static unsigned long big_hash_idx(unsigned long s)
- {
- unsigned long idx;
- /* s is rounded => s = k*2^n (SF_ROUNDTO=2^n)
- * index= i such that 2^i > s >= 2^(i-1)
- *
- * => index = number of the first non null bit in s*/
- idx=sizeof(long)*8-1;
- for (; !(s&(1UL<<(sizeof(long)*8-1))) ; s<<=1, idx--);
- return idx;
- }
- #ifdef DBG_F_MALLOC
- #define ST_CHECK_PATTERN 0xf0f0f0f0
- #define END_CHECK_PATTERN1 0xc0c0c0c0
- #define END_CHECK_PATTERN2 0xabcdefed
- #endif
- #ifdef SFM_ONE_LOCK
- #define SFM_MAIN_HASH_LOCK(qm, hash) lock_get(&(qm)->lock)
- #define SFM_MAIN_HASH_UNLOCK(qm, hash) lock_release(&(qm)->lock)
- #define SFM_POOL_LOCK(p, hash) lock_get(&(p)->lock)
- #define SFM_POOL_UNLOCK(p, hash) lock_release(&(p)->lock)
- #warn "degraded performance, only one lock"
- #elif defined SFM_LOCK_PER_BUCKET
- #define SFM_MAIN_HASH_LOCK(qm, hash) \
- lock_get(&(qm)->free_hash[(hash)].lock)
- #define SFM_MAIN_HASH_UNLOCK(qm, hash) \
- lock_release(&(qm)->free_hash[(hash)].lock)
- #define SFM_POOL_LOCK(p, hash) lock_get(&(p)->pool_hash[(hash)].lock)
- #define SFM_POOL_UNLOCK(p, hash) lock_release(&(p)->pool_hash[(hash)].lock)
- #else
- #error no locks defined
- #endif /* SFM_ONE_LOCK/SFM_LOCK_PER_BUCKET */
- #define SFM_BIG_GET_AND_SPLIT_LOCK(qm) lock_get(&(qm)->get_and_split)
- #define SFM_BIG_GET_AND_SPLIT_UNLOCK(qm) lock_release(&(qm)->get_and_split)
- static unsigned long sfm_max_hash=0; /* maximum hash value (no point in
- searching further) */
- static unsigned long pool_id=(unsigned long)-1;
- /* call for each child */
- int sfm_pool_reset()
- {
- pool_id=(unsigned long)-1;
- return 0;
- }
- #define sfm_fix_pool_id(qm) \
- do{ \
- if (unlikely(pool_id>=SFM_POOLS_NO)) \
- pool_id=((unsigned)atomic_add(&(qm)->crt_id, 1))%SFM_POOLS_NO; \
- }while(0)
- static inline void frag_push(struct sfm_frag** head, struct sfm_frag* frag)
- {
- frag->u.nxt_free=*head;
- *head=frag;
- }
- static inline struct sfm_frag* frag_pop(struct sfm_frag** head)
- {
- struct sfm_frag* frag;
- frag=*head;
- *head=frag->u.nxt_free;
- return frag;
- }
- static inline void sfm_pool_insert (struct sfm_pool* pool, int hash,
- struct sfm_frag* frag)
- {
- unsigned long hash_bit;
- SFM_POOL_LOCK(pool, hash);
- frag_push(&pool->pool_hash[hash].first, frag);
- pool->pool_hash[hash].no++;
- /* set it only if not already set (avoids an expensive
- * cache trashing atomic write op) */
- hash_bit=HASH_TO_BITMAP(hash);
- if (!(atomic_get_long((long*)&pool->bitmap) & hash_bit))
- atomic_or_long((long*)&pool->bitmap, hash_bit);
- SFM_POOL_UNLOCK(pool, hash);
- }
- /* returns 1 if it's ok to add a fragm. to pool p_id @ hash, 0 otherwise */
- static inline int sfm_check_pool(struct sfm_block* qm, unsigned long p_id,
- int hash, int split)
- {
- /* TODO: come up with something better
- * if fragment is some split/rest from an allocation, that is
- * >= requested size, accept it, else
- * look at misses and current fragments and decide based on them */
- return (p_id<SFM_POOLS_NO) && (split ||
- ( (qm->pool[p_id].pool_hash[hash].no < MIN_POOL_FRAGS) ||
- ((qm->pool[p_id].pool_hash[hash].misses >
- qm->pool[p_id].pool_hash[hash].no) &&
- (qm->pool[p_id].pool_hash[hash].no<MAX_POOL_FRAGS) ) ) );
- }
- /* choose on which pool to add a free'd packet
- * return - pool idx or -1 if it should be added to main*/
- static inline unsigned long sfm_choose_pool(struct sfm_block* qm,
- struct sfm_frag* frag,
- int hash, int split)
- {
- /* check original pool first */
- if (sfm_check_pool(qm, frag->id, hash, split))
- return frag->id;
- else{
- /* check if our pool is properly set */
- sfm_fix_pool_id(qm);
- /* check if my pool needs some frags */
- if ((pool_id!=frag->id) && (sfm_check_pool(qm, pool_id, hash, 0))){
- frag->id=pool_id;
- return pool_id;
- }
- }
- /* else add it back to main */
- frag->id=(unsigned long)(-1);
- return frag->id;
- }
- static inline void sfm_insert_free(struct sfm_block* qm, struct sfm_frag* frag,
- int split)
- {
- struct sfm_frag** f;
- unsigned long p_id;
- int hash;
- unsigned long hash_bit;
-
- if (likely(frag->size<=SF_POOL_MAX_SIZE)){
- hash=GET_SMALL_HASH(frag->size);
- if (unlikely((p_id=sfm_choose_pool(qm, frag, hash, split))==
- (unsigned long)-1)){
- /* add it back to the "main" hash */
- SFM_MAIN_HASH_LOCK(qm, hash);
- frag->id=(unsigned long)(-1); /* main hash marker */
- /*insert it here*/
- frag_push(&(qm->free_hash[hash].first), frag);
- qm->free_hash[hash].no++;
- /* set it only if not already set (avoids an expensive
- * cache trashing atomic write op) */
- hash_bit=HASH_TO_BITMAP(hash);
- if (!(atomic_get_long((long*)&qm->bitmap) & hash_bit))
- atomic_or_long((long*)&qm->bitmap, hash_bit);
- SFM_MAIN_HASH_UNLOCK(qm, hash);
- }else{
- /* add it to one of the pools pool */
- sfm_pool_insert(&qm->pool[p_id], hash, frag);
- }
- }else{
- hash=GET_BIG_HASH(frag->size);
- SFM_MAIN_HASH_LOCK(qm, hash);
- f=&(qm->free_hash[hash].first);
- for(; *f; f=&((*f)->u.nxt_free))
- if (frag->size <= (*f)->size) break;
- frag->id=(unsigned long)(-1); /* main hash marker */
- /*insert it here*/
- frag->u.nxt_free=*f;
- *f=frag;
- qm->free_hash[hash].no++;
- /* inc. big hash free size ? */
- SFM_MAIN_HASH_UNLOCK(qm, hash);
- }
-
- }
- /* size should be already rounded-up */
- static inline
- #ifdef DBG_F_MALLOC
- void sfm_split_frag(struct sfm_block* qm, struct sfm_frag* frag,
- unsigned long size,
- const char* file, const char* func, unsigned int line)
- #else
- void sfm_split_frag(struct sfm_block* qm, struct sfm_frag* frag,
- unsigned long size)
- #endif
- {
- unsigned long rest;
- struct sfm_frag* n;
- int bigger_rest;
-
- rest=frag->size-size;
- #ifdef MEM_FRAG_AVOIDANCE
- if ((rest> (FRAG_OVERHEAD+SF_MALLOC_OPTIMIZE))||
- (rest>=(FRAG_OVERHEAD+size))){ /* the residue fragm. is big enough*/
- bigger_rest=1;
- #else
- if (rest>(FRAG_OVERHEAD+SF_MIN_FRAG_SIZE)){
- bigger_rest=rest>=(size+FRAG_OVERHEAD);
- #endif
- frag->size=size;
- /*split the fragment*/
- n=FRAG_NEXT(frag);
- n->size=rest-FRAG_OVERHEAD;
- n->id=pool_id;
- FRAG_CLEAR_USED(n); /* never used */
- #ifdef DBG_F_MALLOC
- /* frag created by malloc, mark it*/
- n->file=file;
- n->func="frag. from sfm_malloc";
- n->line=line;
- n->check=ST_CHECK_PATTERN;
- #endif
- /* reinsert n in free list*/
- sfm_insert_free(qm, n, bigger_rest);
- }else{
- /* we cannot split this fragment any more => alloc all of it*/
- }
- }
- /* init malloc and return a sfm_block*/
- struct sfm_block* sfm_malloc_init(char* address, unsigned long size)
- {
- char* start;
- char* end;
- struct sfm_block* qm;
- unsigned long init_overhead;
- int r;
- #ifdef SFM_LOCK_PER_BUCKET
- int i;
- #endif
-
- /* make address and size multiple of 8*/
- start=(char*)ROUNDUP((unsigned long) address);
- DBG("sfm_malloc_init: SF_OPTIMIZE=%lu, /SF_ROUNDTO=%lu\n",
- SF_MALLOC_OPTIMIZE, SF_MALLOC_OPTIMIZE/SF_ROUNDTO);
- DBG("sfm_malloc_init: SF_HASH_SIZE=%lu, sfm_block size=%lu\n",
- SF_HASH_SIZE, (long)sizeof(struct sfm_block));
- DBG("sfm_malloc_init(%p, %lu), start=%p\n", address, size, start);
- if (size<start-address) return 0;
- size-=(start-address);
- if (size <(SF_MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0;
- size=ROUNDDOWN(size);
- init_overhead=INIT_OVERHEAD;
-
-
- if (size < init_overhead)
- {
- /* not enough mem to create our control structures !!!*/
- return 0;
- }
- end=start+size;
- qm=(struct sfm_block*)start;
- memset(qm, 0, sizeof(struct sfm_block));
- qm->size=size;
- size-=init_overhead;
-
- qm->first_frag=(struct sfm_frag*)(start+ROUNDUP(sizeof(struct sfm_block)));
- qm->last_frag=(struct sfm_frag*)(end-sizeof(struct sfm_frag));
- /* init initial fragment*/
- qm->first_frag->size=size;
- qm->first_frag->id=(unsigned long)-1; /* not in a pool */
- qm->last_frag->size=0;
-
- #ifdef DBG_F_MALLOC
- qm->first_frag->check=ST_CHECK_PATTERN;
- qm->last_frag->check=END_CHECK_PATTERN1;
- #endif
-
- /* link initial fragment into the free list*/
-
- sfm_insert_free(qm, qm->first_frag, 0);
- sfm_max_hash=GET_HASH(size);
-
- /* init locks */
- if (lock_init(&qm->get_and_split)==0)
- goto error;
- #ifdef SFM_ONE_LOCK
- if (lock_init(&qm->lock)==0){
- lock_destroy(&qm->get_and_split);
- goto error;
- }
- for (r=0; r<SFM_POOLS_NO; r++){
- if (lock_init(&qm->pool[r].lock)==0){
- for (;r>0; r--) lock_destroy(&qm->pool[r-1].lock);
- lock_destroy(&qm->lock);
- lock_destroy(&qm->get_and_split);
- goto error;
- }
- }
- #elif defined(SFM_LOCK_PER_BUCKET)
- for (r=0; r<SF_HASH_SIZE; r++)
- if (lock_init(&qm->free_hash[r].lock)==0){
- for(;r>0; r--) lock_destroy(&qm->free_hash[r-1].lock);
- lock_destroy(&qm->get_and_split);
- goto error;
- }
- for (i=0; i<SFM_POOLS_NO; i++){
- for (r=0; r<SF_HASH_POOL_SIZE; r++)
- if (lock_init(&qm->pool[i].pool_hash[r].lock)==0){
- for(;r>0; r--) lock_destroy(&qm->pool[i].poo_hash[r].lock);
- for(; i>0; i--){
- for (r=0; r<SF_HASH_POOL_SIZE; r++)
- lock_destroy(&qm->pool[i].pool_hash[r].lock);
- }
- for (r=0; r<SF_HASH_SIZE; r++)
- lock_destroy(&qm->free_hash[r].lock);
- lock_destroy(&qm->get_and_split);
- goto error;
- }
- }
- #endif
- qm->is_init=1;
- return qm;
- error:
- return 0;
- }
- /* cleanup */
- void sfm_malloc_destroy(struct sfm_block* qm)
- {
- int r, i;
- /* destroy all the locks */
- if (!qm || !qm->is_init)
- return; /* nothing to do */
- lock_destroy(&qm->get_and_split);
- #ifdef SFM_ONE_LOCK
- lock_destroy(&qm->lock);
- for (r=0; r<SFM_POOLS_NO; r++){
- lock_destroy(&qm->pool[r].lock);
- }
- #elif defined(SFM_LOCK_PER_BUCKET)
- for (r=0; r<SF_HASH_SIZE; r++)
- lock_destroy(&qm->free_hash[r].lock);
- for (i=0; i<SFM_POOLS_NO; i++){
- for (r=0; r<SF_HASH_POOL_SIZE; r++)
- lock_destroy(&qm->pool[i].pool_hash[r].lock);
- }
- #endif
- qm->is_init=0;
- }
- /* returns next set bit in bitmap, starts at b
- * if b is set, returns b
- * if not found returns BITMAP_BITS */
- static inline unsigned long _next_set_bit(unsigned long b,
- unsigned long* bitmap)
- {
- for (; !((1UL<<b)& *bitmap) && b<BITMAP_BITS; b++);
- return b;
- }
- /* returns start of block b and sets *end
- * (handles also the "rest" block at the end ) */
- static inline unsigned long _hash_range(unsigned long b, unsigned long* end)
- {
- unsigned long s;
-
- if ((unlikely(b>=BITMAP_BITS))){
- s=BIT_TO_HASH(BITMAP_BITS);
- *end=SF_HASH_POOL_SIZE; /* last, possible rest block */
- }else{
- s=BIT_TO_HASH(b);
- *end=s+BITMAP_BLOCK_SIZE;
- }
- return s;
- }
- #ifdef DBG_F_MALLOC
- static inline struct sfm_frag* pool_get_frag(struct sfm_block* qm,
- struct sfm_pool* pool, int hash, unisgned long size,
- const char* file, const char* func, unsigned int line)
- #else
- static inline struct sfm_frag* pool_get_frag(struct sfm_block* qm,
- struct sfm_pool* pool,
- int hash, unsigned long size)
- #endif
- {
- int r;
- int next_block;
- struct sfm_frag* volatile* f;
- struct sfm_frag* frag;
- unsigned long b;
- unsigned long eob;
- /* special case for r=hash */
- r=hash;
- f=&pool->pool_hash[r].first;
- if (*f==0)
- goto not_found;
- SFM_POOL_LOCK(pool, r);
- if (unlikely(*f==0)){
- SFM_POOL_UNLOCK(pool, r);
- goto not_found;
- }
- found:
- /* detach it from the free list*/
- frag=frag_pop((struct sfm_frag**)f);
- frag->u.nxt_free=0; /* mark it as 'taken' */
- frag->id=pool_id;
- pool->pool_hash[r].no--;
- SFM_POOL_UNLOCK(pool, r);
- #ifdef DBG_F_MALLOC
- sfm_split_frag(qm, frag, size, file, func, line);
- #else
- sfm_split_frag(qm, frag, size);
- #endif
- if (&qm->pool[pool_id]==pool)
- atomic_inc_long((long*)&pool->hits);
- return frag;
-
- not_found:
- atomic_inc_long((long*)&pool->pool_hash[r].misses);
- r++;
- b=HASH_BIT_POS(r);
-
- while(r<SF_HASH_POOL_SIZE){
- b=_next_set_bit(b, &pool->bitmap);
- next_block=_hash_range(b, &eob);
- r=(r<next_block)?next_block:r;
- for (; r<eob; r++){
- f=&pool->pool_hash[r].first;
- if (*f){
- SFM_POOL_LOCK(pool, r);
- if (unlikely(*f==0)){
- /* not found */
- SFM_POOL_UNLOCK(pool, r);
- }else
- goto found;
- }
- atomic_inc_long((long*)&pool->pool_hash[r].misses);
- }
- b++;
- }
- #if 0 /* EXPENSIVE BUG CHECK */
- for (r=hash; r<SF_HASH_POOL_SIZE; r++){
- f=&pool->pool_hash[r].first;
- if (*f){
- SFM_POOL_LOCK(pool, r);
- if (unlikely(*f==0)){
- /* not found */
- SFM_POOL_UNLOCK(pool, r);
- }else{
- b=_next_set_bit(HASH_BIT_POS(r), &pool->bitmap);
- next_block=_hash_range(b, &eob);
- BUG("pool_get_frag: found fragm. %d at %d (bit %ld range %ld-%ld), next set bit=%ld"
- " bitmap %ld (%p)\n", hash, r, HASH_BIT_POS(r),
- next_block, eob, b, pool->bitmap, &pool->bitmap);
- goto found;
- }
- }
- }
- #endif
- atomic_inc_long((long*)&pool->missed);
- return 0;
- }
- #ifdef DBG_F_MALLOC
- static inline struct sfm_frag* main_get_frag(struct sfm_block* qm, int hash,
- unsigned long size,
- const char* file, const char* func, unsigned int line)
- #else
- static inline struct sfm_frag* main_get_frag(struct sfm_block* qm, int hash,
- unsigned long size)
- #endif
- {
- int r;
- int next_block;
- struct sfm_frag* volatile* f;
- struct sfm_frag* frag;
- unsigned long b;
- unsigned long eob;
- r=hash;
- b=HASH_BIT_POS(r);
- while(r<=SF_MALLOC_OPTIMIZE/SF_ROUNDTO){
- b=_next_set_bit(b, &qm->bitmap);
- next_block=_hash_range(b, &eob);
- r=(r<next_block)?next_block:r;
- for (; r<eob; r++){
- f=&qm->free_hash[r].first;
- if (*f){
- SFM_MAIN_HASH_LOCK(qm, r);
- if (unlikely(*f==0)){
- /* not found, somebody stole it */
- SFM_MAIN_HASH_UNLOCK(qm, r);
- continue;
- }
- /* detach it from the free list*/
- frag=frag_pop((struct sfm_frag**)f);
- frag->u.nxt_free=0; /* mark it as 'taken' */
- qm->free_hash[r].no--;
- SFM_MAIN_HASH_UNLOCK(qm, r);
- frag->id=pool_id;
- #ifdef DBG_F_MALLOC
- sfm_split_frag(qm, frag, size, file, func, line);
- #else
- sfm_split_frag(qm, frag, size);
- #endif
- return frag;
- }
- }
- b++;
- }
- /* big fragments */
- SFM_BIG_GET_AND_SPLIT_LOCK(qm);
- for (; r<= sfm_max_hash ; r++){
- f=&qm->free_hash[r].first;
- if (*f){
- SFM_MAIN_HASH_LOCK(qm, r);
- if (unlikely((*f)==0)){
- /* not found */
- SFM_MAIN_HASH_UNLOCK(qm, r);
- continue;
- }
- for(;(*f); f=&((*f)->u.nxt_free))
- if ((*f)->size>=size){
- /* found, detach it from the free list*/
- frag=*f;
- *f=frag->u.nxt_free;
- frag->u.nxt_free=0; /* mark it as 'taken' */
- qm->free_hash[r].no--;
- SFM_MAIN_HASH_UNLOCK(qm, r);
- frag->id=pool_id;
- #ifdef DBG_F_MALLOC
- sfm_split_frag(qm, frag, size, file, func, line);
- #else
- sfm_split_frag(qm, frag, size);
- #endif
- SFM_BIG_GET_AND_SPLIT_UNLOCK(qm);
- return frag;
- };
- SFM_MAIN_HASH_UNLOCK(qm, r);
- /* try in a bigger bucket */
- }
- }
- SFM_BIG_GET_AND_SPLIT_UNLOCK(qm);
- return 0;
- }
- #ifdef DBG_F_MALLOC
- void* sfm_malloc(struct sfm_block* qm, unsigned long size,
- const char* file, const char* func, unsigned int line)
- #else
- void* sfm_malloc(struct sfm_block* qm, unsigned long size)
- #endif
- {
- struct sfm_frag* frag;
- int hash;
- unsigned int i;
-
- #ifdef DBG_F_MALLOC
- MDBG("sfm_malloc(%p, %lu) called from %s: %s(%d)\n", qm, size, file, func,
- line);
- #endif
- /*size must be a multiple of 8*/
- size=ROUNDUP(size);
- /* if (size>(qm->size-qm->real_used)) return 0; */
- /* check if our pool id is set */
- sfm_fix_pool_id(qm);
-
- /*search for a suitable free frag*/
- if (likely(size<=SF_POOL_MAX_SIZE)){
- hash=GET_SMALL_HASH(size);
- /* try first in our pool */
- #ifdef DBG_F_MALLOC
- if (likely((frag=pool_get_frag(qm, &qm->pool[pool_id], hash, size,
- file, func, line))!=0))
- goto found;
- /* try in the "main" free hash, go through all the hash */
- if (likely((frag=main_get_frag(qm, hash, size, file, func, line))!=0))
- goto found;
- /* really low mem , try in other pools */
- for (i=(pool_id+1); i< (pool_id+SFM_POOLS_NO); i++){
- if ((frag=pool_get_frag(qm, &qm->pool[i%SFM_POOLS_NO], hash, size,
- file, func, line))!=0)
- goto found;
- }
- #else
- if (likely((frag=pool_get_frag(qm, &qm->pool[pool_id], hash, size))
- !=0 ))
- goto found;
- /* try in the "main" free hash, go through all the hash */
- if (likely((frag=main_get_frag(qm, hash, size))!=0))
- goto found;
- /* really low mem , try in other pools */
- for (i=(pool_id+1); i< (pool_id+SFM_POOLS_NO); i++){
- if ((frag=pool_get_frag(qm, &qm->pool[i%SFM_POOLS_NO], hash, size))
- !=0 )
- goto found;
- }
- #endif
- /* not found, bad! */
- return 0;
- }else{
- hash=GET_BIG_HASH(size);
- #ifdef DBG_F_MALLOC
- if ((frag=main_get_frag(qm, hash, size, file, func, line))==0)
- return 0; /* not found, bad! */
- #else
- if ((frag=main_get_frag(qm, hash, size))==0)
- return 0; /* not found, bad! */
- #endif
- }
- found:
- /* we found it!*/
- #ifdef DBG_F_MALLOC
- frag->file=file;
- frag->func=func;
- frag->line=line;
- frag->check=ST_CHECK_PATTERN;
- MDBG("sfm_malloc(%p, %lu) returns address %p \n", qm, size,
- (char*)frag+sizeof(struct sfm_frag));
- #endif
- FRAG_MARK_USED(frag); /* mark it as used */
- return (char*)frag+sizeof(struct sfm_frag);
- }
- #ifdef DBG_F_MALLOC
- void sfm_free(struct sfm_block* qm, void* p, const char* file,
- const char* func, unsigned int line)
- #else
- void sfm_free(struct sfm_block* qm, void* p)
- #endif
- {
- struct sfm_frag* f;
- #ifdef DBG_F_MALLOC
- MDBG("sfm_free(%p, %p), called from %s: %s(%d)\n", qm, p, file, func,
- line);
- if (p>(void*)qm->last_frag || p<(void*)qm->first_frag){
- LOG(L_CRIT, "BUG: sfm_free: bad pointer %p (out of memory block!) - "
- "aborting\n", p);
- abort();
- }
- #endif
- if (unlikely(p==0)) {
- LOG(L_WARN, "WARNING: sfm_free: free(0) called\n");
- return;
- }
- f=(struct sfm_frag*) ((char*)p-sizeof(struct sfm_frag));
- #ifdef DBG_F_MALLOC
- MDBG("sfm_free: freeing block alloc'ed from %s: %s(%ld)\n",
- f->file, f->func, f->line);
- #endif
- #ifdef DBG_F_MALLOC
- f->file=file;
- f->func=func;
- f->line=line;
- #endif
- sfm_insert_free(qm, f, 0);
- }
- #ifdef DBG_F_MALLOC
- void* sfm_realloc(struct sfm_block* qm, void* p, unsigned long size,
- const char* file, const char* func, unsigned int line)
- #else
- void* sfm_realloc(struct sfm_block* qm, void* p, unsigned long size)
- #endif
- {
- struct sfm_frag *f;
- unsigned long orig_size;
- void *ptr;
- #ifndef SFM_REALLOC_REMALLOC
- struct sfm_frag *n;
- struct sfm_frag **pf;
- unsigned long diff;
- unsigned long p_id;
- int hash;
- unsigned long n_size;
- struct sfm_pool * pool;
- #endif
-
- #ifdef DBG_F_MALLOC
- MDBG("sfm_realloc(%p, %p, %lu) called from %s: %s(%d)\n", qm, p, size,
- file, func, line);
- if ((p)&&(p>(void*)qm->last_frag || p<(void*)qm->first_frag)){
- LOG(L_CRIT, "BUG: sfm_free: bad pointer %p (out of memory block!) - "
- "aborting\n", p);
- abort();
- }
- #endif
- if (size==0) {
- if (p)
- #ifdef DBG_F_MALLOC
- sfm_free(qm, p, file, func, line);
- #else
- sfm_free(qm, p);
- #endif
- return 0;
- }
- if (p==0)
- #ifdef DBG_F_MALLOC
- return sfm_malloc(qm, size, file, func, line);
- #else
- return sfm_malloc(qm, size);
- #endif
- f=(struct sfm_frag*) ((char*)p-sizeof(struct sfm_frag));
- #ifdef DBG_F_MALLOC
- MDBG("sfm_realloc: realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
- f, f->file, f->func, f->line);
- #endif
- size=ROUNDUP(size);
- orig_size=f->size;
- if (f->size > size){
- /* shrink */
- #ifdef DBG_F_MALLOC
- MDBG("sfm_realloc: shrinking from %lu to %lu\n", f->size, size);
- sfm_split_frag(qm, f, size, file, "frag. from sfm_realloc", line);
- #else
- sfm_split_frag(qm, f, size);
- #endif
- }else if (f->size<size){
- /* grow */
- #ifdef DBG_F_MALLOC
- MDBG("sfm_realloc: growing from %lu to %lu\n", f->size, size);
- #endif
- #ifndef SFM_REALLOC_REMALLOC
- diff=size-f->size;
- n=FRAG_NEXT(f);
- if (((char*)n < (char*)qm->last_frag) &&
- (n->u.nxt_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
- /* join */
- /* detach n from the free list */
- try_again:
- p_id=n->id;
- n_size=n->size;
- if ((unlikely(p_id >=SFM_POOLS_NO))){
- hash=GET_HASH(n_size);
- SFM_MAIN_HASH_LOCK(qm, hash);
- if (unlikely((n->u.nxt_free==0) ||
- ((n->size+FRAG_OVERHEAD)<diff))){
- SFM_MAIN_HASH_UNLOCK(qm, hash);
- goto not_found;
- }
- if (unlikely((n->id!=p_id) || (n->size!=n_size))){
- /* fragment still free, but changed, either
- * moved to another pool or has a diff. size */
- SFM_MAIN_HASH_UNLOCK(qm, hash);
- goto try_again;
- }
- pf=&(qm->free_hash[hash].first);
- /* find it */
- for(;(*pf)&&(*pf!=n); pf=&((*pf)->u.nxt_free));/*FIXME slow */
- if (*pf==0){
- SFM_MAIN_HASH_UNLOCK(qm, hash);
- /* not found, bad! */
- LOG(L_WARN, "WARNING: sfm_realloc: could not find %p in "
- "free " "list (hash=%d)\n", n, hash);
- /* somebody is in the process of changing it ? */
- goto not_found;
- }
- /* detach */
- *pf=n->u.nxt_free;
- n->u.nxt_free=0; /* mark it immediately as detached */
- qm->free_hash[hash].no--;
- SFM_MAIN_HASH_UNLOCK(qm, hash);
- /* join */
- f->size+=n->size+FRAG_OVERHEAD;
- /* split it if necessary */
- if (f->size > size){
- #ifdef DBG_F_MALLOC
- sfm_split_frag(qm, f, size, file, "fragm. from "
- "sfm_realloc", line);
- #else
- sfm_split_frag(qm, f, size);
- #endif
- }
- }else{ /* p_id < SFM_POOLS_NO (=> in a pool )*/
- hash=GET_SMALL_HASH(n_size);
- pool=&qm->pool[p_id];
- SFM_POOL_LOCK(pool, hash);
- if (unlikely((n->u.nxt_free==0) ||
- ((n->size+FRAG_OVERHEAD)<diff))){
- SFM_POOL_UNLOCK(pool, hash);
- goto not_found;
- }
- if (unlikely((n->id!=p_id) || (n->size!=n_size))){
- /* fragment still free, but changed, either
- * moved to another pool or has a diff. size */
- SFM_POOL_UNLOCK(pool, hash);
- goto try_again;
- }
- pf=&(pool->pool_hash[hash].first);
- /* find it */
- for(;(*pf)&&(*pf!=n); pf=&((*pf)->u.nxt_free));/*FIXME slow */
- if (*pf==0){
- SFM_POOL_UNLOCK(pool, hash);
- /* not found, bad! */
- LOG(L_WARN, "WARNING: sfm_realloc: could not find %p in "
- "free " "list (hash=%d)\n", n, hash);
- /* somebody is in the process of changing it ? */
- goto not_found;
- }
- /* detach */
- *pf=n->u.nxt_free;
- n->u.nxt_free=0; /* mark it immediately as detached */
- pool->pool_hash[hash].no--;
- SFM_POOL_UNLOCK(pool, hash);
- /* join */
- f->size+=n->size+FRAG_OVERHEAD;
- /* split it if necessary */
- if (f->size > size){
- #ifdef DBG_F_MALLOC
- sfm_split_frag(qm, f, size, file, "fragm. from "
- "sfm_realloc", line);
- #else
- sfm_split_frag(qm, f, size);
- #endif
- }
- }
- }else{
- not_found:
- /* could not join => realloc */
- #else/* SFM_REALLOC_REMALLOC */
- {
- #endif /* SFM_REALLOC_REMALLOC */
- #ifdef DBG_F_MALLOC
- ptr=sfm_malloc(qm, size, file, func, line);
- #else
- ptr=sfm_malloc(qm, size);
- #endif
- if (ptr){
- /* copy, need by libssl */
- memcpy(ptr, p, orig_size);
- #ifdef DBG_F_MALLOC
- sfm_free(qm, p, file, func, line);
- #else
- sfm_free(qm, p);
- #endif
- }
- p=ptr;
- }
- }else{
- /* do nothing */
- #ifdef DBG_F_MALLOC
- MDBG("sfm_realloc: doing nothing, same size: %lu - %lu\n",
- f->size, size);
- #endif
- }
- #ifdef DBG_F_MALLOC
- MDBG("sfm_realloc: returning %p\n", p);
- #endif
- return p;
- }
- void sfm_status(struct sfm_block* qm)
- {
- struct sfm_frag* f;
- int i,j;
- int h;
- int unused;
- unsigned long size;
- int k;
- int memlog;
- memlog=cfg_get(core, core_cfg, memlog);
- LOG(memlog, "sfm_status (%p):\n", qm);
- if (!qm) return;
- LOG(memlog, " heap size= %ld\n", qm->size);
- LOG(memlog, "dumping free list:\n");
- for(h=0,i=0,size=0;h<=sfm_max_hash;h++){
- SFM_MAIN_HASH_LOCK(qm, h);
- unused=0;
- for (f=qm->free_hash[h].first,j=0; f;
- size+=f->size,f=f->u.nxt_free,i++,j++){
- if (!FRAG_WAS_USED(f)){
- unused++;
- #ifdef DBG_F_MALLOC
- LOG(memlog, "unused fragm.: hash = %3d, fragment %p,"
- " address %p size %lu, created from %s: %s(%ld)\n",
- h, f, (char*)f+sizeof(struct sfm_frag), f->size,
- f->file, f->func, f->line);
- #endif
- };
- }
- if (j) LOG(memlog, "hash = %3d fragments no.: %5d, unused: %5d\n\t\t"
- " bucket size: %9lu - %9lu (first %9lu)\n",
- h, j, unused, UN_HASH(h),
- ((h<=SF_MALLOC_OPTIMIZE/SF_ROUNDTO)?1:2)* UN_HASH(h),
- qm->free_hash[h].first->size
- );
- if (j!=qm->free_hash[h].no){
- LOG(L_CRIT, "BUG: sfm_status: different free frag. count: %d!=%ld"
- " for hash %3d\n", j, qm->free_hash[h].no, h);
- }
- SFM_MAIN_HASH_UNLOCK(qm, h);
- }
- for (k=0; k<SFM_POOLS_NO; k++){
- for(h=0;h<SF_HASH_POOL_SIZE;h++){
- SFM_POOL_LOCK(&qm->pool[k], h);
- unused=0;
- for (f=qm->pool[k].pool_hash[h].first,j=0; f;
- size+=f->size,f=f->u.nxt_free,i++,j++){
- if (!FRAG_WAS_USED(f)){
- unused++;
- #ifdef DBG_F_MALLOC
- LOG(memlog, "[%2d] unused fragm.: hash = %3d, fragment %p,"
- " address %p size %lu, created from %s: "
- "%s(%ld)\n", k
- h, f, (char*)f+sizeof(struct sfm_frag),
- f->size, f->file, f->func, f->line);
- #endif
- };
- }
- if (j) LOG(memlog, "[%2d] hash = %3d fragments no.: %5d, unused: "
- "%5d\n\t\t bucket size: %9lu - %9lu "
- "(first %9lu)\n",
- k, h, j, unused, UN_HASH(h),
- ((h<=SF_MALLOC_OPTIMIZE/SF_ROUNDTO)?1:2) *
- UN_HASH(h),
- qm->pool[k].pool_hash[h].first->size
- );
- if (j!=qm->pool[k].pool_hash[h].no){
- LOG(L_CRIT, "BUG: sfm_status: [%d] different free frag."
- " count: %d!=%ld for hash %3d\n",
- k, j, qm->pool[k].pool_hash[h].no, h);
- }
- SFM_POOL_UNLOCK(&qm->pool[k], h);
- }
- }
- LOG(memlog, "TOTAL: %6d free fragments = %6lu free bytes\n", i, size);
- LOG(memlog, "-----------------------------\n");
- }
- /* fills a malloc info structure with info about the block
- * if a parameter is not supported, it will be filled with 0 */
- void sfm_info(struct sfm_block* qm, struct mem_info* info)
- {
- int r, k;
- unsigned long total_frags;
- struct sfm_frag* f;
-
- memset(info,0, sizeof(*info));
- total_frags=0;
- info->total_size=qm->size;
- info->min_frag=SF_MIN_FRAG_SIZE;
- /* we'll have to compute it all */
- for (r=0; r<=SF_MALLOC_OPTIMIZE/SF_ROUNDTO; r++){
- info->free+=qm->free_hash[r].no*UN_HASH(r);
- total_frags+=qm->free_hash[r].no;
- }
- for(;r<=sfm_max_hash; r++){
- total_frags+=qm->free_hash[r].no;
- SFM_MAIN_HASH_LOCK(qm, r);
- for(f=qm->free_hash[r].first;f;f=f->u.nxt_free){
- info->free+=f->size;
- }
- SFM_MAIN_HASH_UNLOCK(qm, r);
- }
- for (k=0; k<SFM_POOLS_NO; k++){
- for (r=0; r<SF_HASH_POOL_SIZE; r++){
- info->free+=qm->pool[k].pool_hash[r].no*UN_HASH(r);
- total_frags+=qm->pool[k].pool_hash[r].no;
- }
- }
- info->real_used=info->total_size-info->free;
- info->used=info->real_used-total_frags*FRAG_OVERHEAD-INIT_OVERHEAD
- -FRAG_OVERHEAD;
- info->max_used=0; /* we don't really know */
- info->total_frags=total_frags;
- }
- /* returns how much free memory is available
- * on error (not compiled with bookkeeping code) returns (unsigned long)(-1) */
- unsigned long sfm_available(struct sfm_block* qm)
- {
- /* we don't know how much free memory we have and it's to expensive
- * to compute it */
- return ((unsigned long)-1);
- }
- #endif
|