/* * Registration of free area on FreeQue * FreeQue is composed of 2 types: Queue that links the * different size of areas by size and queue that links the * same size of areas. * * freeque * | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * | +-----------------------+ +-----------------------+ * *---> FreeQue Size order | | EmptyQue | * | | FreeQue Same size --------->| FreeQue Same size -----> * | | | | | * | | | | | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * v +-----------------------+ +-----------------------+ */ EXPORT void knl_appendFreeArea( IMACB *imacb, QUEUE *aq ) { QUEUE *fq; W size = AreaSize(aq); /* Registration position search */ /* Search the free area whose size is equal to 'blksz', * or larger than 'blksz' but closest. * If it does not exist, return '&imacb->freeque'. */ fq = knl_searchFreeArea(imacb, size); /* Register */ clrAreaFlag(aq, AREA_USE); if ( fq != &imacb->freeque && FreeSize(fq) == size ) { /* FreeQue Same size */ (aq + 2)->next = (fq + 1)->next; (fq + 1)->next = aq + 2; (aq + 2)->prev = fq + 1; if( (aq + 2)->next != NULL ) { (aq + 2)->next->prev = aq + 2; } (aq + 1)->next = NULL; } else { /* FreeQue Size order */ QueInsert(aq + 1, fq); (aq + 2)->next = NULL; (aq + 2)->prev = (QUEUE*)size; } }
/* * 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; }
/* * Free memory * It may be called during interrupt disable. In this case, need to wait * until interrupt is enabled and until free. */ EXPORT void knl_Ifree( void *ptr ) { QUEUE *aq; UINT imask; DI(imask); /* Exclusive control by interrupt disable */ aq = (QUEUE*)ptr - 1; clrAreaFlag(aq, AREA_USE); if ( !chkAreaFlag(aq->next, AREA_USE) ) { /* Merge with free area in after location */ knl_removeFreeQue(aq->next + 1); knl_removeAreaQue(aq->next); } if ( !chkAreaFlag(aq->prev, AREA_USE) ) { /* Merge with free area in front location */ aq = aq->prev; knl_removeFreeQue(aq + 1); knl_removeAreaQue(aq->next); } knl_appendFreeArea(knl_imacb, aq); EI(imask); }
/* * 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); } }
/* * Registration in free space free queue * Free queue comprises a two-tier structure: a queue linking * areas of differing size in order of size, and a queue * linking areas that are the same size. * * macb->freeque * | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * | +-----------------------+ +-----------------------+ * +----> FreeQue size order | +--------> FreeQue same size -----> * | | FreeQue same size --------+ | EmptyQue | * | | | | | * | | | | | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * | +-----------------------+ +-----------------------+ */ void appendFreeArea( LIST *aq, MACB *macb ) { LIST *fq; RAW_U32 size = (RAW_U32)AreaSize(aq); /* Search registration position */ /* Searches for a free space with the same size as 'size' or * the next largest. * If none is found, returns &freeque. */ fq = searchFreeArea(size, macb); /* Registration */ clrAreaFlag(aq, AREA_USE); if ( fq != &macb->freeque && (RAW_U32)FreeSize(fq) == size ) { list_insert(fq + 1, aq + 1); } else { list_insert(fq, aq + 1); } list_init(aq + 2); }
/* * Registration of free area on FreeQue * FreeQue is composed of 2 types: Queue that links the * different size of areas by size and queue that links the * same size of areas. * * freeque * | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * | +-----------------------+ +-----------------------+ * *---> FreeQue Size order | *----> FreeQue Same size -----> * | | FreeQue Same size -----* | EmptyQue | * | | | | | * | | | | | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * v +-----------------------+ +-----------------------+ */ LOCAL void appendFreeArea( MPLCB *mplcb, QUEUE *aq ) { QUEUE *fq; INT size = AreaSize(aq); /* Registration position search */ /* Search the free area whose size is equal to 'blksz', * or larger than 'blksz' but closest. * If it does not exist, return '&mplcb->freeque'. */ fq = searchFreeArea(mplcb, size); /* Register */ clrAreaFlag(aq, AREA_USE); if ( fq != &mplcb->freeque && FreeSize(fq) == size ) { QueInsert(aq + 1, fq + 1); } else { QueInsert(aq + 1, fq); } QueInit(aq + 2); }
/* * Registration of free area on FreeQue * FreeQue is composed of 2 types: Queue that links the different * size of areas by size * and queue that links the same size areas. * * imacb->freeque * | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * | +-----------------------+ +-----------------------+ * *---> FreeQue by size | *----> FreeQue same size ----> * | | FreeQue same size ----* | EmptyQue | * | | | | | * | | | | | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * v +-----------------------+ +-----------------------+ */ LOCAL void appendFreeArea( QUEUE *aq, IMACB *imacb ) { QUEUE *fq; size_t size = AreaSize(aq); /* Registration position search */ /* Search free area whose size is equal to 'blksz', * or closest and larger than 'blksz'. * If it can not be found, return '&imacb->freeque'. */ fq = searchFreeArea(size, imacb); /* Registration */ clrAreaFlag(aq, AREA_USE); if ( (fq != &imacb->freeque) && (FreeSize(fq) == size) ) { QueInsert(aq + 1, fq + 1); } else { QueInsert(aq + 1, fq); } QueInit(aq + 2); }