[instance] single OpenThread instance optimizations (#1926)

This commit new configuration option `enable-multiple-instances` and
its corresponding option `OPENTHREAD_ENABLE_MULTIPLE_INSTANCES`. When
enabled OpenThread supports handling of multiple instances. By default
this is disabled.

This commit also adds two optimizations for single instance case to
simplify the code and also help reduce memory/RAM usage:

(1) OpenThread objects/classes typically keep a reference to a higher
level object (e.g., many classes keep track of owning `ThreadNetif`)
to be able to access other objects/methods within OpenThread class
hierarchy. In single instance mode, the reference member variables are
removed and instead global functions are used to access the singleton
objects from one class to the other. To implement this, a group of
`<Object>Locator` classes are defined (e.g., `ThreadNetifLocator`,
etc.) which are then used as base class of other OpenThread classes.

(2) OpenThread objects which provide a callback/handler (e.g.,
`Timer`, `Tasklet`, etc.) have `void *mContext` member variable which
is used to keep track of the owner of the object. In single instance
mode the `mConext` member variables are removed since the owner is
expected to be a singleton and can be uniquely determined from the
callback function.

To implement this, two changes are made: First the handler methods are
modified to provide a reference to the object (e.g., `Timer` handler
will provide a `Timer &aTimer` as a parameter of its handler
callback). Second, a new base class `Context` is introduced which
hides the implementation providing an arbitrary context information. A
new static method `GetOwner(aContext)` is added to classes which own a
callback providing objects. This method help convert a `Context` to
the reference of the owner class object.
This commit is contained in:
Abtin Keshavarzian
2017-06-30 11:48:26 -07:00
committed by Jonathan Hui
parent 5128602b49
commit bbab3074ed
143 changed files with 2932 additions and 1831 deletions
+72 -48
View File
@@ -78,15 +78,34 @@ void InitCounters(void)
memset(sCallCount, 0, sizeof(sCallCount));
}
void TestTimerHandler(void *aContext)
/**
* `TestTimer` sub-classes `ot::Timer` and provides a handler and a counter to keep track of number of times timer gets
* fired.
*/
class TestTimer: public ot::Timer
{
sCallCount[kCallCountIndexTimerHandler]++;
public:
TestTimer(otInstance *aInstance):
ot::Timer(aInstance->mIp6.mTimerScheduler, TestTimer::HandleTimerFired, NULL),
mFiredCounter(0)
{ }
if (aContext)
{
(*static_cast<uint32_t *>(aContext))++;
static void HandleTimerFired(ot::Timer &aTimer) {
static_cast<TestTimer &>(aTimer).HandleTimerFired();
}
}
void HandleTimerFired(void) {
sCallCount[kCallCountIndexTimerHandler]++;
mFiredCounter++;
}
uint32_t GetFiredCounter(void) { return mFiredCounter; }
void ResetFiredCounter(void) { mFiredCounter = 0; }
private:
uint32_t mFiredCounter; //< Number of times timer has been fired so far
};
/**
* Test the TimerScheduler's behavior of one timer started and fired.
@@ -95,8 +114,8 @@ int TestOneTimer(void)
{
const uint32_t kTimeT0 = 1000;
const uint32_t kTimerInterval = 10;
otInstance aInstance;
ot::Timer timer(aInstance.mIp6.mTimerScheduler, TestTimerHandler, NULL);
otInstance *instance = testInitInstance();
TestTimer timer(instance);
// Test one Timer basic operation.
@@ -117,7 +136,7 @@ int TestOneTimer(void)
sNow += kTimerInterval;
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "TestOneTimer: Start CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "TestOneTimer: Stop CallCount Failed.\n");
@@ -141,7 +160,7 @@ int TestOneTimer(void)
sNow += kTimerInterval;
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "TestOneTimer: Start CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "TestOneTimer: Stop CallCount Failed.\n");
@@ -165,7 +184,7 @@ int TestOneTimer(void)
sNow += kTimerInterval + 5;
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "TestOneTimer: Start CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "TestOneTimer: Stop CallCount Failed.\n");
@@ -189,7 +208,7 @@ int TestOneTimer(void)
sNow += kTimerInterval - 2;
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "TestOneTimer: Start CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "TestOneTimer: Stop CallCount Failed.\n");
@@ -199,7 +218,7 @@ int TestOneTimer(void)
sNow += kTimerInterval;
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "TestOneTimer: Start CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "TestOneTimer: Stop CallCount Failed.\n");
@@ -209,6 +228,8 @@ int TestOneTimer(void)
printf(" --> PASSED\n");
testFreeInstance(instance);
return 0;
}
@@ -219,10 +240,9 @@ int TestTwoTimers(void)
{
const uint32_t kTimeT0 = 1000;
const uint32_t kTimerInterval = 10;
otInstance aInstance;
uint32_t timerContextHandleCounter[2] = {0};
ot::Timer timer1(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[0]);
ot::Timer timer2(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[1]);
otInstance *instance = testInitInstance();
TestTimer timer1(instance);
TestTimer timer2(instance);
InitTestTimer();
printf("TestTwoTimers() ");
@@ -230,7 +250,6 @@ int TestTwoTimers(void)
// Test when second timer stars at the fire time of first timer (before alarm callback).
InitCounters();
memset(timerContextHandleCounter, 0, sizeof(timerContextHandleCounter));
sNow = kTimeT0;
timer1.Start(kTimerInterval);
@@ -255,24 +274,24 @@ int TestTwoTimers(void)
VerifyOrQuit(timer2.IsRunning() == true, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(sTimerOn, "TestTwoTimers: Platform Timer State Failed.\n");
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "TestTwoTimers: Start CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "TestTwoTimers: Stop CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "TestTwoTimers: Handler CallCount Failed.\n");
VerifyOrQuit(timerContextHandleCounter[0] == 1, "TestTwoTimers: Context handler failed.\n");
VerifyOrQuit(sPlatT0 == sNow && sPlatDt == kTimerInterval, "TestTwoTimers: Start params Failed.\n");
VerifyOrQuit(timer1.GetFiredCounter() == 1, "TestTwoTimers: Fire Counter failed.\n");
VerifyOrQuit(sPlatT0 == sNow && sPlatDt == kTimerInterval, "TestTwoTimers: Start params Failed.\n");
VerifyOrQuit(timer1.IsRunning() == false, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(timer2.IsRunning() == true, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(sTimerOn == true, "TestTwoTimers: Platform Timer State Failed.\n");
sNow += kTimerInterval;
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "TestTwoTimers: Start CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "TestTwoTimers: Stop CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 2, "TestTwoTimers: Handler CallCount Failed.\n");
VerifyOrQuit(timerContextHandleCounter[1] == 1, "TestTwoTimers: Context handler failed.\n");
VerifyOrQuit(timer2.GetFiredCounter() == 1, "TestTwoTimers: Fire Counter failed.\n");
VerifyOrQuit(timer1.IsRunning() == false, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(timer2.IsRunning() == false, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(sTimerOn == false, "TestTwoTimers: Platform Timer State Failed.\n");
@@ -281,7 +300,8 @@ int TestTwoTimers(void)
// is before the first timer. Ensure that the second timer handler is invoked before the first one.
InitCounters();
memset(timerContextHandleCounter, 0, sizeof(timerContextHandleCounter));
timer1.ResetFiredCounter();
timer2.ResetFiredCounter();
sNow = kTimeT0;
timer1.Start(kTimerInterval);
@@ -303,21 +323,21 @@ int TestTwoTimers(void)
VerifyOrQuit(timer2.IsRunning() == true, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(sTimerOn, "TestTwoTimers: Platform Timer State Failed.\n");
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "TestTwoTimers: Stop CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "TestTwoTimers: Handler CallCount Failed.\n");
VerifyOrQuit(timerContextHandleCounter[1] == 1, "TestTwoTimers: Context handler failed.\n");
VerifyOrQuit(timer2.GetFiredCounter() == 1, "TestTwoTimers: Fire Counter failed.\n");
VerifyOrQuit(sPlatT0 == sNow && sPlatDt == 0, "TestTwoTimers: Start params Failed.\n");
VerifyOrQuit(timer1.IsRunning() == true, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(timer2.IsRunning() == false, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(sTimerOn == true, "TestTwoTimers: Platform Timer State Failed.\n");
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "TestTwoTimers: Stop CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 2, "TestTwoTimers: Handler CallCount Failed.\n");
VerifyOrQuit(timerContextHandleCounter[0] == 1, "TestTwoTimers: Context handler failed.\n");
VerifyOrQuit(timer1.GetFiredCounter() == 1, "TestTwoTimers: Fire Counter failed.\n");
VerifyOrQuit(timer1.IsRunning() == false, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(timer2.IsRunning() == false, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(sTimerOn == false, "TestTwoTimers: Platform Timer State Failed.\n");
@@ -327,7 +347,8 @@ int TestTwoTimers(void)
// the maximum interval.
InitCounters();
memset(timerContextHandleCounter, 0, sizeof(timerContextHandleCounter));
timer1.ResetFiredCounter();
timer2.ResetFiredCounter();
sNow = kTimeT0;
timer1.Start(kTimerInterval);
@@ -351,12 +372,12 @@ int TestTwoTimers(void)
VerifyOrQuit(timer2.IsRunning() == true, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(sTimerOn, "TestTwoTimers: Platform Timer State Failed.\n");
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "TestTwoTimers: Start CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "TestTwoTimers: Stop CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "TestTwoTimers: Handler CallCount Failed.\n");
VerifyOrQuit(timerContextHandleCounter[0] == 1, "TestTwoTimers: Context handler failed.\n");
VerifyOrQuit(timer1.GetFiredCounter() == 1, "TestTwoTimers: Fire Counter failed.\n");
VerifyOrQuit(sPlatT0 == sNow, "TestTwoTimers: Start params Failed.\n");
VerifyOrQuit(sPlatDt == ot::Timer::kMaxDt, "TestTwoTimers: Start params Failed.\n");
VerifyOrQuit(timer1.IsRunning() == false, "TestTwoTimers: Timer running Failed.\n");
@@ -364,18 +385,20 @@ int TestTwoTimers(void)
VerifyOrQuit(sTimerOn == true, "TestTwoTimers: Platform Timer State Failed.\n");
sNow += ot::Timer::kMaxDt;
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "TestTwoTimers: Start CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "TestTwoTimers: Stop CallCount Failed.\n");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 2, "TestTwoTimers: Handler CallCount Failed.\n");
VerifyOrQuit(timerContextHandleCounter[1] == 1, "TestTwoTimers: Context handler failed.\n");
VerifyOrQuit(timer2.GetFiredCounter() == 1, "TestTwoTimers: Fire Counter failed.\n");
VerifyOrQuit(timer1.IsRunning() == false, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(timer2.IsRunning() == false, "TestTwoTimers: Timer running Failed.\n");
VerifyOrQuit(sTimerOn == false, "TestTwoTimers: Platform Timer State Failed.\n");
printf(" --> PASSED\n");
testFreeInstance(instance);
return 0;
}
@@ -501,20 +524,19 @@ static void TenTimers(uint32_t aTimeShift)
11
};
otInstance aInstance;
otInstance *instance = testInitInstance();
uint32_t timerContextHandleCounter[kNumTimers] = {0};
ot::Timer timer0(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[0]);
ot::Timer timer1(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[1]);
ot::Timer timer2(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[2]);
ot::Timer timer3(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[3]);
ot::Timer timer4(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[4]);
ot::Timer timer5(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[5]);
ot::Timer timer6(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[6]);
ot::Timer timer7(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[7]);
ot::Timer timer8(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[8]);
ot::Timer timer9(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[9]);
ot::Timer *timers[kNumTimers] =
TestTimer timer0(instance);
TestTimer timer1(instance);
TestTimer timer2(instance);
TestTimer timer3(instance);
TestTimer timer4(instance);
TestTimer timer5(instance);
TestTimer timer6(instance);
TestTimer timer7(instance);
TestTimer timer8(instance);
TestTimer timer9(instance);
TestTimer *timers[kNumTimers] =
{
&timer0,
&timer1,
@@ -570,7 +592,7 @@ static void TenTimers(uint32_t aTimeShift)
// timer is ready to be triggered by examining the aDt arg passed into otPlatAlarmStartAt(). If
// that value is 0, then otPlatAlarmFired should be fired immediately. This loop calls otPlatAlarmFired()
// the requisite number of times based on the aDt argument.
otPlatAlarmFired(&aInstance);
otPlatAlarmFired(instance);
}
while (sPlatDt == 0);
@@ -594,10 +616,12 @@ static void TenTimers(uint32_t aTimeShift)
for (i = 0 ; i < kNumTimers ; i++)
{
VerifyOrQuit(timerContextHandleCounter[i] == 1, "TestTenTimer: Timer context counter Failed.\n");
VerifyOrQuit(timers[i]->GetFiredCounter() == 1, "TestTenTimer: Timer fired counter Failed.\n");
}
printf("--> PASSED\n");
testFreeInstance(instance);
}
int TestTenTimers(void)