/* * 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); }
/* * Get memory */ LOCAL void* imalloc( size_t size, IMACB *imacb ) { QUEUE *q; VP mem; UW imask; /* If it is smaller than the minimum fragment size, allocate the minimum size to it. */ if ( size < MIN_FRAGMENT ) { size = MIN_FRAGMENT; } size = ROUND(size); DI(imask); /* Exclusive control by interrupt disable */ SpinLock(&MemLockObj); /* Search FreeQue */ q = searchFreeArea(size, imacb); if ( q != &imacb->freeque ) { /* There is free area: Split from FreeQue once */ removeFreeQue(q); q = q - 1; } else { /* Reserve new pages because there is no free space */ QUEUE *e; size_t n; /* Reserve pages */ SpinUnlock(&MemLockObj); EI(imask); n = PageCount(size + sizeof(QUEUE) * 2); q = GetSysMemBlk(n, imacb->mematr); if ( q == NULL ) { goto err_ret; /* Insufficient memory */ } DI(imask); SpinLock(&MemLockObj); /* Register on AreaQue */ e = (QUEUE*)((VB*)q + n * pagesz) - 1; insertAreaQue(&imacb->areaque, e); insertAreaQue(&imacb->areaque, q); setAreaFlag(q, AREA_TOP); setAreaFlag(e, AREA_END); } /* Allocate memory */ mem = mem_alloc(q, size, imacb); SpinUnlock(&MemLockObj); EI(imask); return mem; err_ret: BMS_DEBUG_PRINT(("imalloc error\n")); return NULL; }
/* * 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); }
/* * 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); } }
/* * Memory allocate */ static void *_mem_malloc(RAW_U32 size, MACB *macb) { LIST *q; if ( macb->testmode) { chkalloc(0, 0, macb); } /* If smaller than the minimum fragment size, allocate the minimum fragment size */ if ( size > 0 && size < MIN_FRAGMENT ) { size = MIN_FRAGMENT; } size = ROUND(size); if ( size <= 0 ) { return 0; } /* Search free queue */ q = searchFreeArea(size, macb); if ( q != &macb->freeque ) { /* Free space available: first, isolate from free queue */ removeFreeQue(q); q = q - 1; } else { /* No free space, then allocate new page */ q = newPage(size, macb); if ( q == 0 ) { return 0; /* Insufficient memory */ } } /* Allocate memory */ return allocate(q, size, macb); }
/* * Memory allocation size change */ static void *_mem_realloc( void *ptr, RAW_U32 size, MACB *macb ) { LIST *aq; RAW_U32 oldsz, sz; if ( macb->testmode > 0 ) { if ( !chkalloc(ptr, 0, macb) ) { return 0; } } /* If smaller than minimum fragment size, allocate minimum fragment size */ if ( size > 0 && size < MIN_FRAGMENT ) { size = MIN_FRAGMENT; } size = ROUND(size); aq = (LIST *)ptr - 1; if ( ptr != 0 ) { /* Current allocation size */ oldsz = (RAW_U32)AreaSize(aq); /* Merge if next space is free space */ if ( !chkAreaFlag(aq->next, AREA_END|AREA_USE) ) { removeFreeQue(aq->next + 1); removeAreaQue(aq->next); } sz = (RAW_U32)AreaSize(aq); } else { sz = oldsz = 0; } if ( size <= sz ) { if ( size > 0 ) { /* Fragment current area and allocate */ allocate(aq, size, macb); } else { /* Release area */ _mem_free(ptr, macb); ptr = 0; } } else { /* Allocate new area */ void *newptr = _mem_malloc(size, macb); if ( newptr == 0 ) { /* Reallocate original area at original size */ if ( ptr != 0 ) { allocate(aq, oldsz, macb); } return 0; } if ( ptr != 0 ) { /* Copy contents */ raw_memcpy(newptr, ptr, oldsz); /* Release old area */ _mem_free(ptr, macb); } ptr = newptr; } return ptr; }