/* * Allocate new page capable of allocating a contiguous area at least * as big as 'size' byte */ RAW_INLINE LIST *newPage( RAW_U32 size, MACB *macb ) { LIST *top, *end; RAW_U32 nblk; if ( macb->pagesz == 0 ) { return 0; } /* Allocate page */ nblk = toPageCount(size + sizeof(LIST )*2, macb); top = (LIST *)(*macb->getblk)(nblk); if ( top == 0 ) { return 0; } /* Register in area queue */ end = (LIST *)((RAW_S8 *)top + nblk * macb->pagesz) - 1; insertAreaQue(&macb->areaque, end); insertAreaQue(&macb->areaque, top); setAreaFlag(top, AREA_TOP); setAreaFlag(end, AREA_END); return top; }
/* * 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; }
/* * 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); }
/* * 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); }
/* * 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); }