This is code which must run on XP, so no GetTickCount64
, and which should correctly handle the value wrapping around after 49 days. Can it be improved?
// DWORD timeoutMs is a given parameter.
DWORD beginMs = (timeoutMs == INFINITE ? 0 : ::GetTickCount());
DWORD endMs = beginMs + timeoutMs; // unsigned arithmethic is Mod(MAX+1)
DWORD currentMs;
// Create Process, omitted for brevity
while ((waitResult = ::WaitForSingleObject(pi.hProcess, DEFAULT_WAIT_MS)) == WAIT_TIMEOUT)
{
if (timeoutMs != INFINITE)
{
bool timeoutReached = false;
currentMs = ::GetTickCount();
if (beginMs <= endMs) // normal case
{
if (currentMs > endMs)
{
timeoutReached = true;
}
}
else // special case: tick count wrapped around after 49 days uptime
{
if (currentMs < beginMs && currentMs > endMs)
{
timeoutReached = true;
}
}
if (timeoutReached)
{
::TerminateProcess(pi.hProcess, 0);
break;
}
}
}
1 Answer 1
Unsigned subtraction (and automatic mod 2^32) will always give currentMs - beginMs == elapsedMs
, even when beginMs > currentMs
, and as long as the actual elapsed time doesn't overflow the tick count (it isn't greater than 49 days).
So you could replace the original with the following code:
DWORD beginMs = GetTickCount();
// Create Process, omitted for brevity
while ((waitResult = WaitForSingleObject(pi.hProcess, DEFAULT_WAIT_MS)) == WAIT_TIMEOUT) {
if (timeoutMs != INFINITE) {
DWORD currentMs = GetTickCount();
bool timeoutReached = currentMs - beginMs > timeoutMs;
if (timeoutReached) {
TerminateProcess(pi.hProcess, 0);
break;
}
}
}
And you could even go a step further and eliminate the variables currentMs
and timeoutReached
: if (GetTickCount() - beginMs > timeoutMs) {...
waitResult = ::WaitForSingleObject(pi.hProcess, timeoutMs);
? Why use::GetTickCount()
at all? \$\endgroup\$QueryPerformanceCounter
functions? Are they also unavailable on XP? \$\endgroup\$