void doneTiming() { // terminate "stuck" thread SetEvent(endStuckEvent); Real_WaitForSingleObject(stuckThread,500); CloseHandle(stuckThread); CloseHandle(stuckTimer); // make sure all currently active waits are finished ResetEvent(resyncEvent); SetEvent(nextFrameEvent); if(waitCounter) ResetEvent(noOneWaiting); else SetEvent(noOneWaiting); while(Real_WaitForSingleObject(noOneWaiting,5) == WAIT_TIMEOUT) if(!waitCounter) break; // these functions depend on critical sections that we're about to delete. UnhookFunction(&Real_timeSetEvent); UnhookFunction(&Real_timeKillEvent); UnhookFunction(&Real_SetTimer); EnterCriticalSection(&TimerAllocLock); LeaveCriticalSection(&TimerAllocLock); DeleteCriticalSection(&TimerAllocLock); EnterCriticalSection(&TimerSeedLock); TimersSeeded = true; LeaveCriticalSection(&TimerSeedLock); DeleteCriticalSection(&TimerSeedLock); // we have to remove those, because code we call on deinitilization (especially directshow related) // might be using them. UnhookFunction(&Real_Sleep); UnhookFunction(&Real_WaitForSingleObject); UnhookFunction(&Real_WaitForMultipleObjects); UnhookFunction(&Real_MsgWaitForMultipleObjects); CloseHandle(nextFrameEvent); CloseHandle(resyncEvent); CloseHandle(noOneWaiting); CloseHandle(endStuckEvent); int runTime = Real_timeGetTime() - realStartTime; timeEndPeriod(1); if(runTime) { int rate = MulDiv(currentFrame,100*1000,runTime); printLog("timing: %d.%02d frames per second on average\n",rate/100,rate%100); } }
DWORD __stdcall Mine_MsgWaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles,BOOL bWaitAll,DWORD dwMilliseconds,DWORD dwWakeMask) { // infinite waits are always passed through if(dwMilliseconds >= 0x7fffffff) return Real_MsgWaitForMultipleObjects(nCount,lpHandles,bWaitAll,dwMilliseconds,dwWakeMask); else { // waitalls are harder to fake, so we just clamp them to timeout 0. if(bWaitAll) return Real_MsgWaitForMultipleObjects(nCount,lpHandles,TRUE,0,dwWakeMask); else { // we can't use new/delete, this might be called from a context // where they don't work (such as after clib deinit) HANDLE *handles = (HANDLE *) _alloca((nCount + 1) * sizeof(HANDLE)); memcpy(handles,lpHandles,nCount*sizeof(HANDLE)); handles[nCount] = nextFrameEvent; Real_WaitForSingleObject(resyncEvent,INFINITE); IncrementWaiting(); DWORD result = Real_MsgWaitForMultipleObjects(nCount+1,handles,FALSE,dwMilliseconds,dwWakeMask); if(result == WAIT_OBJECT_0+nCount) result = WAIT_TIMEOUT; DecrementWaiting(); return result; } } }
VOID __stdcall Mine_Sleep(DWORD dwMilliseconds) { if(dwMilliseconds) { Real_WaitForSingleObject(resyncEvent,INFINITE); IncrementWaiting(); if(params.MakeSleepsLastOneFrame) Real_WaitForSingleObject(nextFrameEvent,dwMilliseconds); else Real_WaitForSingleObject(nextFrameEvent,params.SleepTimeout); DecrementWaiting(); } else Real_Sleep(0); }
DWORD __stdcall Mine_WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds) { if(dwMilliseconds <= 0x7fffffff) { Real_WaitForSingleObject(resyncEvent,INFINITE); IncrementWaiting(); HANDLE handles[] = { hHandle, nextFrameEvent }; DWORD result = Real_WaitForMultipleObjects(2,handles,FALSE,dwMilliseconds); DecrementWaiting(); if(result == WAIT_OBJECT_0+1) result = WAIT_TIMEOUT; return result; } else return Real_WaitForSingleObject(hHandle,dwMilliseconds); }
DWORD __stdcall My_WaitForSingleObject(HANDLE a0,DWORD a1) { if( calledFromSC() ){ AddAddr( SCOffset() ); LogAPI("WaitForSingleObject(%x,%x)\n", a0, a1); } DWORD ret = 0; try { ret = Real_WaitForSingleObject(a0, a1); } catch(...){ } return ret; }
void nextFrameTiming() { ResetEvent(resyncEvent); SetEvent(nextFrameEvent); if(waitCounter) ResetEvent(noOneWaiting); else SetEvent(noOneWaiting); while(Real_WaitForSingleObject(noOneWaiting,5) == WAIT_TIMEOUT) if(!waitCounter) break; ResetEvent(nextFrameEvent); SetEvent(resyncEvent); DWORD oldFrameTime = UMulDiv(currentFrame,1000*frameRateDenom,frameRateScaled); DWORD newFrameTime = UMulDiv(currentFrame+1,1000*frameRateDenom,frameRateScaled); ProcessEventTimers(newFrameTime - oldFrameTime); if(!currentFrame) realStartTime = Real_timeGetTime(); if(params.EnableAutoSkip) { LARGE_INTEGER due; due.QuadPart = -10*1000*__int64(params.FrameTimeout); SetWaitableTimer(stuckTimer,&due,0,0,0,FALSE); } if(exitNextFrame) { printLog("main: clean exit requested, doing my best...\n"); ExitProcess(0); } // make sure there's always a message in the queue for next frame // (some old hjb intros stop when there's no new messages) PostMessage(GetForegroundWindow(),WM_NULL,0,0); currentFrame++; timerHammeringCounter = 0; }