3
\$\begingroup\$

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;
        }
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Why not just have waitResult = ::WaitForSingleObject(pi.hProcess, timeoutMs);? Why use ::GetTickCount() at all? \$\endgroup\$ – ncalmbeblpaicr0011 May 20 '16 at 22:34
  • \$\begingroup\$ What about the QueryPerformanceCounter functions? Are they also unavailable on XP? \$\endgroup\$ – glampert May 21 '16 at 3:43
  • \$\begingroup\$ @ncalmbeblpaicr0011 to be able to call a callback function in the loop and do other things like copy the standard output stream while the program is running. \$\endgroup\$ – Felix Dombek May 23 '16 at 19:45
  • \$\begingroup\$ @glampert They are available, that would be another option. \$\endgroup\$ – Felix Dombek May 30 '16 at 23:05
1
\$\begingroup\$

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) {...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.