Merge pull request #55 from openweave/bug/szewczyk/wrmp-long-inactivity
Fix timeout computation for WRMP after long inactivity
diff --git a/src/lib/core/WeaveExchangeMgr.cpp b/src/lib/core/WeaveExchangeMgr.cpp
index e812fe9..cc357d4 100644
--- a/src/lib/core/WeaveExchangeMgr.cpp
+++ b/src/lib/core/WeaveExchangeMgr.cpp
@@ -1206,6 +1206,16 @@
uint32_t WeaveExchangeManager::GetTickCounterFromTimeDelta (uint64_t newTime,
uint64_t oldTime)
{
+ // Note on math: we have a utility function that will compute U64 var / U32
+ // compile-time const => U32. At the moment, we are leaving
+ // mWRMPTimerInterval as a member variable in WeaveExchangeManager, however,
+ // given its current usage, it could be replaced by a compile time const.
+ // Should we make that change, I would recommend making the timeDelta a u64,
+ // and replacing the plain 32-bit division below with the utility function.
+ // Note that the 32bit timeDelta overflows at around 46 days; pursuing the
+ // above code strategy would extend that overflow by a factor if 200 given
+ // the default mWRMPPTimerInterval. If and when such change is made, please
+ // update the comment around line 1426.
uint32_t timeDelta = static_cast<uint32_t>(newTime - oldTime);
return (timeDelta / mWRMPTimerInterval);
@@ -1334,7 +1344,7 @@
{
uint64_t now = 0;
ExchangeContext* ec = NULL;
- uint16_t deltaTicks;
+ uint32_t deltaTicks;
//Process Ack Tables for all ExchangeContexts
ec = (ExchangeContext *)ContextPool;
@@ -1345,8 +1355,14 @@
// to the previous tick. If we are between tick boundaries, the extra time since the
// last virtual tick is not accounted for here (it will be accounted for when resetting
// the WRMP timer)
+
deltaTicks = GetTickCounterFromTimeDelta(now, mWRMPTimeStampBase);
+ // Note on math involving deltaTicks: in the code below, deltaTicks, a
+ // 32-bit value, is being subtracted from 16-bit expiration times. In each
+ // case, we compare the expiration time prior to subtraction to guard
+ // against underflow.
+
#if defined(WRMP_TICKLESS_DEBUG)
WeaveLogProgress(ExchangeManager, "WRMPExpireTicks at %" PRIu64 ", %" PRIu64 ", %u", now, mWRMPTimeStampBase, deltaTicks);
#endif
@@ -1408,11 +1424,15 @@
// Re-Adjust the base time stamp to the most recent tick boundary
- // Note on math: because we're really multiplying two 16-bit
- // unsigned numbers, we know that the result will fit in a 32-bit
- // unsigned without overflow. Consequently, casting operands to
- // 32-bit, and performing 32-bit multiplication is correct.
- mWRMPTimeStampBase += static_cast<uint64_t>( static_cast<uint32_t>(deltaTicks) * static_cast<uint32_t>(mWRMPTimerInterval));
+ // Note on math: we cast deltaTicks to a 64bit value to ensure that that we
+ // produce a full 64 bit product. At the moment this is a bit of a moot
+ // conversion: right now, the math in GetTickCounterFromTimeDelta ensures
+ // that the deltaTicks * mWRMPTimerTick fits in 32bits. However, I'm
+ // leaving the math in this form, because I'm leaving the door open to
+ // refactoring the division in GetTickCounterFromTimeDelta to use our
+ // specialized utility function that computes U64 var/ U32 compile-time
+ // const ==> U32
+ mWRMPTimeStampBase += static_cast<uint64_t>(deltaTicks) * mWRMPTimerInterval;
#if defined(WRMP_TICKLESS_DEBUG)
WeaveLogProgress(ExchangeManager, "WRMPExpireTicks mWRMPTimeStampBase to %" PRIu64, mWRMPTimeStampBase);
#endif