From 747b48510d37cb7fb4a9ed1184a840350bf3b997 Mon Sep 17 00:00:00 2001 From: Zang MingJie Date: Fri, 17 Sep 2021 23:41:35 +0800 Subject: [PATCH] SystemLayer::PostEvent add API to post a lambda event (#9678) --- src/include/platform/CHIPDeviceEvent.h | 3 ++ .../internal/GenericPlatformManagerImpl.cpp | 4 ++ src/lib/core/CHIPConfig.h | 18 +++++++ src/platform/LwIPEventSupport.cpp | 9 ++++ src/system/LwIPEventSupport.h | 2 + src/system/SystemEvent.h | 10 ---- src/system/SystemLayer.h | 36 ++++++++++++++ src/system/SystemLayerImplLwIP.cpp | 48 ++++++------------- src/system/SystemLayerImplLwIP.h | 5 +- src/system/SystemObject.cpp | 2 +- 10 files changed, 88 insertions(+), 49 deletions(-) diff --git a/src/include/platform/CHIPDeviceEvent.h b/src/include/platform/CHIPDeviceEvent.h index 66a27f0cd19fca..d235f4cd838d9b 100644 --- a/src/include/platform/CHIPDeviceEvent.h +++ b/src/include/platform/CHIPDeviceEvent.h @@ -228,6 +228,7 @@ enum InternalEventTypes kEventTypeNotSet = kRange_Internal, kNoOp, kCallWorkFunct, + kChipLambdaEvent, kChipSystemLayerEvent, kCHIPoBLESubscribe, kCHIPoBLEUnsubscribe, @@ -302,6 +303,7 @@ typedef void (*AsyncWorkFunct)(intptr_t arg); #include #include #include +#include #include #include @@ -318,6 +320,7 @@ struct ChipDeviceEvent final union { ChipDevicePlatformEvent Platform; + System::LambdaBridge LambdaEvent; struct { ::chip::System::EventType Type; diff --git a/src/include/platform/internal/GenericPlatformManagerImpl.cpp b/src/include/platform/internal/GenericPlatformManagerImpl.cpp index e388f424eb700c..dbdbe659858cf9 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl.cpp +++ b/src/include/platform/internal/GenericPlatformManagerImpl.cpp @@ -232,6 +232,10 @@ void GenericPlatformManagerImpl::_DispatchEvent(const ChipDeviceEvent Impl()->DispatchEventToSystemLayer(event); break; + case DeviceEventType::kChipLambdaEvent: + event->LambdaEvent.LambdaProxy(static_cast(event->LambdaEvent.LambdaBody)); + break; + case DeviceEventType::kCallWorkFunct: // If the event is a "call work function" event, call the specified function. event->CallWorkFunct.WorkFunct(event->CallWorkFunct.Arg); diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index b3407b32e81328..d4ed65b5cb80db 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -2470,6 +2470,24 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_DEVICE_CONTROLLER_SUBSCRIPTION_ATTRIBUTE_PATH_POOL_SIZE CHIP_IM_MAX_NUM_READ_CLIENT #endif +/** + * @def CHIP_CONFIG_LAMBDA_EVENT_SIZE + * + * @brief The maximum size of the lambda which can be post into system event queue. + */ +#ifndef CHIP_CONFIG_LAMBDA_EVENT_SIZE +#define CHIP_CONFIG_LAMBDA_EVENT_SIZE (16) +#endif + +/** + * @def CHIP_CONFIG_LAMBDA_EVENT_ALIGN + * + * @brief The maximum alignment of the lambda which can be post into system event queue. + */ +#ifndef CHIP_CONFIG_LAMBDA_EVENT_ALIGN +#define CHIP_CONFIG_LAMBDA_EVENT_ALIGN (sizeof(void *)) +#endif + /** * @} */ diff --git a/src/platform/LwIPEventSupport.cpp b/src/platform/LwIPEventSupport.cpp index f51a02b6689d7b..d2c09a6ebc7d1f 100644 --- a/src/platform/LwIPEventSupport.cpp +++ b/src/platform/LwIPEventSupport.cpp @@ -34,6 +34,15 @@ namespace System { using namespace ::chip::DeviceLayer; +CHIP_ERROR PlatformEventing::ScheduleLambdaBridge(System::Layer & aLayer, const LambdaBridge & bridge) +{ + ChipDeviceEvent event; + event.Type = DeviceEventType::kChipLambdaEvent; + event.LambdaEvent = bridge; + + return PlatformMgr().PostEvent(&event); +} + CHIP_ERROR PlatformEventing::PostEvent(System::Layer & aLayer, System::Object & aTarget, System::EventType aType, uintptr_t aArgument) { diff --git a/src/system/LwIPEventSupport.h b/src/system/LwIPEventSupport.h index d3fe51a7c577fa..921bbcc21a45f9 100644 --- a/src/system/LwIPEventSupport.h +++ b/src/system/LwIPEventSupport.h @@ -18,6 +18,7 @@ #include #include +#include namespace chip { namespace System { @@ -28,6 +29,7 @@ class Object; class PlatformEventing { public: + static CHIP_ERROR ScheduleLambdaBridge(System::Layer & aLayer, const LambdaBridge & bridge); static CHIP_ERROR PostEvent(System::Layer & aLayer, Object & aTarget, EventType aType, uintptr_t aArgument); static CHIP_ERROR DispatchEvents(System::Layer & aLayer); static CHIP_ERROR DispatchEvent(System::Layer & aLayer, Event aEvent); diff --git a/src/system/SystemEvent.h b/src/system/SystemEvent.h index a07cc9770c5e9d..95865210e6ee9f 100644 --- a/src/system/SystemEvent.h +++ b/src/system/SystemEvent.h @@ -56,16 +56,6 @@ typedef CHIP_SYSTEM_CONFIG_EVENT_OBJECT_TYPE Event; #if CHIP_SYSTEM_CONFIG_USE_LWIP -/** - * The Inet layer event type definitions. - * - */ -enum -{ - kEvent_ReleaseObj = _CHIP_SYSTEM_CONFIG_LWIP_EVENT(0), /**< The event for the drop of a System::Layer object */ - kEvent_ScheduleWork = _CHIP_SYSTEM_CONFIG_LWIP_EVENT(1), /**< The event for scheduling work on the System Layer's thread. */ -}; - #endif // CHIP_SYSTEM_CONFIG_USE_LWIP } // namespace System diff --git a/src/system/SystemLayer.h b/src/system/SystemLayer.h index e29ab10c8cd1ad..f2b19cf00cb422 100644 --- a/src/system/SystemLayer.h +++ b/src/system/SystemLayer.h @@ -49,6 +49,12 @@ namespace chip { namespace System { +struct LambdaBridge +{ + void (*LambdaProxy)(const void * context); + alignas(CHIP_CONFIG_LAMBDA_EVENT_ALIGN) char LambdaBody[CHIP_CONFIG_LAMBDA_EVENT_SIZE]; +}; + class Layer; using TimerCompleteCallback = void (*)(Layer * aLayer, void * appState); @@ -195,6 +201,36 @@ class LayerLwIP : public Layer */ virtual CHIP_ERROR PostEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument) = 0; + /** + * This posts an event / message of the specified type with the provided argument to this instance's platform-specific event + * queue. + * + * @param[in] event A object encapsulate the context of a lambda + * + * @retval CHIP_NO_ERROR On success. + * @retval CHIP_ERROR_INCORRECT_STATE If the state of the Layer object is incorrect. + * @retval CHIP_ERROR_NO_MEMORY If the event queue is already full. + * @retval other Platform-specific errors generated indicating the reason for failure. + */ + virtual CHIP_ERROR ScheduleLambdaBridge(const LambdaBridge & event) = 0; + + template + CHIP_ERROR ScheduleLambda(const Lambda & lambda) + { + LambdaBridge event; + + // memcpy is used to move the lambda into the event queue, so it must be trivially copyable + static_assert(std::is_trivially_copyable::value); + static_assert(sizeof(Lambda) <= CHIP_CONFIG_LAMBDA_EVENT_SIZE); + static_assert(alignof(Lambda) <= CHIP_CONFIG_LAMBDA_EVENT_ALIGN); + + // Implicit cast a capture-less lambda into a raw function pointer. + event.LambdaProxy = [](const void * body) { (*static_cast(body))(); }; + memcpy(event.LambdaBody, &lambda, sizeof(Lambda)); + + return ScheduleLambdaBridge(event); + } + protected: // Provide access to private members of EventHandlerDelegate. struct LwIPEventHandlerDelegate : public EventHandlerDelegate diff --git a/src/system/SystemLayerImplLwIP.cpp b/src/system/SystemLayerImplLwIP.cpp index e7032941b524d5..199baee7560967 100644 --- a/src/system/SystemLayerImplLwIP.cpp +++ b/src/system/SystemLayerImplLwIP.cpp @@ -30,13 +30,7 @@ namespace chip { namespace System { -LayerLwIP::EventHandlerDelegate LayerImplLwIP::sSystemEventHandlerDelegate; - -LayerImplLwIP::LayerImplLwIP() : mHandlingTimerComplete(false), mEventDelegateList(nullptr) -{ - if (!sSystemEventHandlerDelegate.IsInitialized()) - sSystemEventHandlerDelegate.Init(HandleSystemLayerEvent); -} +LayerImplLwIP::LayerImplLwIP() : mHandlingTimerComplete(false), mEventDelegateList(nullptr) {} CHIP_ERROR LayerImplLwIP::Init() { @@ -44,7 +38,6 @@ CHIP_ERROR LayerImplLwIP::Init() RegisterLwIPErrorFormatter(); - AddEventHandlerDelegate(sSystemEventHandlerDelegate); ReturnErrorOnFailure(mTimerList.Init()); VerifyOrReturnError(mLayerState.Init(), CHIP_ERROR_INCORRECT_STATE); @@ -100,7 +93,7 @@ CHIP_ERROR LayerImplLwIP::ScheduleWork(TimerCompleteCallback onComplete, void * Timer * timer = Timer::New(*this, 0, onComplete, appState); VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY); - return PostEvent(*timer, chip::System::kEvent_ScheduleWork, 0); + return ScheduleLambda([timer] { timer->HandleComplete(); }); } bool LayerLwIP::EventHandlerDelegate::IsInitialized() const @@ -120,31 +113,6 @@ void LayerLwIP::EventHandlerDelegate::Prepend(const LayerLwIP::EventHandlerDeleg aDelegateList = this; } -/** - * This is the dispatch handler for system layer events. - * - * @param[in,out] aTarget A pointer to the CHIP System Layer object making the post request. - * @param[in] aEventType The type of event to post. - * @param[in,out] aArgument The argument associated with the event to post. - */ -CHIP_ERROR LayerImplLwIP::HandleSystemLayerEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument) -{ - // Dispatch logic specific to the event type - switch (aEventType) - { - case kEvent_ReleaseObj: - aTarget.Release(); - return CHIP_NO_ERROR; - - case kEvent_ScheduleWork: - static_cast(aTarget).HandleComplete(); - return CHIP_NO_ERROR; - - default: - return CHIP_ERROR_UNEXPECTED_EVENT; - } -} - CHIP_ERROR LayerImplLwIP::AddEventHandlerDelegate(EventHandlerDelegate & aDelegate) { LwIPEventHandlerDelegate & lDelegate = static_cast(aDelegate); @@ -153,6 +121,18 @@ CHIP_ERROR LayerImplLwIP::AddEventHandlerDelegate(EventHandlerDelegate & aDelega return CHIP_NO_ERROR; } +CHIP_ERROR LayerImplLwIP::ScheduleLambdaBridge(const LambdaBridge & bridge) +{ + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); + + CHIP_ERROR lReturn = PlatformEventing::ScheduleLambdaBridge(*this, bridge); + if (lReturn != CHIP_NO_ERROR) + { + ChipLogError(chipSystemLayer, "Failed to queue CHIP System Layer lambda event: %s", ErrorStr(lReturn)); + } + return lReturn; +} + CHIP_ERROR LayerImplLwIP::PostEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument) { VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE); diff --git a/src/system/SystemLayerImplLwIP.h b/src/system/SystemLayerImplLwIP.h index c72ed372ed13cd..69e20c08f17df6 100644 --- a/src/system/SystemLayerImplLwIP.h +++ b/src/system/SystemLayerImplLwIP.h @@ -44,6 +44,7 @@ class LayerImplLwIP : public LayerLwIP // LayerLwIP overrides. CHIP_ERROR AddEventHandlerDelegate(EventHandlerDelegate & aDelegate); + CHIP_ERROR ScheduleLambdaBridge(const LambdaBridge & bridge) override; CHIP_ERROR PostEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument); public: @@ -55,13 +56,9 @@ class LayerImplLwIP : public LayerLwIP private: friend class PlatformEventing; - static CHIP_ERROR HandleSystemLayerEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument); - CHIP_ERROR DispatchEvent(Event aEvent); CHIP_ERROR StartPlatformTimer(uint32_t aDelayMilliseconds); - static EventHandlerDelegate sSystemEventHandlerDelegate; - Timer::MutexedList mTimerList; bool mHandlingTimerComplete; // true while handling any timer completion const EventHandlerDelegate * mEventDelegateList; diff --git a/src/system/SystemObject.cpp b/src/system/SystemObject.cpp index 54c2e08070168f..342cbe62c08a52 100644 --- a/src/system/SystemObject.cpp +++ b/src/system/SystemObject.cpp @@ -83,7 +83,7 @@ void Object::DeferredRelease(LayerLwIP * aSystemLayer, Object::ReleaseDeferralEr { VerifyOrReturn(aSystemLayer != nullptr, ChipLogError(chipSystemLayer, "aSystemLayer is nullptr")); - CHIP_ERROR lError = aSystemLayer->PostEvent(*this, chip::System::kEvent_ReleaseObj, 0); + CHIP_ERROR lError = aSystemLayer->ScheduleLambda([this] { this->Release(); }); if (lError != CHIP_NO_ERROR) {