timer.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 704 行 · 第 1/2 页

C
704
字号
//  performance counter, the return value is FALSE.
//  
//  If this function is implemented by the OEM, the pointer pQueryPerformanceFrequency
//  should be initialized as follows:
//  
//  BOOL (*pQueryPerformanceFrequency)(LARGE_INTEGER *lpPerformanceFrequency)=OEMQueryPerformanceFrequency;
//
//------------------------------------------------------------------------------
BOOL 
OEMQueryPerformanceFrequency(
    LARGE_INTEGER *lpliPerformanceFreq
    ) 
{
    lpliPerformanceFreq->HighPart = 0;
    lpliPerformanceFreq->LowPart  = PerfCountFreq( );
    return TRUE;
}



//------------------------------------------------------------------------------
// set pointers to OEM functions
//------------------------------------------------------------------------------
BOOL (*pQueryPerformanceCounter)(LARGE_INTEGER *lpliPerformanceCount)=OEMQueryPerformanceCounter;
BOOL (*pQueryPerformanceFrequency)(LARGE_INTEGER *lpliPerformanceFreq)=OEMQueryPerformanceFrequency;



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
CPUSetSysTimerCount(
    DWORD dwCountdownMSec
    )
{
    // Using fixed tick, so do nothing
    return;
}


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
CPUClearSysTimerIRQ(
    void
    )
{
    // Using fixed tick, so do nothing
    return FALSE;
}



// In general the PIT (8254) does not support immediate reprogramming of the counter
// (the 8254 waits until the current countdown cycle is finished before reloading the
// counter with the new value) so the counter is fixed at SYSTEM_TICK_MS.  If this
// OAL is being adapted to a system with a reprogrammable countdown timer or a
// free running counter with compare registers, see the ODO platform for examples.
#define IDLE_MAX_MS SYSTEM_TICK_MS
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD
CPUGetSysTimerCountMax(
    DWORD dwIdleMSecRequested
    )
{
    if (dwIdleMSecRequested > IDLE_MAX_MS) {
        //
        // Our timer isn't capable of idling more than IDLE_MAX_MS milliseconds. 
        // We'll have to break the sleep time into reasonable chunks.
        //
        return IDLE_MAX_MS;
    }

    return dwIdleMSecRequested;
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
CPUEnterIdle(
    DWORD dwIdleParam
    )
{
    _asm {
        sti
        hlt
    }
}


//------------------------------------------------------------------------------
//
//  This routine is called by the kernel when there are no threads ready to
//  run. The CPU should be put into a reduced power mode and halted. It is 
//  important to be able to resume execution quickly upon receiving an interrupt.
//
//------------------------------------------------------------------------------
#if (CE_MAJOR_VER == 0x0003)
// Cedar
DWORD
CPUGetSysTimerCountElapsed(
    DWORD dwTimerCountdownMSec,
    volatile DWORD *pCurMSec,
    volatile DWORD *pDiffMSec,
    DWORD *pPartialCurMSec,
    DWORD *pPartialDiffMSec,
    volatile ULARGE_INTEGER *pCurTicks
    )
{
    // Using fixed tick, so do nothing and return 0 time passed
    return 0;
}

void
OEMIdle(
    DWORD dwIdleParam
    )
{
    DWORD dwIdleMSec;
    DWORD dwDiffMSecPrev = *pDiffMSec;
    static DWORD dwPartialCurMSec = 0;           // Keep CPU-specific sub-millisecond leftover.

    // Use for 64-bit math
    ULARGE_INTEGER currIdle = {
        curridlelow, 
        curridlehigh
    };
    
    if (ticksleft) {
        // if ticksleft, potentially there are threads on the sleep queue waiting to run, so don't idle
        return;
    }

    if (bProfileTimerRunning) {
        // system timer is running at CPU specific profiling value - just call CPUEnterIdle and return
        CPUEnterIdle(dwIdleParam);
        return;
    }

    if (dwSleepMin == 0 || fIntrTime) {
        //
        // No minimum sleep time specified. Wakeup on the normal schedule tick.
        //
        CPUEnterIdle(dwIdleParam);

        // Update global idle time and return
        currIdle.QuadPart += SYSTEM_TICK_MS;
        curridlelow = currIdle.LowPart;
        curridlehigh = currIdle.HighPart;

        return;
    }

    if (dwDiffMSecPrev >= dwSleepMin) {
        //
        // According to the globals, our sleep time has already passed!
        //
        return;
    }

    //
    // How many milliseconds until we should wake up again?
    //
    dwIdleMSec = dwSleepMin - dwDiffMSecPrev;

    //
    // The system timer may not be capable of arbitrary timeouts. Get the
    // CPU-specific highest possible timeout available.
    //
    dwIdleMSec = CPUGetSysTimerCountMax(dwIdleMSec);

    //
    // Since OEMIdle( ) is being called in the middle of a normal reschedule
    // period, CurMSec, dwPartialCurMSec, dwPartialDiffMSec and CurTicks need to be updated accordingly.
    //
    CPUGetSysTimerCountElapsed(SYSTEM_TICK_MS, pCurMSec, pDiffMSec, &dwPartialCurMSec, &dwPartialDiffMSec, pCurTicks);
    dwDiffMSecPrev = *pDiffMSec;

    //
    // Set the timer to wake up much later than usual, if needed.
    //
    CPUSetSysTimerCount(dwIdleMSec);
    CPUClearSysTimerIRQ( );

    //
    // Enable wakeup on any interrupt, then go to sleep.
    //
    CPUEnterIdle(dwIdleParam);
    INTERRUPTS_OFF( );
    
    //
    // We're awake! The wake-up ISR has already run.
    //
    if (dwDiffMSecPrev != *pDiffMSec) {
        //
        // We completed the full period we asked to sleep.  Update the counters.
        //
        *pCurMSec += (dwIdleMSec - SYSTEM_TICK_MS);     // Subtract SYSTEM_TICK_MS, because ISR also incremented.
        *pDiffMSec += (dwIdleMSec - SYSTEM_TICK_MS);
        CurTicks.QuadPart += (dwIdleMSec - SYSTEM_TICK_MS) * TIMER_COUNT;

        currIdle.QuadPart += dwIdleMSec;
    } else {
        //
        // Some other interrupt woke us up before the full idle period was
        // complete.  Determine how much time has elapsed.
        //
        currIdle.QuadPart += CPUGetSysTimerCountElapsed(dwIdleMSec, pCurMSec, pDiffMSec, &dwPartialCurMSec, &dwPartialDiffMSec, pCurTicks);
    }

    CPUSetSysTimerCount(SYSTEM_TICK_MS);
    CPUClearSysTimerIRQ( );

    // Update global idle time
    curridlelow = currIdle.LowPart;
    curridlehigh = currIdle.HighPart;

    return;
}

#else
// DougFir or later
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD CPUGetSysTimerCountElapsed (
    DWORD dwTimerCountdownMSec,
    volatile DWORD *pCurMSec,
    DWORD *pPartialCurMSec,
    volatile ULARGE_INTEGER *pCurTicks
    )
{
    // Using fixed tick, so do nothing and return 0 time passed
    return 0;
}

void
OEMIdle(
    DWORD dwIdleParam
    )
{
    DWORD dwIdleMSec;
    DWORD dwPrevMSec = CurMSec;

    // Use for 64-bit math
    ULARGE_INTEGER currIdle = {
        curridlelow,
        curridlehigh
    };

    if ((int) (dwIdleMSec = dwReschedTime - dwPrevMSec) <= 0) {
        // already time to wakeup
        return;
    }

    // just idle till tick if profiling or running iltiming
    if (bProfileTimerRunning || fIntrTime) {
        // idle till end of 'tick'
        CPUEnterIdle(dwIdleParam);

        // Update global idle time and return
        currIdle.QuadPart += SYSTEM_TICK_MS;
        curridlelow = currIdle.LowPart;
        curridlehigh = currIdle.HighPart;
        
        return;
    }

    //
    // Since OEMIdle( ) is being called in the middle of a normal reschedule
    // period, CurMSec, dwPartialCurMSec, and CurTicks need
    // to be updated accordingly.
    // Once we reach this point, we must re-program the timer (if we ever did) 
    // because dwPartialCurMSec will be modified in the next function call.
    //
    CPUGetSysTimerCountElapsed(SYSTEM_TICK_MS, &CurMSec, &dwPartialCurMSec, pCurTicks);

    if ((int) (dwIdleMSec -= CurMSec - dwPrevMSec) > 0) {

        dwPrevMSec = CurMSec;

        //
        // The system timer may not be capable of arbitrary timeouts. Get the
        // CPU-specific highest possible timeout available.
        //
        dwIdleMSec = CPUGetSysTimerCountMax(dwIdleMSec);
    
        //
        // Set the timer to wake up much later than usual, if needed.
        //
        CPUSetSysTimerCount(dwIdleMSec);
        CPUClearSysTimerIRQ( );
        
        //
        // Enable wakeup on any interrupt, then go to sleep.
        //
        CPUEnterIdle(dwIdleParam);
        INTERRUPTS_OFF( );
        
        //
        // We're awake! The wake-up ISR (or any other ISR) has already run.
        //
        if (dwPrevMSec != CurMSec) {
            //
            // We completed the full period we asked to sleep.  Update the counters.
            //
            CurMSec  += (dwIdleMSec - SYSTEM_TICK_MS); // Subtract resched period, because ISR also incremented.
            CurTicks.QuadPart += (dwIdleMSec - SYSTEM_TICK_MS) * TIMER_COUNT;

            currIdle.QuadPart += dwIdleMSec;
        } else {
            //
            // Some other interrupt woke us up before the full idle period was
            // complete.  Determine how much time has elapsed.
            //
            currIdle.QuadPart += CPUGetSysTimerCountElapsed(dwIdleMSec, &CurMSec, &dwPartialCurMSec, pCurTicks);
        }
    }

    // Re-arm counters
    CPUSetSysTimerCount(SYSTEM_TICK_MS);
    CPUClearSysTimerIRQ( );

    // Update global idle time
    curridlelow = currIdle.LowPart;
    curridlehigh = currIdle.HighPart;

    return;

}
#endif // CE_MAJOR_VER == 0x0003

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//
// SC_GetTickCount must take into account the partials to reflect where we really
// are in time AND IT SHOULD NOT MODIFY ANY OF THE GLOBALS.
//
DWORD SC_GetTickCount(void) 
{
#if (CE_MAJOR_VER == 0x0003)
    return CurMSec;
#else
    DWORD dwInc = 0, dwPartial = dwPartialCurMSec;
    ULARGE_INTEGER cdummy = {0, 0};
    CPUGetSysTimerCountElapsed(SYSTEM_TICK_MS, &dwInc, &dwPartial, &cdummy);
    return CurMSec + dwInc;
#endif
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?