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\$
4
  • 1
    \$\begingroup\$ Why not just have waitResult = ::WaitForSingleObject(pi.hProcess, timeoutMs);? Why use ::GetTickCount() at all? \$\endgroup\$ Commented May 20, 2016 at 22:34
  • \$\begingroup\$ What about the QueryPerformanceCounter functions? Are they also unavailable on XP? \$\endgroup\$
    – glampert
    Commented May 21, 2016 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\$ Commented May 23, 2016 at 19:45
  • \$\begingroup\$ @glampert They are available, that would be another option. \$\endgroup\$ Commented May 30, 2016 at 23:05

1 Answer 1

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 and acknowledge you have read our privacy policy.

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