#ifndef __ACCURATE_TIMER_H__ #define __ACCURATE_TIMER_H__ #pragma warning ( disable : 4786 ) #include #include #include #include #include #include #include "mmsystem.h" using namespace std; //------------------------------------------------------------------- // this timer class was designed to give high precision < 2% average // error and it was designed to work best with multi-threaded clients // waiting on the single instance of this timer // class AccurateTimer { public: static AccurateTimer* Instance() { return &instance; }; virtual ~AccurateTimer() { timeKillEvent(timer), timer = 0; DeleteCriticalSection(&crit); } /////////////////////////////////////////////////////////////// // Function name : Wait // Description : Timer wait method // : // Return type : void : // Argument : int timeout : /////////////////////////////////////////////////////////////// void Wait(int timeout) { //#define TIMING_DEBUG #ifdef TIMING_DEBUG LARGE_INTEGER s[2]; QueryPerformanceCounter(&s[0]); // timing starts #endif if ( timeout > 0 ) // anything to wait on ? { HANDLE tHandle = 0; HANDLE pHandle = GetCurrentProcess(); DuplicateHandle(pHandle, GetCurrentThread(), pHandle, &tHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); HANDLE WaitEvent; WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); ResetEvent(WaitEvent); CTrigger Trg; Trg.InsertTrigger(WaitEvent); // wrap pool data access EnterCriticalSection(&AccurateTimer::Instance()->crit); waitPool.push_back(WaitData(tHandle, WaitEvent, timeout)); LeaveCriticalSection(&AccurateTimer::Instance()->crit); //SuspendThread(tHandle); // do the wait Trg.Wait(); CloseHandle(tHandle); } #ifdef TIMING_DEBUG QueryPerformanceCounter(&s[1]); // wake up call and timing ends double diff = ((double)s[1].QuadPart - (double)s[0].QuadPart)/(double)freq.QuadPart; double percent = /*Absolute*/(diff-timeout)*100.0/(timeout?timeout:1); TRACE("intended to sleep for: %3ld. slept for: %8.4f. error = %8.4f\n", timeout, diff, percent); error += percent; ++count; #endif } inline double Absolute(double val) { return val > 0 ? val : -val; } inline LARGE_INTEGER GetFrequency() { return freq; }; /////////////////////////////////////////////////////////////// // Function name : CALLBACK TimerFunc // Description : Media callback timer method // : // Return type : static void : // Argument : UINT uID : // Argument : UINT uMsg : // Argument : DWORD dwUser : // Argument : DWORD dw1 : // Argument : DWORD dw2 : /////////////////////////////////////////////////////////////// static void CALLBACK TimerFunc(UINT /*uID*/, UINT /*uMsg*/, DWORD_PTR dwUser, DWORD_PTR /*dw1*/, DWORD_PTR /*dw2*/) { static LARGE_INTEGER s[2]; static bool init = true; if ( !init ) { init = true; HANDLE tHandle = 0; HANDLE pHandle = GetCurrentProcess(); DuplicateHandle(pHandle, GetCurrentThread(), pHandle, &tHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); SetThreadPriority(tHandle, THREAD_PRIORITY_TIME_CRITICAL); HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _getpid()); if (!SetPriorityClass(h, REALTIME_PRIORITY_CLASS)) { DWORD err = GetLastError(); TRACE("SetPriorityClass Error: %d.\n", err); } CloseHandle(h); CloseHandle(tHandle); } AccurateTimer* pThis = reinterpret_cast(dwUser); QueryPerformanceCounter(&s[1]); //double diff = (((double)s[1].QuadPart - (double)s[0].QuadPart)/(double)pThis->freq.QuadPart); __int64 now = s[1].QuadPart/*+pThis->halfMsec.QuadPart*/; EnterCriticalSection(&pThis->crit); deque::iterator it = pThis->waitPool.begin(); while ( it != pThis->waitPool.end() ) { if ( now >= it->timeout.QuadPart ) { //ResumeThread(it->h); SetEvent(it->eventHandle); it = pThis->waitPool.erase(it); continue; } ++it; } LeaveCriticalSection(&pThis->crit); s[0] = s[1]; } volatile static double error; volatile static int count; private: AccurateTimer() { error = 0; count = 0; QueryPerformanceFrequency(&freq); halfMsec.QuadPart = freq.QuadPart / 2000; freq.QuadPart /= 1000; // convert to msecs InitializeCriticalSection(&crit); timer = timeSetEvent(UINT(1), UINT(0), TimerFunc, (DWORD_PTR)this, (UINT)TIME_PERIODIC); } struct WaitData { WaitData(HANDLE _h, HANDLE _evtH, int _t) : h(_h), eventHandle(_evtH) { LARGE_INTEGER now; QueryPerformanceCounter(&now); timeout.QuadPart = _t * AccurateTimer::Instance()->freq.QuadPart + now.QuadPart; }; HANDLE h; HANDLE eventHandle; LARGE_INTEGER timeout; }; friend struct WaitData; static AccurateTimer instance; CRITICAL_SECTION crit; deque waitPool; MMRESULT timer; LARGE_INTEGER freq; LARGE_INTEGER halfMsec; }; #endif // __ACCURATE_TIMER_H__