From 302c99936739077f44e55612457e9b394f057325 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 20 Mar 2018 10:48:27 -0700 Subject: [PATCH] [child-supervision] change how child supervision gets started/stopped (#2627) This commit removes the `Start()/Stop()` APIs from `ChildSupervisor` class. Instead `ChildSupervisor` class itself would decide when to start/stop. It registers a `Notifier` callback to be notified when the Thread role changes and/or when a child is added or removed. If MLE operation is enabled and there is at least one "valid" child in the child table, child supervision starts, otherwise it is stopped. --- src/core/common/notifier.hpp | 2 +- src/core/thread/thread_netif.cpp | 2 - src/core/utils/child_supervision.cpp | 67 +++++++++++++++++++++------- src/core/utils/child_supervision.hpp | 9 +++- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/core/common/notifier.hpp b/src/core/common/notifier.hpp index e9b4b1f00..0db7040f0 100644 --- a/src/core/common/notifier.hpp +++ b/src/core/common/notifier.hpp @@ -80,7 +80,7 @@ public: * * @param[in] aCallback A reference to callback instance. * @param[in] aFlags A bit-field indicating specific state that has changed. See `OT_CHANGED_` - * definitions in `types.h`. + * definitions in `instance.h`. * */ typedef void (*Handler)(Callback &aCallback, uint32_t aFlags); diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp index 07b6cdf78..1912c9656 100644 --- a/src/core/thread/thread_netif.cpp +++ b/src/core/thread/thread_netif.cpp @@ -140,7 +140,6 @@ otError ThreadNetif::Up(void) #if OPENTHREAD_ENABLE_CHANNEL_MONITOR GetInstance().GetChannelMonitor().Start(); #endif - mChildSupervisor.Start(); mMleRouter.Enable(); mIsUp = true; } @@ -157,7 +156,6 @@ otError ThreadNetif::Down(void) #if OPENTHREAD_ENABLE_CHANNEL_MONITOR GetInstance().GetChannelMonitor().Stop(); #endif - mChildSupervisor.Stop(); mMleRouter.Disable(); mMeshForwarder.Stop(); GetIp6().RemoveNetif(*this); diff --git a/src/core/utils/child_supervision.cpp b/src/core/utils/child_supervision.cpp index e1a6e90fc..f8326b5ce 100644 --- a/src/core/utils/child_supervision.cpp +++ b/src/core/utils/child_supervision.cpp @@ -53,28 +53,15 @@ ChildSupervisor::ChildSupervisor(Instance &aInstance) : InstanceLocator(aInstance) , mSupervisionInterval(kDefaultSupervisionInterval) , mTimer(aInstance, &ChildSupervisor::HandleTimer, this) + , mNotifierCallback(&ChildSupervisor::HandleStateChanged, this) { -} - -void ChildSupervisor::Start(void) -{ - VerifyOrExit(mSupervisionInterval != 0); - VerifyOrExit(!mTimer.IsRunning()); - mTimer.Start(kOneSecond); - -exit: - return; -} - -void ChildSupervisor::Stop(void) -{ - mTimer.Stop(); + aInstance.GetNotifier().RegisterCallback(mNotifierCallback); } void ChildSupervisor::SetSupervisionInterval(uint16_t aInterval) { mSupervisionInterval = aInterval; - Start(); + CheckState(); } Child *ChildSupervisor::GetDestination(const Message &aMessage) const @@ -147,7 +134,7 @@ void ChildSupervisor::HandleTimer(void) for (uint8_t i = 0; i < numChildren; i++, child++) { - if (!child->IsStateValidOrRestoring()) + if (child->GetState() != Child::kStateValid) { continue; } @@ -166,6 +153,52 @@ exit: return; } +void ChildSupervisor::CheckState(void) +{ + bool shouldRun = false; + uint8_t numChildren = 0; + Mle::MleRouter &mle = GetInstance().Get(); + + // Child Supervision should run if `mSupervisionInterval` is not + // zero, Thread MLE operation is enabled, and there is at least one + // "valid" child in the child table. + + VerifyOrExit(mSupervisionInterval != 0); + VerifyOrExit(mle.GetRole() != OT_DEVICE_ROLE_DISABLED); + + for (Child *child = mle.GetChildren(&numChildren); numChildren > 0; child++, numChildren--) + { + VerifyOrExit(child->GetState() != Child::kStateValid, shouldRun = true); + } + +exit: + + if (shouldRun && !mTimer.IsRunning()) + { + mTimer.Start(kOneSecond); + otLogInfoUtil(GetInstance(), "Starting Child Supervision"); + } + + if (!shouldRun && mTimer.IsRunning()) + { + mTimer.Stop(); + otLogInfoUtil(GetInstance(), "Stopping Child Supervision"); + } +} + +void ChildSupervisor::HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags) +{ + aCallback.GetOwner().HandleStateChanged(aFlags); +} + +void ChildSupervisor::HandleStateChanged(uint32_t aFlags) +{ + if ((aFlags & (OT_CHANGED_THREAD_ROLE | OT_CHANGED_THREAD_CHILD_ADDED | OT_CHANGED_THREAD_CHILD_REMOVED)) != 0) + { + CheckState(); + } +} + #endif // #if OPENTHREAD_FTD SupervisionListener::SupervisionListener(Instance &aInstance) diff --git a/src/core/utils/child_supervision.hpp b/src/core/utils/child_supervision.hpp index 8b36bccd6..2fbbf1d26 100644 --- a/src/core/utils/child_supervision.hpp +++ b/src/core/utils/child_supervision.hpp @@ -39,6 +39,7 @@ #include "common/locator.hpp" #include "common/message.hpp" +#include "common/notifier.hpp" #include "common/timer.hpp" #include "mac/mac_frame.hpp" #include "thread/topology.hpp" @@ -155,11 +156,15 @@ private: }; void SendMessage(Child &aChild); + void CheckState(void); static void HandleTimer(Timer &aTimer); void HandleTimer(void); + static void HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags); + void HandleStateChanged(uint32_t aFlags); - uint16_t mSupervisionInterval; - TimerMilli mTimer; + uint16_t mSupervisionInterval; + TimerMilli mTimer; + Notifier::Callback mNotifierCallback; }; #else // #if OPENTHREAD_ENABLE_CHILD_SUPERVISION && OPENTHREAD_FTD