mirror of
https://github.com/espressif/openthread.git
synced 2026-08-16 15:47:46 +00:00
[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:
committed by
Jonathan Hui
parent
5128602b49
commit
bbab3074ed
+72
-48
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user