I came across a timeout function in a product line code which get me really confused:
int TestTimeOut(unsigned long Timed_Val1, unsigned long Timed_Val2)
{
Timed_Val2 = Timed_Val1 + (Timed_Val2 * 200);
if (((Timed_Val1 > Timed_Val2) && (sys_msec < Timed_Val1) && (sys_msec > Timed_Val2)) || ((Timed_Val1 < Timed_Val2) && ((sys_msec < Timed_Val1) || (sys_msec > Timed_Val2))))
return TRUE;
return FALSE;
}
And here is how it's used:
unsigned long Timeout = sys_msec;
#define MAX_TIMEOUT 15L
while (!com_eot(1)) //to check if some transmission in progress in COM1
if (TestTimeOut(Timeout, MAX_TIMEOUT))
return FALSE;
return TRUE;
How does it work? I am totally confused by the 3 lines in TestTimeOut().
The reason for the somewhat complex check is because of the possibility of integer rollover. If that happens, then it needs the two parts of the check. A specific example might help. If, for example, a long is 32-bits on this system, and the initial value of
Timed_Val1
is 2^32-100 = 4294967196, thenTimed_Val2
would be computed as 2900. So it is that type of situation that requires this part of the check:In that situation, the timeout occurs when
sys_msec
is between val1 and val2. It needs to be greater than 2900 and less than 4294967196.The other half of the condition is the "normal" situation when there is no rollover in the computation of
Timed_Val2
:In that case, the timeout occurs when
sys_msec
is greater than val2 OR when it has rolled over and is, thus, less than val1.The chosen variable names are definitely poor, though. It would make sense to rename them.
First I refactor out
a
andb
local variables.Now this is interesting,
Timed_Val2
is based onTimed_Val1
, they are bothunsigned
soTimed_Val2
is always>= Timed_Val1
. At first I could not see no waya
can be true, but as Mark Wilkins points out, it could if it wraps around.There's also only 1 case where they are equal however, that is when
Timed_Val2==0
I'm going to extract that out as a special case to help readability. I can then factor out the two>
/<
statements into anif
.So I would say this returns true iff (if and only if)
sys_msec
is beforeTimed_Val1
or afterTimed_Val1 + Timed_Val2 * 0.2 seconds
.As a final stage, now I would rename the variables and comment it.
That's not to say there's not a better way of doing this, but at least it's readable now.