os/boardsupport/emulator/emulatorbsp/specific/timer.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // wins\specific\timer.cpp
    15 // 
    16 //
    17 
    18 #include "variant.h"
    19 
    20 #define KWinsTimerPanicCategory "WinsTimer"
    21 
    22 enum TWinsTimerPanic
    23 	{
    24 	EReleaseSemaphoreError = 1,
    25 	ETimeSetEventError = 2
    26 	};
    27 
    28 void PanicFromWinsTimer(TWinsTimerPanic aReason)
    29 	{
    30 	Kern::Fault(KWinsTimerPanicCategory, aReason);
    31 	}
    32 
    33 
    34 
    35 inline Int64 FileTime2Milliseconds(const FILETIME& aFileTime)
    36 	{return ((Int64(aFileTime.dwHighDateTime)<<32) + aFileTime.dwLowDateTime)/10000;}
    37 
    38 
    39 void CALLBACK WinsTimer::Tick(UINT, UINT, DWORD aPtr, DWORD, DWORD) 
    40 	{
    41 
    42 	WinsTimer& timer=*(WinsTimer*)aPtr;
    43 	if (!ReleaseSemaphore(timer.iSemaphore,1,NULL))
    44 		{
    45 		__ASSERT_ALWAYS((GetLastError() == ERROR_TOO_MANY_POSTS), PanicFromWinsTimer(EReleaseSemaphoreError));
    46 		timeKillEvent(timer.iTimer);
    47 		// If WinsTimer::EventThread() has run since the above call to
    48 		// ReleaseSemaphore() (this has been observed to happen while 
    49 		// within the call to timeKillEvent()) then the semaphore may be 
    50 		// signallable again. If it is, restart the timer otherwise wait 
    51 		// for the event thread to restart it.
    52 		if (ReleaseSemaphore(timer.iSemaphore,1,NULL))
    53 			timer.Enable();
    54 		else
    55 			timer.iSuspend = timer.iMaxLagTicks;
    56 		}
    57 	}
    58 
    59 DWORD WINAPI WinsTimer::Thread(LPVOID aPtr)
    60 	{
    61 	static_cast<WinsTimer*>(aPtr)->EventThread(*(NTimerQ*)NTimerQ::TimerAddress());
    62 	return 0;
    63 	}
    64 
    65 void WinsTimer::EventThread(NTimerQ& aTimerQ)
    66 	{
    67 	for (;;)
    68 		{
    69 		WaitForSingleObject(iSemaphore,INFINITE);
    70 		if (iSuspend > 0)
    71 			{
    72 			// Emulator interrupted/suspended for too long, MM-callback has been suspended
    73 			//
    74 			// Rather than try and catch up now, just discard the lost ticks - this improves
    75 			// system behaviour particularly when debugging at the expense of losing sync
    76 			// between the Windows clock and the emulator RTC.
    77 			//
    78 			while (--iSuspend > 0)
    79 				WaitForSingleObject(iSemaphore, 0);	// absorb all signals
    80 			//
    81 			// un-nobble once we are debugging
    82 			if (iNobbleNanos && IsDebuggerPresent())
    83 				iNobbleNanos = 0;
    84 			//
    85 			// now restart the timer callbacks
    86 			Enable();
    87 			//
    88 			// don't deliver a tick until next callback
    89 			continue;
    90 			}
    91 		if (iNobbleNanos && iIdleThread != NKern::CurrentThread())
    92 			Kern::NanoWait(iNobbleNanos);
    93 		StartOfInterrupt();
    94 		iTime += iPeriod;
    95 		if (!iStandby)
    96 			aTimerQ.Tick();
    97 		EndOfInterrupt();
    98 		}
    99 	}
   100 
   101 
   102 WinsTimer::WinsTimer()
   103 	:iPeriod(0),iNobbleNanos(0),iMaxLagTicks(0),iSemaphore(NULL),iSuspend(0),iTime(0),iIdleThread(0)
   104 	{}
   105 
   106 void WinsTimer::Init(TUint aPeriod)
   107 	{
   108 	// calculate the y2k offset in seconds from Win32 'zero' FILETIME
   109 	// This initially synchronizes EPOC time with Windows time
   110 	const SYSTEMTIME KSystemTimeY2K = {2000,1,0,1,0,0,0,0};
   111 	FILETIME y2k, now;
   112 	SystemTimeToFileTime(&KSystemTimeY2K,&y2k);
   113 	GetSystemTimeAsFileTime(&now);
   114 	iTime = FileTime2Milliseconds(now) - FileTime2Milliseconds(y2k);
   115 
   116 	TIMECAPS caps;
   117 	timeGetDevCaps(&caps,sizeof(caps));
   118 
   119 	iPeriod = min(caps.wPeriodMax, max(caps.wPeriodMin, aPeriod));
   120 	TUint resolution = max(caps.wPeriodMin, iPeriod/2);
   121 	iMaxLagTicks = EMaxLag / iPeriod;
   122 
   123 	// limit 'catch-up' for when Win32 gets too busy for us to fire timer events
   124 	// making this too large causes delays when resuming from debug
   125 	iSemaphore = CreateSemaphoreA(NULL, 0, iMaxLagTicks, NULL);
   126 
   127 	timeBeginPeriod(resolution);
   128 
   129 	CreateWin32Thread(EThreadEvent, &WinsTimer::Thread, this, ETrue);
   130 	}
   131 
   132 void WinsTimer::Enable()
   133 	{
   134 	iTimer = timeSetEvent(iPeriod,0,&WinsTimer::Tick,DWORD(this),TIME_PERIODIC);
   135 	__ASSERT_ALWAYS(iTimer != NULL, PanicFromWinsTimer(ETimeSetEventError));
   136 	}
   137 
   138 TInt WinsTimer::SystemTime() const
   139 //
   140 // Return the time in seconds since y2k
   141 //
   142 	{
   143 	TInt irq = NKern::DisableAllInterrupts();
   144 	Int64 time = iTime;
   145 	NKern::RestoreInterrupts(irq);
   146 	if (time < 0)
   147 		time -= 999;	// we want rounding to -infinity for the division
   148 	return TInt(time/1000);
   149 	}
   150 
   151 void WinsTimer::SetSystemTime(TInt aTime)
   152 //
   153 // Set the time in seconds since y2k
   154 //
   155 	{
   156 	Int64 time=aTime;
   157 	time*=1000;
   158 	TInt irq = NKern::DisableAllInterrupts();
   159 	iTime = time;
   160 	NKern::RestoreInterrupts(irq);
   161 	}
   162 
   163 void WinsTimer::Standby()
   164 	{
   165 	iStandby = ETrue;
   166 	}
   167 
   168 void WinsTimer::Wakeup()
   169 	{
   170 	iStandby = EFalse;
   171 	// Busy wait for the next timer interrupt 
   172 	volatile Int64* t = &iTime;
   173 	Int64 time = *t;
   174 	while (time == *t)
   175 		{}
   176 	}