diff -r 000000000000 -r bde4ae8d615e os/boardsupport/emulator/emulatorbsp/specific/timer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/boardsupport/emulator/emulatorbsp/specific/timer.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,176 @@ +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// wins\specific\timer.cpp +// +// + +#include "variant.h" + +#define KWinsTimerPanicCategory "WinsTimer" + +enum TWinsTimerPanic + { + EReleaseSemaphoreError = 1, + ETimeSetEventError = 2 + }; + +void PanicFromWinsTimer(TWinsTimerPanic aReason) + { + Kern::Fault(KWinsTimerPanicCategory, aReason); + } + + + +inline Int64 FileTime2Milliseconds(const FILETIME& aFileTime) + {return ((Int64(aFileTime.dwHighDateTime)<<32) + aFileTime.dwLowDateTime)/10000;} + + +void CALLBACK WinsTimer::Tick(UINT, UINT, DWORD aPtr, DWORD, DWORD) + { + + WinsTimer& timer=*(WinsTimer*)aPtr; + if (!ReleaseSemaphore(timer.iSemaphore,1,NULL)) + { + __ASSERT_ALWAYS((GetLastError() == ERROR_TOO_MANY_POSTS), PanicFromWinsTimer(EReleaseSemaphoreError)); + timeKillEvent(timer.iTimer); + // If WinsTimer::EventThread() has run since the above call to + // ReleaseSemaphore() (this has been observed to happen while + // within the call to timeKillEvent()) then the semaphore may be + // signallable again. If it is, restart the timer otherwise wait + // for the event thread to restart it. + if (ReleaseSemaphore(timer.iSemaphore,1,NULL)) + timer.Enable(); + else + timer.iSuspend = timer.iMaxLagTicks; + } + } + +DWORD WINAPI WinsTimer::Thread(LPVOID aPtr) + { + static_cast(aPtr)->EventThread(*(NTimerQ*)NTimerQ::TimerAddress()); + return 0; + } + +void WinsTimer::EventThread(NTimerQ& aTimerQ) + { + for (;;) + { + WaitForSingleObject(iSemaphore,INFINITE); + if (iSuspend > 0) + { + // Emulator interrupted/suspended for too long, MM-callback has been suspended + // + // Rather than try and catch up now, just discard the lost ticks - this improves + // system behaviour particularly when debugging at the expense of losing sync + // between the Windows clock and the emulator RTC. + // + while (--iSuspend > 0) + WaitForSingleObject(iSemaphore, 0); // absorb all signals + // + // un-nobble once we are debugging + if (iNobbleNanos && IsDebuggerPresent()) + iNobbleNanos = 0; + // + // now restart the timer callbacks + Enable(); + // + // don't deliver a tick until next callback + continue; + } + if (iNobbleNanos && iIdleThread != NKern::CurrentThread()) + Kern::NanoWait(iNobbleNanos); + StartOfInterrupt(); + iTime += iPeriod; + if (!iStandby) + aTimerQ.Tick(); + EndOfInterrupt(); + } + } + + +WinsTimer::WinsTimer() + :iPeriod(0),iNobbleNanos(0),iMaxLagTicks(0),iSemaphore(NULL),iSuspend(0),iTime(0),iIdleThread(0) + {} + +void WinsTimer::Init(TUint aPeriod) + { + // calculate the y2k offset in seconds from Win32 'zero' FILETIME + // This initially synchronizes EPOC time with Windows time + const SYSTEMTIME KSystemTimeY2K = {2000,1,0,1,0,0,0,0}; + FILETIME y2k, now; + SystemTimeToFileTime(&KSystemTimeY2K,&y2k); + GetSystemTimeAsFileTime(&now); + iTime = FileTime2Milliseconds(now) - FileTime2Milliseconds(y2k); + + TIMECAPS caps; + timeGetDevCaps(&caps,sizeof(caps)); + + iPeriod = min(caps.wPeriodMax, max(caps.wPeriodMin, aPeriod)); + TUint resolution = max(caps.wPeriodMin, iPeriod/2); + iMaxLagTicks = EMaxLag / iPeriod; + + // limit 'catch-up' for when Win32 gets too busy for us to fire timer events + // making this too large causes delays when resuming from debug + iSemaphore = CreateSemaphoreA(NULL, 0, iMaxLagTicks, NULL); + + timeBeginPeriod(resolution); + + CreateWin32Thread(EThreadEvent, &WinsTimer::Thread, this, ETrue); + } + +void WinsTimer::Enable() + { + iTimer = timeSetEvent(iPeriod,0,&WinsTimer::Tick,DWORD(this),TIME_PERIODIC); + __ASSERT_ALWAYS(iTimer != NULL, PanicFromWinsTimer(ETimeSetEventError)); + } + +TInt WinsTimer::SystemTime() const +// +// Return the time in seconds since y2k +// + { + TInt irq = NKern::DisableAllInterrupts(); + Int64 time = iTime; + NKern::RestoreInterrupts(irq); + if (time < 0) + time -= 999; // we want rounding to -infinity for the division + return TInt(time/1000); + } + +void WinsTimer::SetSystemTime(TInt aTime) +// +// Set the time in seconds since y2k +// + { + Int64 time=aTime; + time*=1000; + TInt irq = NKern::DisableAllInterrupts(); + iTime = time; + NKern::RestoreInterrupts(irq); + } + +void WinsTimer::Standby() + { + iStandby = ETrue; + } + +void WinsTimer::Wakeup() + { + iStandby = EFalse; + // Busy wait for the next timer interrupt + volatile Int64* t = &iTime; + Int64 time = *t; + while (time == *t) + {} + } \ No newline at end of file