From 581221eedb0e350f3e2b3365df7bd416acb4f6e0 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 10 Apr 2026 19:38:35 -0700 Subject: [PATCH] [instance] introduce `ActiveInstanceTracker` for context-aware logging (#12869) This commit introduces `ActiveInstanceTracker` as the first member variable of the `Instance` class to manage the global `gActiveInstance` pointer (when `OPENTHREAD_CONFIG_LOG_INSTANCE_AWARE_API_ENABLE` is enabled). By placing it as the very first member, we ensure its constructor is called before any other member and its destructor is called after all others. The `Instance` destructor body also explicitly sets `gActiveInstance = this` at its start to "claim" the context during its own destruction. This guarantees that logs emitted during both the initialization and destruction of an `Instance` are always correctly associated with that instance. Finally, the `ActiveInstanceTracker` destructor sets `gActiveInstance` to `nullptr` at the very end to prevent any potential use of a dangling pointer. --- src/core/instance/instance.cpp | 15 ++++++-------- src/core/instance/instance.hpp | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/core/instance/instance.cpp b/src/core/instance/instance.cpp index df44a6b59..5a02b7321 100644 --- a/src/core/instance/instance.cpp +++ b/src/core/instance/instance.cpp @@ -78,7 +78,8 @@ LogLevel Instance::sGlobalLogLevel = static_cast(OPENTHREAD_CONFIG_LOG #endif Instance::Instance(void) - : mTimerMilliScheduler(*this) + : mActiveInstanceTracker(*this) + , mTimerMilliScheduler(*this) #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE , mTimerMicroScheduler(*this) #endif @@ -337,6 +338,10 @@ Instance::Instance(void) #endif } +#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE && OPENTHREAD_CONFIG_LOG_INSTANCE_AWARE_API_ENABLE +Instance::~Instance(void) { gActiveInstance = this; } +#endif + #if (OPENTHREAD_MTD || OPENTHREAD_FTD) && !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE Utils::Heap &Instance::GetHeap(void) { @@ -490,16 +495,8 @@ void Instance::Finalize(void) IgnoreError(Get().Disable()); -#if !OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE - - /** - * Object was created on buffer, so instead of deleting - * the object we call destructor explicitly. - */ this->~Instance(); -#endif // !OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE - exit: return; } diff --git a/src/core/instance/instance.hpp b/src/core/instance/instance.hpp index 09a8afa7a..a658e4318 100644 --- a/src/core/instance/instance.hpp +++ b/src/core/instance/instance.hpp @@ -484,7 +484,41 @@ public: void AfterInit(void); #endif +#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE && OPENTHREAD_CONFIG_LOG_INSTANCE_AWARE_API_ENABLE + /** + * Destructor + */ + ~Instance(void); +#endif + private: + class ActiveInstanceTracker + { + public: + // This class is used to track and update the `gActiveInstance` pointer during the + // construction and destruction of an `Instance`. + // + // `mActiveInstanceTracker` is defined as the very first member variable in `Instance`. + // This ensures its constructor is called before any other member components are + // initialized, and its destructor is called after all other components are destroyed. + // This ensures `gActiveInstance` is correctly set during the entire lifecycle of + // the `Instance`, allowing member components to safely emit logs. + // + // The `Instance` destructor also explicitly sets `gActiveInstance` to the instance + // being destroyed at the beginning of its body. This ensures that during the + // entire destruction process, log messages are correctly associated with the + // instance being destroyed. Finally, when `mActiveInstanceTracker` itself is + // destroyed (at the end of the `Instance` destruction), `gActiveInstance` is + // set to `nullptr` to avoid any potential use of a dangling pointer. + +#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE && OPENTHREAD_CONFIG_LOG_INSTANCE_AWARE_API_ENABLE + ActiveInstanceTracker(Instance &aInstance) { gActiveInstance = &aInstance; } + ~ActiveInstanceTracker(void) { gActiveInstance = nullptr; } +#else + ActiveInstanceTracker(Instance &) {} +#endif + }; + #if !OPENTHREAD_PLATFORM_NEXUS Instance(void); void AfterInit(void); @@ -509,6 +543,8 @@ private: // Tasklet and Timer Schedulers are first to ensure other // objects/classes can use them from their constructors. + ActiveInstanceTracker mActiveInstanceTracker; + Tasklet::Scheduler mTaskletScheduler; TimerMilli::Scheduler mTimerMilliScheduler; #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE