ZealOS/src/Kernel/Memory/MemPag.CC
TomAwezome 7e0ce60071 Reformatted Kernel files in Memory subdirectory.
Reformatted BlkPool.CC, HeapCtrl.CC, MAllocFree.CC, MemPag.CC, MemPhysical.CC, PageTables.CC.
2020-09-14 21:55:57 -04:00

202 lines
4.1 KiB
C++
Executable File

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 $LK,"MAlloc",A="MN: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
}
}