Skip to content

Commit

Permalink
core: mem - reworked f_malloc free chunks management
Browse files Browse the repository at this point in the history
- credits to Juha Heinanen for heling with testing

(cherry picked from commit 8cced16)
  • Loading branch information
miconda committed Oct 1, 2015
1 parent efb2a06 commit e10fc9b
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 67 deletions.
102 changes: 43 additions & 59 deletions mem/f_malloc.c
Expand Up @@ -91,7 +91,8 @@
((qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] & (1UL<<((b)%FM_HASH_BMP_BITS)))


#define fm_is_free(f) ((f)->u.nxt_free)
#define fm_is_free(f) ((f)->is_free)

/**
* \brief Find the first free fragment in a memory block
*
Expand Down Expand Up @@ -158,12 +159,10 @@ inline static int fm_bmp_first_set(struct fm_block* qm, int start)
* \name Memory manager boundary check pattern
*/
/*@{ */
#ifdef DBG_F_MALLOC
#define ST_CHECK_PATTERN 0xf0f0f0f0 /** inserted at the beginning */
#define END_CHECK_PATTERN1 0xc0c0c0c0 /** inserted at the end */
#define END_CHECK_PATTERN2 0xabcdefed /** inserted at the end */
/*@} */
#endif


/**
Expand All @@ -177,26 +176,25 @@ static inline void fm_extract_free(struct fm_block* qm, struct fm_frag* frag)

hash = GET_HASH(frag->size);

if(frag->prv_free) {
frag->prv_free->u.nxt_free = frag->u.nxt_free;
if(frag->prev_free) {
frag->prev_free->next_free = frag->next_free;
} else {
if(frag->u.nxt_free!=qm->last_frag)
qm->free_hash[hash].first = frag->u.nxt_free;
else
qm->free_hash[hash].first = NULL;
qm->free_hash[hash].first = frag->next_free;
}
if(frag->u.nxt_free && frag->u.nxt_free!=qm->last_frag) {
frag->u.nxt_free->prv_free = frag->prv_free;
if(frag->next_free) {
frag->next_free->prev_free = frag->prev_free;
}

frag->prev_free = NULL;
frag->next_free = NULL;
frag->is_free = 0;

qm->ffrags--;
qm->free_hash[hash].no--;
#ifdef F_MALLOC_HASH_BITMAP
if (qm->free_hash[hash].no==0)
fm_bmp_reset(qm, hash);
#endif /* F_MALLOC_HASH_BITMAP */
frag->prv_free = NULL;
frag->u.nxt_free = NULL;

qm->real_used+=frag->size;
qm->used+=frag->size;
Expand All @@ -210,55 +208,41 @@ static inline void fm_extract_free(struct fm_block* qm, struct fm_frag* frag)
static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag)
{
struct fm_frag* f;
struct fm_frag* p;
int hash;
int after;

hash=GET_HASH(frag->size);
f=qm->free_hash[hash].first;
p=NULL;
if (frag->size > F_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH,
(different from 0.8.1[24] on
purpose --andrei ) */
after = 0;
/* large fragments list -- add at a position ordered by size */
for(; f; f=f->u.nxt_free){
for(; f; f=f->next_free){
if (frag->size <= f->size) break;
if(f->u.nxt_free==qm->last_frag) {
/*size greater than last frag in slot*/
after = 1;
break;
}
p = f;
}

frag->next_free = f;
frag->prev_free = p;
if(f) {
if(after) {
/*insert frag after f*/
frag->prv_free=f;
f->u.nxt_free=frag;
frag->u.nxt_free = qm->last_frag;
} else {
/*insert frag before f*/
frag->u.nxt_free = f;
frag->prv_free=f->prv_free;
if(f->prv_free) f->prv_free->u.nxt_free = frag;
if(qm->free_hash[hash].first==f) qm->free_hash[hash].first = frag;
}
f->prev_free = frag;
}
if(p) {
p->next_free = frag;
} else {
/* to be only one in slot */
qm->free_hash[hash].first = frag;
frag->prv_free=0;
frag->u.nxt_free = qm->last_frag;
}
} else {
/* fixed fragment size list -- add first */
frag->prv_free=0;
frag->prev_free = 0;
frag->next_free = f;
if(f) {
f->prv_free = frag;
frag->u.nxt_free = f;
} else {
frag->u.nxt_free = qm->last_frag;
f->prev_free = frag;
}
qm->free_hash[hash].first = frag;
}
frag->is_free = 1;
qm->ffrags++;
qm->free_hash[hash].no++;
#ifdef F_MALLOC_HASH_BITMAP
Expand Down Expand Up @@ -307,8 +291,8 @@ void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
n->file=file;
n->func="frag. from fm_split_frag";
n->line=line;
n->check=ST_CHECK_PATTERN;
#endif
n->check=ST_CHECK_PATTERN;
/* reinsert n in free list*/
qm->used-=FRAG_OVERHEAD;
fm_insert_free(qm, n);
Expand Down Expand Up @@ -366,17 +350,17 @@ struct fm_block* fm_malloc_init(char* address, unsigned long size, int type)
qm->last_frag=(struct fm_frag*)(end-sizeof(struct fm_frag));
/* init first fragment*/
qm->first_frag->size=size;
qm->first_frag->prv_free=0;
qm->first_frag->u.nxt_free=0;
qm->first_frag->prev_free=0;
qm->first_frag->next_free=0;
qm->first_frag->is_free=0;
/* init last fragment*/
qm->last_frag->size=0;
qm->last_frag->prv_free=0;
qm->last_frag->u.nxt_free=0;
qm->last_frag->prev_free=0;
qm->last_frag->next_free=0;
qm->last_frag->is_free=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*/

Expand Down Expand Up @@ -441,7 +425,7 @@ void* fm_malloc(struct fm_block* qm, unsigned long size,
void* fm_malloc(struct fm_block* qm, unsigned long size)
#endif
{
struct fm_frag** f;
struct fm_frag* f;
struct fm_frag* frag;
int hash;

Expand All @@ -460,8 +444,8 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
hash=fm_bmp_first_set(qm, GET_HASH(size));
if (likely(hash>=0)){
if (likely(hash<=F_MALLOC_OPTIMIZE/ROUNDTO)) { /* return first match */
f=&(qm->free_hash[hash].first);
if(likely(*f)) goto found;
f=qm->free_hash[hash].first;
if(likely(f)) goto found;
#ifdef DBG_F_MALLOC
MDBG(" block %p hash %d empty but no. is %lu\n", qm,
hash, qm->free_hash[hash].no);
Expand All @@ -479,17 +463,17 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
hash buckets.
*/
do {
for(f=&(qm->free_hash[hash].first);(*f); f=&((*f)->u.nxt_free))
if ((*f)->size>=size) goto found;
for(f=qm->free_hash[hash].first; f; f=f->next_free)
if (f->size>=size) goto found;
hash++; /* try in next hash cell */
}while((hash < F_HASH_SIZE) &&
((hash=fm_bmp_first_set(qm, hash)) >= 0));
}
#else /* F_MALLOC_HASH_BITMAP */
for(hash=GET_HASH(size);hash<F_HASH_SIZE;hash++){
f=&(qm->free_hash[hash].first);
for(;(*f); f=&((*f)->u.nxt_free))
if ((*f)->size>=size) goto found;
f=qm->free_hash[hash].first;
for(; f; f=f->u.nxt_free)
if (f->size>=size) goto found;
/* try in a bigger bucket */
}
#endif /* F_MALLOC_HASH_BITMAP */
Expand All @@ -504,7 +488,7 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
found:
/* we found it!*/
/* detach it from the free list*/
frag=*f;
frag=f;
fm_extract_free(qm, frag);

/*see if use full frag or split it in two*/
Expand All @@ -520,10 +504,10 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
frag->file=file;
frag->func=func;
frag->line=line;
frag->check=ST_CHECK_PATTERN;
MDBG("fm_malloc(%p, %lu) returns address %p \n", qm, size,
(char*)frag+sizeof(struct fm_frag));
#endif
frag->check=ST_CHECK_PATTERN;

if (qm->max_real_used<qm->real_used)
qm->max_real_used=qm->real_used;
Expand Down Expand Up @@ -792,7 +776,7 @@ void fm_status(struct fm_block* qm)
for(h=0,i=0,size=0;h<F_HASH_SIZE;h++){
unused=0;
for (f=qm->free_hash[h].first,j=0; f;
size+=f->size,f=f->u.nxt_free,i++,j++){
size+=f->size,f=f->next_free,i++,j++){
if (!FRAG_WAS_USED(f)){
unused++;
#ifdef DBG_F_MALLOC
Expand Down
13 changes: 5 additions & 8 deletions mem/f_malloc.h
Expand Up @@ -80,19 +80,16 @@ typedef unsigned long fm_hash_bitmap_t;
* - +1 .... end - size = 2^k, big buckets
*/
struct fm_frag{
unsigned long size; /* size of fragment */
union{
struct fm_frag* nxt_free; /* next free frag in slot, last poitns to qm last_frag,
used to detect if fragment is free (when not null) */
long reserved;
}u;
struct fm_frag* prv_free; /* prev free frag in slot - for faster join/defrag */
unsigned long size; /* size of fragment */
struct fm_frag* next_free; /* next free frag in slot */
struct fm_frag* prev_free; /* prev free frag in slot - for faster join/defrag */
unsigned int is_free; /* used to detect if fragment is free (when not 0) */
#ifdef DBG_F_MALLOC
const char* file;
const char* func;
unsigned long line;
unsigned long check;
#endif
unsigned int check;
};

struct fm_frag_lnk{
Expand Down

0 comments on commit e10fc9b

Please sign in to comment.