void fm_free(struct fm_block* qm, void* p) #endif { struct fm_frag* f,*n; #ifdef DBG_F_MALLOC LM_DBG("params(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line); if (p>(void*)qm->last_frag || p<(void*)qm->first_frag){ LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p); abort(); } #endif if (p==0) { LM_DBG("free(0) called\n"); return; } f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag)); #ifdef DBG_F_MALLOC LM_DBG("freeing block alloc'ed from %s: %s(%ld)\n", f->file, f->func, f->line); f->file=file; f->func=func; f->line=line; #endif join: if( qm->large_limit < qm->large_space ) goto no_join; n = FRAG_NEXT(f); if (((char*)n < (char*)qm->last_frag) && n->prev ) { fm_remove_free(qm, n); /* join */ f->size += n->size + FRAG_OVERHEAD; #if defined(DBG_F_MALLOC) || defined(STATISTICS) //qm->real_used -= FRAG_OVERHEAD; qm->used += FRAG_OVERHEAD; #endif goto join; } no_join: fm_insert_free(qm, f); #if defined(DBG_F_MALLOC) || defined(STATISTICS) qm->fragments -= 1; #endif pkg_threshold_check(); }
void* fm_malloc(struct fm_block* qm, unsigned long size) #endif { struct fm_frag* frag,*n; unsigned int hash; #ifdef DBG_F_MALLOC LM_DBG("params (%p, %lu), called from %s: %s(%d)\n", qm, size, file, func, line); #endif /*size must be a multiple of 8*/ size=ROUNDUP(size); /*search for a suitable free frag*/ for(hash=GET_HASH(size);hash<F_HASH_SIZE;hash++){ frag=qm->free_hash[hash].first; for( ; frag; frag = frag->u.nxt_free ) if ( frag->size >= size ) goto found; /* try in a bigger bucket */ } /* not found, bad! */ LM_WARN("Not enough free memory, will atempt defragmenation\n"); for( frag = qm->first_frag; (char*)frag < (char*)qm->last_frag; ) { n = FRAG_NEXT(frag); if ( ((char*)n < (char*)qm->last_frag) && n->prev && frag->prev ) { /* detach frag*/ fm_remove_free(qm, frag); do { fm_remove_free(qm, n); frag->size += n->size + FRAG_OVERHEAD; #if defined(DBG_F_MALLOC) || defined(STATISTICS) //qm->real_used -= FRAG_OVERHEAD; qm->used += FRAG_OVERHEAD; #endif if( frag->size >size ) goto solved; n = FRAG_NEXT(frag); } while ( ((char*)n < (char*)qm->last_frag) && n->prev); fm_insert_free(qm,frag); } frag = n; } pkg_threshold_check(); return 0; found: /* we found it!*/ fm_remove_free(qm,frag); /*see if we'll use full frag, or we'll split it in 2*/ #ifdef DBG_F_MALLOC fm_split_frag(qm, frag, size, file, func, line); frag->file=file; frag->func=func; frag->line=line; frag->check=ST_CHECK_PATTERN; LM_DBG("params(%p, %lu), returns address %p \n", qm, size, (char*)frag+sizeof(struct fm_frag)); #else fm_split_frag(qm, frag, size); #endif solved: #if defined(DBG_F_MALLOC) || defined(STATISTICS) if (qm->max_real_used<qm->real_used) qm->max_real_used=qm->real_used; #endif pkg_threshold_check(); return (char*)frag+sizeof(struct fm_frag); }
void fm_split_frag(struct fm_block* qm, struct fm_frag* frag, unsigned long size) #endif { unsigned long rest; struct fm_frag* n; rest=frag->size-size; #ifdef MEM_FRAG_AVOIDANCE if ((rest> (FRAG_OVERHEAD+F_MALLOC_OPTIMIZE))|| (rest>=(FRAG_OVERHEAD+size))){ /* the residue fragm. is big enough*/ #else if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){ #endif frag->size=size; /*split the fragment*/ n=FRAG_NEXT(frag); n->size=rest-FRAG_OVERHEAD; /* * The real used memory does not increase, as the frag memory is not * freed from real_used. On the other hand, the used size should * decrease, because the new fragment is not "useful data" - razvanc #if defined(DBG_F_MALLOC) || defined(STATISTICS) qm->real_used+=FRAG_OVERHEAD; #endif */ #if defined(DBG_F_MALLOC) || defined(STATISTICS) qm->used-=FRAG_OVERHEAD; #endif #ifdef DBG_F_MALLOC /* frag created by malloc, mark it*/ n->file=file; n->func="frag. from fm_malloc"; n->line=line; n->check=ST_CHECK_PATTERN; #endif /* reinsert n in free list*/ fm_insert_free(qm, n); }else{ /* we cannot split this fragment any more => alloc all of it*/ } } /* init malloc and return a fm_block*/ struct fm_block* fm_malloc_init(char* address, unsigned long size) { char* start; char* end; struct fm_block* qm; unsigned long init_overhead; /* make address and size multiple of 8*/ start=(char*)ROUNDUP((unsigned long) address); LM_DBG("F_OPTIMIZE=%lu, /ROUNDTO=%lu\n", F_MALLOC_OPTIMIZE, F_MALLOC_OPTIMIZE/ROUNDTO); LM_DBG("F_HASH_SIZE=%lu, fm_block size=%lu\n", F_HASH_SIZE, (long)sizeof(struct fm_block)); LM_DBG("params (%p, %lu), start=%p\n", address, size, start); if (size<(unsigned long)(start-address)) return 0; size-=(start-address); if (size <(MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0; size=ROUNDDOWN(size); init_overhead=(ROUNDUP(sizeof(struct fm_block))+ 2 * FRAG_OVERHEAD); if (size < init_overhead) { /* not enough mem to create our control structures !!!*/ return 0; } end=start+size; qm=(struct fm_block*)start; memset(qm, 0, sizeof(struct fm_block)); qm->size=size; #if defined(DBG_F_MALLOC) || defined(STATISTICS) qm->used=size-init_overhead; qm->real_used=size; qm->max_real_used=init_overhead; #endif qm->first_frag=(struct fm_frag*)(start+ROUNDUP(sizeof(struct fm_block))); qm->last_frag=(struct fm_frag*)(end-sizeof(struct fm_frag)); /* init initial fragment*/ qm->first_frag->size=size-init_overhead; qm->last_frag->size=0; qm->last_frag->prev=NULL; qm->first_frag->prev=NULL; #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*/ qm->large_space = 0; qm->large_limit = qm->size / 100 * F_MALLOC_DEFRAG_PERCENT; if( qm->large_limit < F_MALLOC_DEFRAG_LIMIT ) qm->large_limit = F_MALLOC_DEFRAG_LIMIT; fm_insert_free(qm, qm->first_frag); return qm; }
void* fm_malloc(struct fm_block* qm, unsigned long size) #endif { struct fm_frag* frag,*n; unsigned int hash; #ifdef DBG_MALLOC LM_GEN1(memlog, "%s_malloc(%lu), called from %s: %s(%d)\n", qm->name, size, file, func, line); #endif /*size must be a multiple of 8*/ size=ROUNDUP(size); /*search for a suitable free frag*/ for(hash=GET_HASH(size); hash<F_HASH_SIZE; hash++) { frag=qm->free_hash[hash].first; for( ; frag; frag = frag->u.nxt_free ) if ( frag->size >= size ) goto found; /* try in a bigger bucket */ } /* not found, bad! */ #if defined(DBG_MALLOC) || defined(STATISTICS) LM_ERR(oom_errorf, qm->name, qm->size - qm->real_used, qm->name[0] == 'p' ? "M" : "m"); LM_INFO("attempting defragmentation... (need %lu bytes)\n", size); #else LM_ERR(oom_nostats_errorf, qm->name, qm->name[0] == 'p' ? "M" : "m"); LM_INFO("attempting defragmentation... (need %lu bytes)\n", size); #endif for( frag = qm->first_frag; (char*)frag < (char*)qm->last_frag; ) { n = FRAG_NEXT(frag); if ( ((char*)n < (char*)qm->last_frag) && n->prev && frag->prev ) { /* detach frag*/ fm_remove_free(qm, frag); do { fm_remove_free(qm, n); frag->size += n->size + FRAG_OVERHEAD; #if defined(DBG_MALLOC) || defined(STATISTICS) //qm->real_used -= FRAG_OVERHEAD; qm->used += FRAG_OVERHEAD; #endif if( frag->size >size ) { #ifdef DBG_MALLOC /* mark it as "busy" */ frag->is_free = 0; #endif goto solved; } n = FRAG_NEXT(frag); } while ( ((char*)n < (char*)qm->last_frag) && n->prev); fm_insert_free(qm,frag); } frag = n; } LM_INFO("unable to alloc a big enough fragment!\n"); pkg_threshold_check(); return 0; found: /* we found it!*/ fm_remove_free(qm,frag); #ifdef DBG_MALLOC /* mark it as "busy" */ frag->is_free = 0; #endif /*see if we'll use full frag, or we'll split it in 2*/ #ifdef DBG_MALLOC fm_split_frag(qm, frag, size, file, func, line); frag->file=file; frag->func=func; frag->line=line; frag->check=ST_CHECK_PATTERN; LM_GEN1(memlog, "%s_malloc(%lu), returns address %p\n", qm->name, size, (char*)frag+sizeof(struct fm_frag)); #else fm_split_frag(qm, frag, size); #endif solved: #if defined(DBG_MALLOC) || defined(STATISTICS) if (qm->max_real_used<qm->real_used) qm->max_real_used=qm->real_used; qm->fragments += 1; #endif pkg_threshold_check(); return (char*)frag+sizeof(struct fm_frag); }