--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emulator/emulatorbsp/specific/timer.cpp Tue Feb 02 01:39:10 2010 +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<WinsTimer*>(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