#include #include #include #include "dxwnd.h" #include "dxwcore.hpp" #define MAX_THREAD_ARRAY 40 // forward declarations BOOL SlowCpuSpeed(DWORD, DWORD, int); BOOL LimitCpuUsage(DWORD, DWORD, int); DWORD WINAPI CpuSlow(LPVOID lpThreadParameter) { int iSlowDownRatio = dxw.SlowRatio; DWORD dwOwnerPID = GetCurrentProcessId(); DWORD dwOwnerThread = GetCurrentThreadId(); OutTrace("starting CPUSlow dwOwnerPID=%x Ratio=1:%d\n", dwOwnerPID, iSlowDownRatio); if(!dwOwnerPID) return FALSE; if(iSlowDownRatio < 1) return FALSE; Sleep(100); while(TRUE) SlowCpuSpeed(dwOwnerPID, dwOwnerThread, iSlowDownRatio); return TRUE; } DWORD WINAPI CpuLimit(LPVOID lpThreadParameter) { int iSlowDownRatio = dxw.SlowRatio; DWORD dwOwnerPID = GetCurrentProcessId(); DWORD dwOwnerThread = GetCurrentThreadId(); OutTrace("starting CPULimit dwOwnerPID=%x Ratio=1:%d\n", dwOwnerPID, iSlowDownRatio); if(!dwOwnerPID) return FALSE; if(iSlowDownRatio < 1) return FALSE; return LimitCpuUsage(dwOwnerPID, dwOwnerThread, iSlowDownRatio); } BOOL SlowCpuSpeed(DWORD dwOwnerPID, DWORD dwOwnerThread, int iSlowDownRatio) { HANDLE hThreadSnap = INVALID_HANDLE_VALUE; THREADENTRY32 te32; HANDLE SuspThreads[MAX_THREAD_ARRAY]; int iThreadIndex, iNumThreads; // Take a snapshot of all running threads hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); if(hThreadSnap == INVALID_HANDLE_VALUE) { OutTrace("LimitCpuUsage: CreateToolhelp32Snapshot ERROR err=%d\n", GetLastError()); return FALSE; } // Fill in the size of the structure before using it. te32.dwSize = sizeof(THREADENTRY32); // Retrieve information about the first thread, and exit if unsuccessful if(!Thread32First(hThreadSnap, &te32)){ OutTrace("Thread32First ERROR: err=%d\n", GetLastError()); // Show cause of failure CloseHandle(hThreadSnap); // Must clean up the snapshot object! return FALSE; } // Now walk the thread list of the system, // and stop each low-priority thread iThreadIndex = 0; do { if( (te32.th32OwnerProcessID == dwOwnerPID) && (te32.th32ThreadID != dwOwnerThread) && (te32.tpBasePri < THREAD_PRIORITY_TIME_CRITICAL)) { HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID); SuspendThread(hThread); SuspThreads[iThreadIndex++] = hThread; } } while(Thread32Next(hThreadSnap, &te32) && (iThreadIndex *iNumThreads) *iNumThreads = iThreadIndex; } } } while(Thread32Next(hThreadSnap, &te32) && (*iNumThreads 100) cycle=0; // every 100 cyces forces a thread list refresh for(iThreadIndex=0; iThreadIndexDeltaUsed > (signed long)iTimeLimit) { #ifdef DEBUGTRACE OutTrace("Tid[%d]:%x delta=%d stopped at %d\n", iThreadIndex, t->tid, t->DeltaUsed, __LINE__); #endif if ((iResumeCount=SuspendThread(t->hThread))== -1) { t->tid = NULL; CloseHandle(t->hThread); continue; } t->Suspended = TRUE; t->DeltaUsed -= iTimeSlot; } } Sleep(iSlowDownRatio); for(iThreadIndex=0; iThreadIndextid == NULL) continue; // skip terminated ones if (t->Suspended) { #ifdef DEBUGTRACE OutTrace("Tid[%d]=%x delta=%d started at %d\n", iThreadIndex, t->tid, t->DeltaUsed, __LINE__); #endif if ((iResumeCount=ResumeThread(t->hThread))== -1) { t->tid = NULL; CloseHandle(t->hThread); continue; } t->Suspended = FALSE; t->DeltaUsed -= iTimeSlot; } else { if(!GetThreadTimes(t->hThread, &CreationTime, &ExitTime, &KernelTime, &UserTime)) { t->tid = NULL; CloseHandle(t->hThread); continue; } FILETIME tmp = t->LastUsed; t->LastUsed = FTFTSUM(UserTime, KernelTime); t->DeltaUsed = t->DeltaUsed + DWDIFF(t->LastUsed, tmp); #ifdef DEBUGTRACE OutTrace("Tid[%d]:%x delta=%d measured at %d\n", iThreadIndex, t->tid, t->DeltaUsed, __LINE__); #endif } } Sleep(1); } // should never go here, but in case, awake all suspended threads for(iThreadIndex=0; iThreadIndextid && t->Suspended) { ResumeThread(t->hThread); } } return TRUE; }