/* * Free memory block */ LOCAL ER rel_blk( MPLCB *mplcb, void *blk ) { QUEUE *aq; aq = (QUEUE*)blk - 1; #if CHK_PAR if ( !chkAreaFlag(aq, AREA_USE) ) { return E_PAR; } #endif clrAreaFlag(aq, AREA_USE); if ( !chkAreaFlag(aq->next, AREA_USE) ) { /* Merge to the next area */ removeFreeQue(aq->next + 1); removeAreaQue(aq->next); } if ( !chkAreaFlag(aq->prev, AREA_USE) ) { /* Merge to the previous area */ aq = aq->prev; removeFreeQue(aq + 1); removeAreaQue(aq->next); } /* Register free area onto FreeQue */ appendFreeArea(mplcb, aq); return E_OK; }
/* * Get memory block * 'blksz' must be larger than minimum fragment size * and adjusted by ROUNDSZ unit. */ LOCAL void* get_blk( MPLCB *mplcb, INT blksz ) { QUEUE *q, *aq; /* Search FreeQue */ q = searchFreeArea(mplcb, blksz); if ( q == &mplcb->freeque ) { return NULL; } /* remove free area from FreeQue */ removeFreeQue(q); aq = q - 1; /* If there is a fragment smaller than the minimum fragment size, allocate them together */ if ( AreaSize(aq) - (UINT)blksz >= MIN_FRAGMENT + sizeof(QUEUE) ) { /* Divide the area into 2. */ q = (QUEUE*)((VB*)(aq + 1) + blksz); insertAreaQue(aq, q); /* Register the remaining area onto FreeQue */ appendFreeArea(mplcb, q); } setAreaFlag(aq, AREA_USE); return (void*)(aq + 1); }
/* * Free memory * It may be called during interrupt disable. In this case, need to wait * until interrupt is enabled and until free. */ LOCAL void ifree( void *ptr, IMACB *imacb ) { QUEUE *aq; UW imask; DI(imask); /* Exclusive control by interrupt disable */ SpinLock(&MemLockObj); aq = (QUEUE*)ptr - 1; clrAreaFlag(aq, AREA_USE); if ( !chkAreaFlag(aq->next, AREA_END|AREA_USE) ) { /* Merge with free area in after location */ removeFreeQue(aq->next + 1); removeAreaQue(aq->next); } if ( !chkAreaFlag(aq, AREA_TOP) && !chkAreaFlag(aq->prev, AREA_USE) ) { /* Merge with free area in front location */ aq = aq->prev; removeFreeQue(aq + 1); removeAreaQue(aq->next); } /* If the whole page is free, then free the page. * However, do not free the page if it is called during * interrupt disabled. */ if ( !isDI(imask) && chkAreaFlag(aq, AREA_TOP) && chkAreaFlag(aq->next, AREA_END) ) { /* Free pages */ removeAreaQue(aq->next); removeAreaQue(aq); SpinUnlock(&MemLockObj); EI(imask); RelSysMemBlk(aq); DI(imask); SpinLock(&MemLockObj); } else { /* Register free area to FreeQue */ appendFreeArea(aq, imacb); } SpinUnlock(&MemLockObj); EI(imask); }
/* * Fragment and allocate */ static void *allocate( LIST *aq, RAW_U32 size, MACB *_macb ) { LIST *q; /* Any fragments smaller than the minimum fragment size will also be allocated together */ if ( (RAW_U32)AreaSize(aq) - size >= MIN_FRAGMENT + sizeof(LIST ) ) { /* Divide area in half */ q = (LIST *)((RAW_S8 *)(aq + 1) + size); insertAreaQue(aq, q); /* Register surplus area in free queue */ appendFreeArea(q, _macb); } setAreaFlag(aq, AREA_USE); return (void*)(aq + 1); }
/* * Subdivide and allocate */ Inline VP mem_alloc( QUEUE *aq, size_t blksz, IMACB *imacb ) { QUEUE *q; /* If there are fragments smaller than the minimum fragment size, allocate them also */ if ( (AreaSize(aq) - blksz) >= (MIN_FRAGMENT + sizeof(QUEUE)) ) { /* Divide area into 2 */ q = (QUEUE*)((VB*)(aq + 1) + blksz); insertAreaQue(aq, q); /* Register remaining area to FreeQue */ appendFreeArea(q, imacb); } setAreaFlag(aq, AREA_USE); return (VP)(aq + 1); }
/* * Memory pool initial setting */ LOCAL void init_mempool( MPLCB *mplcb, void *mempool, INT mempsz ) { QUEUE *tp, *ep; QueInit(&mplcb->areaque); QueInit(&mplcb->freeque); /* Register onto AreaQue */ tp = (QUEUE*)mempool; ep = (QUEUE*)((VB*)mempool + mempsz) - 1; insertAreaQue(&mplcb->areaque, ep); insertAreaQue(&mplcb->areaque, tp); /* Set AREA_USE for locations that must not be free area */ setAreaFlag(&mplcb->areaque, AREA_USE); setAreaFlag(ep, AREA_USE); /* Register onto FreeQue */ appendFreeArea(mplcb, tp); }
/* * Free memory */ static void _mem_free( void *ptr, MACB *macb ) { LIST *aq; if ( ptr == 0 ) { return; } if ( macb->testmode > 0 ) { if ( !chkalloc(ptr, 0, macb) ) { return; } } aq = (LIST *)ptr - 1; clrAreaFlag(aq, AREA_USE); if ( !chkAreaFlag(aq->next, AREA_END|AREA_USE) ) { /* Merge with just next free area */ removeFreeQue(aq->next + 1); removeAreaQue(aq->next); } if ( !chkAreaFlag(aq, AREA_TOP) && !chkAreaFlag(aq->previous, AREA_USE) ) { /* Merge with just previous free area */ aq = aq->previous; removeFreeQue(aq + 1); removeAreaQue(aq->next); } /* If whole page is empty, then release the page itself */ if ( chkAreaFlag(aq, AREA_TOP) && chkAreaFlag(aq->next, AREA_END) ) { /* Page release */ removeAreaQue(aq->next); removeAreaQue(aq); (*macb->relblk)(aq); } else { /* Register free area in free queue */ appendFreeArea(aq, macb); } }