U0 SysBadFree(I64 *ptr) { Panic("Bad Free:", ptr); } U0 SysBadMAlloc(I64 *ptr) { Panic("Bad MAlloc:", ptr); } U8 *MemPagAlloc(I64 pags, CBlkPool *bp=NULL) {/*Alloc pags from BlkPool. Don't link to task. (Linking to a task means they will be freed when the task dies.) It might give you more than you asked for. Return: NULL if out of memory. */ CMemBlk *res = NULL, *m; I64 i; if (!bp) bp = sys_code_bp; PUSHFD CLI while (LBts(&bp->locked_flags, BPlf_LOCKED)) PAUSE if (pags < MEM_FREE_PAG_HASH_SIZE) { if (res = bp->free_pag_hash[pags]) { bp->free_pag_hash[pags] = res->next; goto at_done; } i = Bsr(MEM_FREE_PAG_HASH_SIZE) + 1; } else { //We'll now round-up to a power of two. //There is some overhead on allocations and //we wouldn't want to round to the next //power of two if a power of two was requested. //So we use a little more than a power of two. pags -= MEM_EXTRA_HASH2_PAGS; i = Bsr(pags) + 1; pags = 1 << i + MEM_EXTRA_HASH2_PAGS; if (res = bp->free_pag_hash2[i]) { bp->free_pag_hash2[i] = res->next; goto at_done; } } m = &bp->mem_free_list; while (TRUE) { if (!(res = m->next)) { //We're probably out of luck, but lets search for a //freed larger size block... and, screw-it, return the whole thing. do { if (res = bp->free_pag_hash2[++i]) { pags = 1 << i + MEM_EXTRA_HASH2_PAGS; bp->free_pag_hash2[i] = res->next; goto at_done; } } while (i < 64 - MEM_PAG_BITS - 1); pags = 0; res = NULL; //Out of memory goto at_done2; } if (res->pags < pags) m = res; else { if (res->pags == pags) { m->next = res->next; goto at_done; } else { res->pags -= pags; res(U8 *) += res->pags << MEM_PAG_BITS; res->pags = pags; goto at_done; } } } at_done: bp->used_u8s += res->pags << MEM_PAG_BITS; at_done2: LBtr(&bp->locked_flags, BPlf_LOCKED); POPFD return res; } U0 MemPagFree(CMemBlk *m, CBlkPool *bp=NULL) {//Return non-task pags to BlkPool. I64 i, pags; if (m) { if (!bp) bp = sys_code_bp; PUSHFD CLI while (LBts(&bp->locked_flags, BPlf_LOCKED)) PAUSE pags = m->pags; m->mb_signature = MBS_UNUSED_SIGNATURE_VAL; bp->used_u8s -= pags << MEM_PAG_BITS; if (pags < MEM_FREE_PAG_HASH_SIZE) { m->next = bp->free_pag_hash[pags]; bp->free_pag_hash[pags] = m; } else { //We'll now round-up to a power of two. //There is some overhead on allocations and //we wouldn't want to round to the next //power of two if a power of two was requested. //So we use a little more than a power of two. pags -= MEM_EXTRA_HASH2_PAGS; i = Bsr(pags); m->next = bp->free_pag_hash2[i]; bp->free_pag_hash2[i] = m; } LBtr(&bp->locked_flags, BPlf_LOCKED); POPFD } } CMemBlk *MemPagTaskAlloc(I64 pags, CHeapCtrl *hc) {/*hc must be locked. Don't preempt this routine. Currently, this is only called from MAlloc(). Return: NULL if out of memory. */ CMemBlk *res; I64 threshold, count, size; CMemUnused *uum, **_uum, **_ptr; if (res = MemPagAlloc(pags, hc->bp)) { QueueInsert(res, hc->last_mem_blk); res->mb_signature = MBS_USED_SIGNATURE_VAL; hc->alloced_u8s += res->pags << MEM_PAG_BITS; //Tidy-up free list (Move into heap hash) //because if free list gets long, delay causes crash. threshold = MEM_HEAP_HASH_SIZE >> 4; #assert MEM_HEAP_HASH_SIZE >> 4 >= sizeof(U8 *) do { count = 0; _uum = &hc->malloc_free_list; while (uum = *_uum) { #assert !offset(CMemUnused.next) size = uum->size; if (size < threshold) { *_uum = uum->next; _ptr = (&hc->heap_hash)(U8 *) + size; uum->next = *_ptr; *_ptr = uum; } else { count++; _uum = uum; } } threshold <<= 1; } while (count > 8 && threshold <= MEM_HEAP_HASH_SIZE); } return res; } U0 MemPagTaskFree(CMemBlk *m, CHeapCtrl *hc) {//hc must be locked if (m) { PUSHFD CLI if (m->mb_signature != MBS_USED_SIGNATURE_VAL) SysBadFree(m); else { QueueRemove(m); hc->alloced_u8s -= m->pags << MEM_PAG_BITS; MemPagFree(m, hc->bp); } POPFD } }