PVOID
KernelResizeMemory
    (
        PVOID                       pMem,
        ULONG                       ulSize
    )
{
    /*DH  DEBUG*/
    /*KernelTrace("KernelResizeMemory ...\n");*/

    KernelFreeMemory(pMem);

    return  KernelAllocateMemory(ulSize);
}
PVOID
__KernelReAllocMemory
    (
        PVOID                       pMem,
        ULONG                       ulSize,
        PCSTR                       pFileName,
        ULONG                       LineNumber
    )
{
    void*                           pOldMemory = (void*)pMem;
    void*                           pNewMemory = NULL;
    ULONG                           ulOldSize  = KernelGetMemorySize(pOldMemory);
    ULONG                           ulNewSize  = ulSize;
    ULONG                           ulCpySize  = (ulOldSize >= ulNewSize) ? ulNewSize : ulOldSize;

    /*DH  DEBUG*/
    KernelTrace
        (
            "__KernelReAllocMemory -- %s:%lu, old size = %lu, new size = %lu, copy size = %lu ...\n",
            pFileName,
            LineNumber,
            ulOldSize,
            ulNewSize,
            ulCpySize
        );

    if ( ulNewSize <= ulOldSize )
    {
        return  pOldMemory;
    }

    pNewMemory = KernelAllocateMemory(ulNewSize);

    if ( !pNewMemory )
    {
        KernelFreeMemory(pOldMemory);

        return  NULL;
    }
    else
    {
        KernelCopyMemory(pNewMemory, pOldMemory, ulCpySize);
    }

    KernelFreeMemory(pOldMemory);

    return  pNewMemory;
}
PVOID
KernelResizeMemory
    (
        PVOID                       pMem,
        ULONG                       ulSize
    )
{
    BITS                            critLevel;
    PVOID                           pNewMem     = NULL;

    critLevel = atmos_startcritical();

    KernelFreeMemory(pMem);

    pNewMem = KernelAllocateMemory(ulSize);

    atmos_endcritical(critLevel);

    return  pNewMem;
}
PVOID
KernelReAllocMemory
    (
        PVOID                       pMemoryBlock,
        ULONG                       ulMemorySize
    )
{
    BITS                            critLevel;
    void*                           pOldMemory = (void*)pMemoryBlock;
    void*                           pNewMemory = NULL;
    ULONG                           ulOldSize  = 0;
    ULONG                           ulNewSize  = 0;
    ULONG                           ulCpySize  = 0;

    critLevel  = atmos_startcritical();

    ulOldSize  = KernelGetMemorySize(pOldMemory);
    ulNewSize  = ulMemorySize;
    ulCpySize  = (ulOldSize >= ulNewSize) ? ulNewSize : ulOldSize;

    pNewMemory = KernelAllocateMemory(ulNewSize);

    atmos_endcritical(critLevel);

    if ( !pNewMemory )
    {
        return  NULL;
    }
    else
    {
        KernelCopyMemory(pNewMemory, pOldMemory, ulCpySize);
    }

    critLevel = atmos_startcritical();

    KernelFreeMemory(pOldMemory);

    atmos_endcritical(critLevel);

    return  pNewMemory;
}
/*
 *  eCos doesn't clean the memory blocks of stack and thread info required to create
 *  a thread, if they are dynamically allocated. Here is how we clean them:
 *      1) when a thread is created, we allocate a memory block for both stack and thread info.
 *      2) The memory block pointer is stored into thread data, index 0
 *      3) When a thread exits, it retrieves the memory block pointer from thread data, index 0
 *          and put it into a pool
 *      4) Next time when another thread exits, it first cleans up the memory block pool.
 *      5) In step 3) and 4), a spin lock is used to protect the memory block pool.
 */
KERNEL_HANDLE
KernelCreateTask
    (
        cyg_thread_entry_t*         startEntry,
        ULONG                       stackSize,
        ULONG                       priority,
        KERNEL_HANDLE               hContext,
        char*                       pName
    )
{
    ULONG                           ulSize      = 0;
    PKERNEL_TASK_MEM_BLOCK          pMem        = NULL;
    PUCHAR                          pStack      = NULL;
    cyg_thread*                     pThreadInfo = NULL;
    cyg_handle_t                    hThread     = 0;

    ulSize  = (sizeof(KERNEL_TASK_MEM_BLOCK) + CYGNUM_HAL_STACK_FRAME_SIZE) / CYGNUM_HAL_STACK_FRAME_SIZE * CYGNUM_HAL_STACK_FRAME_SIZE;

    pMem    = (PKERNEL_TASK_MEM_BLOCK)KernelAllocateMemory(ulSize + stackSize);

    if ( pMem )
    {
        pStack      = pMem + ulSize;
        pThreadInfo = &pMem->ThreadInfo;

        cyg_thread_create
            (
                priority,
                startEntry,
                hContext,
                pName,
                pStack,
                stackSize,
                &hThread,
                pThreadInfo
            );

        if ( hThread )
        {
            KernelTrace
                (
                    "KernelCreateTask -- memory block pointer for task %s is 0x%lX.\n",
                    pName,
                    pMem
                );

            cyg_thread_set_data(0, pMem);

            cyg_thread_resume(hThread);

            return  hThread;
        }
    }

    if ( pMem )
    {
        KernelFreeMemory(pMem);
    }

    return  (KERNEL_HANDLE)NULL;
}
KERNEL_HANDLE
KernelCreateTask
    (
        KERNEL_TASK_START_ENTRY     startEntry,
        ULONG                       stackSize,
        ULONG                       priority,
        KERNEL_HANDLE               hContext,
        char*                       taskName
    )
{
    static  ULONG                   taskNo          = 0;

    PKERNEL_TASK_CONTEXT            pTaskContext    = NULL;
    PROCESS                         pProc;

    wait_sem(&gSerializeSem);

    KernelTrace2
        (
            KERNEL_DBG_LEVEL_TRACE_FLOW,
            KERNEL_DBG_MASK_GENERIC,
            "KernelCreateTask -- taskName = %s, startEntry = 0x%X, stackSize = %d, priority = %d, context = 0x%X.\n",
            taskName,
            startEntry,
            stackSize,
            priority,
            hContext
        );

    pTaskContext = KernelAllocateMemory(sizeof(KERNEL_TASK_CONTEXT));

    if (pTaskContext == NULL)
    {
        KernelTrace2
            (
                KERNEL_DBG_LEVEL_WARNING,
                KERNEL_DBG_MASK_GENERIC,
                "KernelCreateTask -- cannot allocate memory for the task context, size = %d.\n",
                sizeof(KERNEL_TASK_CONTEXT)
            );

        signal_sem(&gSerializeSem);

        return  KERNEL_HANDLE_NULL;
    }

    pTaskContext->StartEntry    = startEntry;
    pTaskContext->hContext      = hContext;

    KernelAssert(gpTaskContext == NULL);

    gpTaskContext = pTaskContext;

    pProc =
        create_process
            (
                priority - (priority % 64),
                taskName,
                KernelTaskRoutineEntry,
                stackSize,
                priority % 64,
                0,
                (PROCESS)0,
                (struct OS_redir_entry *)0,
                0x0000,
                (OSUSER)0
            );

    if (!pProc)
    {
        KernelTrace2
            (
                KERNEL_DBG_LEVEL_WARNING,
                KERNEL_DBG_MASK_GENERIC,
                "KernelCreateTask -- failed to create the process %s!\n",
                taskName
            );

        /*
         *  capture this exception
         */
        KernelAssert(FALSE);

        signal_sem(&gSerializeSem);

        return  KERNEL_HANDLE_NULL;
    }

    /*
     *  start the process
     */
    start(pProc);

    /*
     *  wait for the process complete access to the global task context
     */
    wait_sem(&gCompletionSem);

    KernelAssert(gpTaskContext == NULL);

    signal_sem(&gSerializeSem);

    return  (KERNEL_HANDLE)pProc;
}
BOOLEAN
KernelInitializeEvent
    (
        PKERNEL_EVENT               pBaseEvent
    )
{
    PKERNEL_EVENT_MSG               pEvent          = (PKERNEL_EVENT_MSG)pBaseEvent;
    BITS                            critLevel;
    BOOLEAN                         retStatus       = TRUE;

    KernelTrace2
        (
            KERNEL_DBG_LEVEL_TRACE_FLOW,
            KERNEL_DBG_MASK_EVENT,
            "KernelInitializeEvent -- Handle: 0x%lX, Task: %s.\n",
            pEvent,
            atmos_pcb_current_get_name()
        );

    critLevel = atmos_startcritical();

    if ( !bEventMsgInit )
    {
        int                 i;
        PKERNEL_FREE_MSG    pTmpMsg;
    
        pFreeMsgHeader = NULL;

        for (i = 0; i < KERNEL_MAX_MESSAGE_NUM; i++)
        {
            pTmpMsg =
                (PKERNEL_FREE_MSG)KernelAllocateMemory(sizeof(KERNEL_FREE_MSG));

            pTmpMsg->Next   = pFreeMsgHeader;
            pFreeMsgHeader  = pTmpMsg;
        }

        /* KernelRealInitializeLock(&EventLock,  __FILE__, __LINE__); */

        bEventMsgInit = TRUE;
    }

    if ( pEvent == NULL)
    {
        KernelTrace2
            (
                KERNEL_DBG_LEVEL_WARNING,
                KERNEL_DBG_MASK_EVENT,
                "KernelInitializeEvent -- NULL Event!!\n"
            );

        retStatus = FALSE;
        goto EXIT1; 
    }

    pEvent->NumberSignaled = 0;
    KernelSListInitializeHeader(&pEvent->TaskList);

EXIT1:

    atmos_endcritical(critLevel);
    KernelTrace2
        (
            KERNEL_DBG_LEVEL_TRACE_FLOW,
            KERNEL_DBG_MASK_EVENT,
            "KernelInitializeEvent -- done, Handle: 0x%lX, Task: %s.\n",
            pEvent,
            atmos_pcb_current_get_name()
        );

    return retStatus;
}
BOOLEAN
KernelRealInitializeLock
    (
        PKERNEL_LOCK                pLock,
        const char*                 pFileName,
        ULONG                       ulLineNumber
    )
{
    BITS                            critLevel;
    BOOLEAN                         retStatus       = TRUE;
    tASErr                          err;
    char                            cSemaName[32];

    if ( !bEnableLock )
    {
        return retStatus;
    }

    critLevel = atmos_startcritical();

    if ( !bSemaphoreInit )
    {
        int                 i;
        PKERNEL_FREE_LOCK   pFreeSema;

        pFreeLockHeader = NULL;

        for ( i = 0; i < KERNEL_MAX_SEMAPHORE_NUM; i++ )
        {
            if ( i % (KERNEL_MAX_SEMAPHORE_NUM / 10) == 0 )
            {
                KernelTrace2
                    (
                        KERNEL_DBG_LEVEL_TRACE_FLOW,
                        KERNEL_DBG_MASK_LOCK,
                        "KernelRealInitializeLock -- %03d%% finished!!\n",
                        (i * 100 / KERNEL_MAX_SEMAPHORE_NUM)
                    );
            }
            
            pFreeSema =
                (PKERNEL_FREE_LOCK)KernelAllocateMemory(sizeof(KERNEL_FREE_LOCK));

            if ( pFreeSema == NULL )
            {
                KernelTrace2
                    (
                        KERNEL_DBG_LEVEL_WARNING,
                        KERNEL_DBG_MASK_LOCK,
                        "KernelRealInitializeLock -- run out of memory!!\n"
                    );

                retStatus = FALSE;
                goto EXIT1;
            }

            pFreeSema->semaLock = NULL;
            pFreeSema->Next     = pFreeLockHeader;
            pFreeLockHeader     = pFreeSema;
        }

        KernelTrace2
            (
                KERNEL_DBG_LEVEL_TRACE_FLOW,
                KERNEL_DBG_MASK_LOCK,
                "KernelRealInitializeLock -- %03d%% finished!!\n",
                (i * 100 / KERNEL_MAX_SEMAPHORE_NUM)
            );

        bSemaphoreInit = TRUE;
    }

    if ( pLock == NULL)
    {
        KernelTrace2
            (
                KERNEL_DBG_LEVEL_WARNING,
                KERNEL_DBG_MASK_LOCK,
                "KernelRealInitializeLock -- NULL lock, file -- %s, line %lu!!\n",
                (pFileName ? pFileName : "No file name"),
                ulLineNumber
            );

        retStatus = FALSE;
        goto EXIT1; 
    }

    if ( !bSemaphoreInit || pFreeLockHeader == NULL )
    {
        KernelTrace2
            (
                KERNEL_DBG_LEVEL_WARNING,
                KERNEL_DBG_MASK_LOCK,
                "KernelRealInitializeLock -- run out of FREE LOCK, %u, task: %s!!\n",
                bSemaphoreInit,
                atmos_pcb_current_get_name()
            );

        retStatus = FALSE;
        goto EXIT1; 
    }

    gulLockCount   += 1;
    *pLock          = pFreeLockHeader;
    pFreeLockHeader = (*pLock)->Next;
    (*pLock)->Next  = NULL;

    atmos_endcritical(critLevel);

    if ( (*pLock)->semaLock == NULL )
    {
        sprintf(cSemaName, "%s%05u", semaphore_name, gulSemaphoreId);
        gulSemaphoreId += 1;

        err = as_SemaphoreNew
            (
                &(*pLock)->semaLock, 
                (const char*)cSemaName, 
                ""
            );
    
        if (kASEOK != err)
        {
            retStatus                = FALSE;

            KernelTrace2
                (
                    KERNEL_DBG_LEVEL_WARNING,
                    KERNEL_DBG_MASK_LOCK,
                    "KernelRealInitializeLock -- new semaphore failed!!\n"
                );

            return retStatus;
        }

        as_SemaphorePost((*pLock)->semaLock);
    }

EXIT1:
    atmos_endcritical(critLevel);
    return retStatus;
}
void
KernelWaitEvent
    (
        PKERNEL_EVENT               pBaseEvent,
        ULONG                       ulMilliSeconds
    )
{
    PKERNEL_EVENT_MSG               pEvent          = (PKERNEL_EVENT_MSG)pBaseEvent;
    PKERNEL_SLIST_ENTRY             pSavedSListEntry= (PKERNEL_SLIST_ENTRY)NULL;
    PKERNEL_TASK_LIST_ENTRY         pTaskListEntry;
    PKERNEL_FREE_MSG                pFreeMsg;
    BITS                            critLevel;
    BOOLEAN                         bInfinite       = FALSE;
    BOOLEAN                         bLoop           = TRUE;
    CHAR*                           cTaskName;
    ATMOS_MESSAGE                   TimerMsg;
    ATMOS_MESSAGE*                  pWaitingMsg;
    WORD                            wRtnCode;
    int                             iPhase          = 0;
    char                            NameBuffer[16]  = "Insuffient";
    char                            NameBuffer2[16] = "Insuffient";

    cTaskName = (char*)atmos_pcb_current_get_name();

    KernelTrace2
        (
            KERNEL_DBG_LEVEL_TRACE_FLOW,
            KERNEL_DBG_MASK_EVENT,
            "KernelWaitEvent -- event: 0x%lX, task = %s, time = %u.\n",
            pEvent,
            cTaskName,
            ulMilliSeconds
        );

    if ( ulMilliSeconds == 0 || ulMilliSeconds == 0xFFFFFFFF )
    {
        bInfinite = TRUE;
    }

    if ( pEvent == NULL)
    {
        KernelTrace2
            (
                KERNEL_DBG_LEVEL_WARNING,
                KERNEL_DBG_MASK_EVENT,
                "KernelWaitEvent -- NULL Event, Task: %s!!\n",
                cTaskName
            );

        return;
    }

    critLevel = atmos_startcritical();
    /*KernelRealAcquireLock(&EventLock,  __FILE__, __LINE__);*/
    
    if ( pEvent->NumberSignaled )
    {
        pEvent->NumberSignaled -= 1;
        bLoop = FALSE;
    }
    else
    {
        pTaskListEntry          = (PKERNEL_TASK_LIST_ENTRY)KernelAllocateMemory(sizeof(KERNEL_TASK_LIST_ENTRY));
        pTaskListEntry->TaskQid = atmos_qid_get_current();

    #if defined(KERNEL_CHECKED_BUILD)
        KernelCopyString(pTaskListEntry->TaskName, cTaskName);
    #endif

        KernelSListPushEntry(&pEvent->TaskList, &pTaskListEntry->Linkage);
        pSavedSListEntry = &pTaskListEntry->Linkage;
    }

    atmos_endcritical(critLevel);
    /*KernelRealReleaseLock(&EventLock,  __FILE__, __LINE__);*/

    if ( bLoop && !bInfinite )
    {
        timer_ms_timeout(&TimerMsg, ulMilliSeconds);
    }

    while ( bLoop )
    {
        KernelTrace2
            (
                KERNEL_DBG_LEVEL_TRACE_FLOW,
                KERNEL_DBG_MASK_EVENT,
                "KernelWaitEvent -- waiting ..., Event = 0x%lx, Task = %s.\n",
                pEvent,
                cTaskName
            );

        pWaitingMsg = awaitmessage();

        switch ( pWaitingMsg->code )
        {
            case    MSG_N_KTX_AL_SET_EVENT:
                {
                    MSG_D_KTX_AL_SET_EVENT(pSetEvent, pWaitingMsg);

                    if ( pSetEvent->EventHandle == (U32*)pEvent ) 
                    {
                        bLoop = FALSE;

                        if ( !bInfinite )
                        {
                            bInfinite = TRUE;

                            if ( pollspecificmessage(&TimerMsg) )
                            {
                                KernelTrace2
                                    (
                                        KERNEL_DBG_LEVEL_TRACE_FLOW,
                                        KERNEL_DBG_MASK_EVENT,
                                        "KernelWaitEvent -- event = 0x%lX, task = %s, timer message is on the way...\n",
                                        pEvent,
                                        cTaskName
                                    );

                                awaitspecificmessage(&TimerMsg);

                                KernelTrace2
                                    (
                                        KERNEL_DBG_LEVEL_TRACE_FLOW,
                                        KERNEL_DBG_MASK_EVENT,
                                        "KernelWaitEvent -- event = 0x%lX, task = %s, cleaned the timer message.\n",
                                        pEvent,
                                        cTaskName
                                    );
                            }
                            else
                            {
                                KernelTrace2
                                    (
                                        KERNEL_DBG_LEVEL_TRACE_FLOW,
                                        KERNEL_DBG_MASK_EVENT,
                                        "KernelWaitEvent -- event = 0x%lX, task = %s, cancel the timer message...\n",
                                        pEvent,
                                        cTaskName
                                    );

                                wRtnCode = timer_cancel(&TimerMsg);

                                KernelTrace2
                                    (
                                        KERNEL_DBG_LEVEL_TRACE_FLOW,
                                        KERNEL_DBG_MASK_EVENT,
                                        "KernelWaitEvent -- event = 0x%lX, task = %s, done with the timer message cancellation, error code = %u, %s.\n",
                                        pEvent,
                                        cTaskName,
                                        wRtnCode,
                                        pollmessage() ? "new message pending" : "no new messages"
                                    );

                                /* Found or not (wRtnCode == ENOTFOUND), the original message should have come back */
                                if ( pollspecificmessage(&TimerMsg) )
                                {
                                    awaitspecificmessage(&TimerMsg);

                                    KernelTrace2
                                        (
                                            KERNEL_DBG_LEVEL_TRACE_FLOW,
                                            KERNEL_DBG_MASK_EVENT,
                                            "KernelWaitEvent -- event = 0x%lX, task = %s, cleaned the timer message.\n",
                                            pEvent,
                                            cTaskName
                                        );
                                }
                                else
                                {
                                    KernelTrace2
                                        (
                                            KERNEL_DBG_LEVEL_WARNING,
                                            KERNEL_DBG_MASK_EVENT,
                                            "KernelWaitEvent -- event = 0x%lX, task = %s, Timer message didn't come back!!!\n",
                                            pEvent,
                                            cTaskName
                                        );
                                }
                            }
                        }
                    }
                    else
                    {
                        KernelTrace2
                            (
                                KERNEL_DBG_LEVEL_WARNING,
                                KERNEL_DBG_MASK_EVENT,
                                "KernelWaitEvent -- event = 0x%lX, qid = 0x%lX, task = %s, received bad SetEvent msg, event handle = 0x%lX, from task %s!!\n",
                                pEvent,
                                atmos_qid_get_current(),
                                cTaskName,
                                pSetEvent->EventHandle,
                                atmos_qid_get_name(pWaitingMsg->src, NameBuffer, sizeof(NameBuffer))
                            );
                    }

                    critLevel = atmos_startcritical();
                    /*KernelRealAcquireLock(&EventLock,  __FILE__, __LINE__);*/

                    pFreeMsg = ACCESS_FREE_MSG(pWaitingMsg);

                    pFreeMsg->Next = pFreeMsgHeader;
                    pFreeMsgHeader = pFreeMsg;

                    atmos_endcritical(critLevel);
                    /*KernelRealReleaseLock(&EventLock,  __FILE__, __LINE__);*/

                    iPhase = 1;

                    break;
                }

            case    MSG_R_TIMER_MSWAIT:
                {
                    BOOLEAN         bFound;

                    bLoop = FALSE;

                    KernelTrace2
                        (
                            KERNEL_DBG_LEVEL_TRACE_INFO,
                            KERNEL_DBG_MASK_EVENT,
                            "KernelWaitEvent -- event = 0x%lX, task = %s, timed-out...\n",
                            pEvent,
                            cTaskName
                        );

                    critLevel = atmos_startcritical();
                    /*KernelRealAcquireLock(&EventLock,  __FILE__, __LINE__);*/

                    bFound = 
                        KernelSListPopEntryByLink(&pEvent->TaskList, pSavedSListEntry);
                    if ( bFound )
                    {
                        pTaskListEntry = ACCESS_TASK_LIST_ENTRY(pSavedSListEntry);
                        if ( pTaskListEntry->TaskQid == atmos_qid_get_current() )
                        {
                            KernelFreeMemory(pTaskListEntry);
                        }
                        else
                        {
                            KernelSListPushEntry(&pEvent->TaskList, pSavedSListEntry);
                        }
                    }

                    atmos_endcritical(critLevel);
                    /*KernelRealReleaseLock(&EventLock,  __FILE__, __LINE__);*/

                    iPhase = 2;

                    break;
                }

            default:
                {
                    KernelTrace2
                        (
                            KERNEL_DBG_LEVEL_WARNING,
                            KERNEL_DBG_MASK_EVENT,
                            "KernelWaitEvent -- event = 0x%lX, qid = 0x%lX, task = %s, received unknown msg: 0x%X, src: 0x%X(%s), dst: 0x%X(%s)!\n",
                            pEvent,
                            atmos_qid_get_current(),
                            cTaskName,
                            pWaitingMsg->code,
                            pWaitingMsg->src,
                            atmos_qid_get_name(pWaitingMsg->src, NameBuffer, sizeof(NameBuffer)),
                            pWaitingMsg->dest,
                            atmos_qid_get_name(pWaitingMsg->dest, NameBuffer2, sizeof(NameBuffer2))
                        );

                    break;
                }
        }
    }

    return;
}