#help_index "Memory/Task"
public I64 TaskMemAlloced(CTask *task=NULL, Bool override_validate=FALSE)
{//Count of bytes alloced to a task, used+unused.
        I64 res;

        if (!task)
                task = Fs;
        if (override_validate || TaskValidate(task))
        {
                res = task->code_heap->alloced_u8s;
                if (task->code_heap != task->data_heap)
                        res += task->data_heap->alloced_u8s;
                return res;
        }
        else
                return 0;
}

public I64 TaskMemUsed(CTask *task=NULL, Bool override_validate=FALSE)
{//Count of bytes alloced to a task and in use.
        I64 res;

        if (!task)
                task = Fs;
        if (override_validate || TaskValidate(task))
        {
                res = task->code_heap->used_u8s;
                if (task->data_heap != task->code_heap)
                        res += task->data_heap->used_u8s;
                return res;
        }
        else
                return 0;
}

#help_index "Memory/Task;Debugging/Heap;Memory/Debugging"
public Bool HeapRep(CTask *task)
{//Report status of task's heap.
        I64                      i, count;
        CMemUnused      *uum;

        if (!task || task == Fs)
        {
                "Task can't HeapRep on self.\n";
                return FALSE;
        }
        if (!TaskValidate(task))
                return FALSE;

        PUSHFD
        CLI
        while (LBts(&task->code_heap->locked_flags, HClf_LOCKED))
                PAUSE
        if (task->data_heap != task->code_heap)
                while (LBts(&task->data_heap->locked_flags, HClf_LOCKED))
                        PAUSE

        for (i = 0; i < MEM_HEAP_HASH_SIZE >> 3; i++)
        {
                count = 0;
                uum = task->code_heap->heap_hash[i];
                while (uum)
                {
                        count += uum->size;
                        uum = uum->next;
                }
                if (task->data_heap != task->code_heap)
                {
                        uum = task->data_heap->heap_hash[i];
                        while (uum)
                        {
                                count += uum->size;
                                uum = uum->next;
                        }
                }
                if (count)
                        "%03X:%08X\n", i << 3, count;
        }
        '\n';

        uum = task->code_heap->malloc_free_list;
        while (uum)
        {
                "%X, ", uum->size;
                uum = uum->next;
        }
        if (task->data_heap != task->code_heap)
        {
                uum = task->data_heap->malloc_free_list;
                while (uum)
                {
                        "%X, ", uum->size;
                        uum = uum->next;
                }
        }

        if (task->data_heap != task->code_heap)
                LBtr(&task->data_heap->locked_flags, HClf_LOCKED);
        LBtr(&task->code_heap->locked_flags, HClf_LOCKED);
        POPFD

        '\n';
}

#help_index "Memory/HeapCtrl;Debugging/Heap;Memory/Debugging"
public Bool IsInHeapCtrl(U8 *a, CHeapCtrl *hc, Bool lock=TRUE)
{//Check addr if in HeapCtrl.
        CMemBlk *m;

        PUSHFD
        CLI
        if (lock)
                while (LBts(&hc->locked_flags, HClf_LOCKED))
                        PAUSE
        m = hc->next_mem_blk;
        while (m != &hc->next_mem_blk)
        {
                if (a >= m && a < m(U8 *) + m->pags << MEM_PAG_BITS)
                {
                        if (lock)
                                LBtr(&hc->locked_flags, HClf_LOCKED);
                        POPFD
                        return TRUE;
                }
                m = m->next;
        }
        if (lock)
                LBtr(&hc->locked_flags, HClf_LOCKED);
        POPFD

        return FALSE;
}

public Bool HeapCtrlWalk(CHeapCtrl *hc)
{//Check integrity of HeapCtrl.
        I64                      i;
        CMemUnused      *uum;

        PUSHFD
        CLI
        while (LBts(&hc->locked_flags, HClf_LOCKED))
                PAUSE

        for (i = 0; i < MEM_HEAP_HASH_SIZE >> 3; i++)
        {
                uum = hc->heap_hash[i];
                while (uum)
                {
                        if (!IsInHeapCtrl(uum, hc, FALSE))
                                goto hc_false;
                        uum = uum->next;
                }
        }
        uum = hc->malloc_free_list;
        while (uum)
        {
                if (!IsInHeapCtrl(uum, hc, FALSE))
                        goto hc_false;
                uum = uum->next;
        }

        #if _CONFIG_HEAP_DEBUG
        CMemUsed *um, *um1;
        um1 = (&hc->next_um)(U8 *) - offset(CMemUsed.next);
        um = um1->next;
        while (um != um1)
        {
                if (!IsInHeapCtrl(um, hc, FALSE))
                        goto hc_false;
                um = um->next;
        }
#endif

        LBtr(&hc->locked_flags, HClf_LOCKED);
        POPFD
        return TRUE;

        hc_false:
        LBtr(&hc->locked_flags, HClf_LOCKED);
        POPFD

        return FALSE;
}

#help_index "Memory/Task;Debugging/Heap;Memory/Debugging"
public Bool IsInHeap(U8 *a, CTask *task=NULL, Bool lock=TRUE)
{//Check addr if in task's heaps.
        if (!task)
                task = Fs;
        if (TaskValidate(task) && (IsInHeapCtrl(a, task->code_heap, lock) ||
                        task->data_heap != task->code_heap &&
                        IsInHeapCtrl(a, task->data_heap, lock)))
                return TRUE;
        else
                return FALSE;
}

public Bool HeapWalk(CTask *task=NULL)
{//Check integrity of task's heaps.
        if (!task)
                task = Fs;
        if (!TaskValidate(task) || !HeapCtrlWalk(task->code_heap) || task->data_heap != task->code_heap && !HeapCtrlWalk(task->data_heap))
                return FALSE;
        else
                return TRUE;
}