/* * 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; }
/* * 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); }
/* * 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); }