From 27ea53eaedce125ed1f45aae44b2d3868dee96cf Mon Sep 17 00:00:00 2001 From: Zang MingJie Date: Tue, 2 Nov 2021 21:57:36 +0800 Subject: [PATCH] Pull up LayerLwIP::ScheduleLambda to SystemLayer (#11187) --- src/include/platform/CHIPDeviceEvent.h | 7 +- src/include/platform/PlatformManager.h | 5 +- .../internal/GenericPlatformManagerImpl.cpp | 2 +- src/lib/support/LambdaBridge.h | 53 +++++++++++++++ src/platform/BUILD.gn | 2 +- ...ntSupport.cpp => PlatformEventSupport.cpp} | 4 +- src/system/BUILD.gn | 3 +- ...PEventSupport.h => PlatformEventSupport.h} | 2 +- src/system/SystemLayer.cpp | 35 ++++++++++ src/system/SystemLayer.h | 64 ++++++++----------- src/system/SystemLayerImplLwIP.cpp | 14 +--- src/system/SystemLayerImplLwIP.h | 1 - 12 files changed, 127 insertions(+), 65 deletions(-) create mode 100644 src/lib/support/LambdaBridge.h rename src/platform/{LwIPEventSupport.cpp => PlatformEventSupport.cpp} (96%) rename src/system/{LwIPEventSupport.h => PlatformEventSupport.h} (97%) create mode 100644 src/system/SystemLayer.cpp diff --git a/src/include/platform/CHIPDeviceEvent.h b/src/include/platform/CHIPDeviceEvent.h index 4583f6cc887c7b..0d3da3b44db27d 100644 --- a/src/include/platform/CHIPDeviceEvent.h +++ b/src/include/platform/CHIPDeviceEvent.h @@ -307,10 +307,7 @@ typedef void (*AsyncWorkFunct)(intptr_t arg); #include #include -#include -#include -#include -#include +#include namespace chip { namespace DeviceLayer { @@ -325,7 +322,7 @@ struct ChipDeviceEvent final union { ChipDevicePlatformEvent Platform; - System::LambdaBridge LambdaEvent; + LambdaBridge LambdaEvent; struct { ::chip::System::EventType Type; diff --git a/src/include/platform/PlatformManager.h b/src/include/platform/PlatformManager.h index 38cf83fa41c04f..5bbb68c9adf2cc 100644 --- a/src/include/platform/PlatformManager.h +++ b/src/include/platform/PlatformManager.h @@ -25,12 +25,9 @@ #include #include +#include #include -#if CHIP_SYSTEM_CONFIG_USE_LWIP -#include -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP - namespace chip { namespace Dnssd { diff --git a/src/include/platform/internal/GenericPlatformManagerImpl.cpp b/src/include/platform/internal/GenericPlatformManagerImpl.cpp index 28f1eb8d9ad730..a54e36baa6be1b 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl.cpp +++ b/src/include/platform/internal/GenericPlatformManagerImpl.cpp @@ -226,7 +226,7 @@ void GenericPlatformManagerImpl::_DispatchEvent(const ChipDeviceEvent break; case DeviceEventType::kChipLambdaEvent: - event->LambdaEvent.LambdaProxy(static_cast(event->LambdaEvent.LambdaBody)); + event->LambdaEvent(); break; case DeviceEventType::kCallWorkFunct: diff --git a/src/lib/support/LambdaBridge.h b/src/lib/support/LambdaBridge.h new file mode 100644 index 00000000000000..32b0a17075fc80 --- /dev/null +++ b/src/lib/support/LambdaBridge.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace chip { + +class LambdaBridge +{ +public: + // Use initialize instead of constructor because this class has to be trivial + template + void Initialize(const Lambda & lambda) + { + // memcpy is used to move the lambda into the event queue, so it must be trivially copyable + static_assert(std::is_trivially_copyable::value, "lambda must be trivially copyable"); + static_assert(sizeof(Lambda) <= CHIP_CONFIG_LAMBDA_EVENT_SIZE, "lambda too large"); + static_assert(CHIP_CONFIG_LAMBDA_EVENT_ALIGN % alignof(Lambda) == 0, "lambda align too large"); + + // Implicit cast a capture-less lambda into a raw function pointer. + mLambdaProxy = [](const std::aligned_storage & body) { + (*reinterpret_cast(&body))(); + }; + memcpy(&mLambdaBody, &lambda, sizeof(Lambda)); + } + + void operator()() const { mLambdaProxy(mLambdaBody); } + +private: + void (*mLambdaProxy)(const std::aligned_storage & body); + std::aligned_storage mLambdaBody; +}; + +static_assert(std::is_trivial::value, "LambdaBridge is not trivial"); + +} // namespace chip diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index c18a3da9d193cb..7870c9127e3b8c 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -285,8 +285,8 @@ if (chip_device_platform != "none") { "GeneralUtils.cpp", "Globals.cpp", "LockTracker.cpp", - "LwIPEventSupport.cpp", "PersistedStorage.cpp", + "PlatformEventSupport.cpp", "TestIdentity.cpp", ] diff --git a/src/platform/LwIPEventSupport.cpp b/src/platform/PlatformEventSupport.cpp similarity index 96% rename from src/platform/LwIPEventSupport.cpp rename to src/platform/PlatformEventSupport.cpp index 0a4cead359ab50..f7ed770bdf8f6f 100644 --- a/src/platform/LwIPEventSupport.cpp +++ b/src/platform/PlatformEventSupport.cpp @@ -34,11 +34,11 @@ namespace System { using namespace ::chip::DeviceLayer; -CHIP_ERROR PlatformEventing::ScheduleLambdaBridge(System::Layer & aLayer, const LambdaBridge & bridge) +CHIP_ERROR PlatformEventing::ScheduleLambdaBridge(System::Layer & aLayer, LambdaBridge && bridge) { ChipDeviceEvent event; event.Type = DeviceEventType::kChipLambdaEvent; - event.LambdaEvent = bridge; + event.LambdaEvent = std::move(bridge); return PlatformMgr().PostEvent(&event); } diff --git a/src/system/BUILD.gn b/src/system/BUILD.gn index 83989935b6f7ef..e4538f9a930142 100644 --- a/src/system/BUILD.gn +++ b/src/system/BUILD.gn @@ -131,6 +131,7 @@ static_library("system") { "SystemError.h", "SystemEvent.h", "SystemFaultInjection.h", + "SystemLayer.cpp", "SystemLayer.h", "SystemLayerImpl${chip_system_config_event_loop}.cpp", "SystemLayerImpl${chip_system_config_event_loop}.h", @@ -170,7 +171,7 @@ static_library("system") { } if (chip_system_config_use_lwip) { - sources += [ "LwIPEventSupport.h" ] + sources += [ "PlatformEventSupport.h" ] } if (chip_with_nlfaultinjection) { diff --git a/src/system/LwIPEventSupport.h b/src/system/PlatformEventSupport.h similarity index 97% rename from src/system/LwIPEventSupport.h rename to src/system/PlatformEventSupport.h index 3679bec5a68a38..ee17332a04df4a 100644 --- a/src/system/LwIPEventSupport.h +++ b/src/system/PlatformEventSupport.h @@ -29,7 +29,7 @@ class Object; class PlatformEventing { public: - static CHIP_ERROR ScheduleLambdaBridge(System::Layer & aLayer, const LambdaBridge & bridge); + static CHIP_ERROR ScheduleLambdaBridge(System::Layer & aLayer, LambdaBridge && bridge); static CHIP_ERROR PostEvent(System::Layer & aLayer, Object & aTarget, EventType aType, uintptr_t aArgument); static CHIP_ERROR StartTimer(System::Layer & aLayer, System::Clock::Timeout aTimeout); }; diff --git a/src/system/SystemLayer.cpp b/src/system/SystemLayer.cpp new file mode 100644 index 00000000000000..cb4330e194c5ec --- /dev/null +++ b/src/system/SystemLayer.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace chip { +namespace System { + +CHIP_ERROR Layer::ScheduleLambdaBridge(LambdaBridge && bridge) +{ + CHIP_ERROR lReturn = PlatformEventing::ScheduleLambdaBridge(*this, std::move(bridge)); + if (lReturn != CHIP_NO_ERROR) + { + ChipLogError(chipSystemLayer, "Failed to queue CHIP System Layer lambda event: %s", ErrorStr(lReturn)); + } + return lReturn; +} + +} // namespace System +} // namespace chip diff --git a/src/system/SystemLayer.h b/src/system/SystemLayer.h index b731ec31fa5feb..b61acf22c6fe70 100644 --- a/src/system/SystemLayer.h +++ b/src/system/SystemLayer.h @@ -25,6 +25,8 @@ #pragma once +#include + // Include configuration headers #include @@ -32,6 +34,7 @@ #include #include +#include #include #include #include @@ -50,12 +53,6 @@ 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); @@ -148,6 +145,31 @@ class DLL_EXPORT Layer */ virtual CHIP_ERROR ScheduleWork(TimerCompleteCallback aComplete, void * aAppState) = 0; + /** + * @brief + * Schedules a lambda even to be run as soon as possible in the CHIP context. This function is not thread-safe, + * it must be called with in the CHIP context + * + * @param[in] event A object encapsulate the context of a lambda + * + * @retval CHIP_NO_ERROR On success. + * @retval other Platform-specific errors generated indicating the reason for failure. + */ + CHIP_ERROR ScheduleLambdaBridge(LambdaBridge && event); + + /** + * @brief + * Schedules a lambda object to be run as soon as possible in the CHIP context. This function is not thread-safe, + * it must be called with in the CHIP context + */ + template + CHIP_ERROR ScheduleLambda(const Lambda & lambda) + { + LambdaBridge bridge; + bridge.Initialize(lambda); + return ScheduleLambdaBridge(std::move(bridge)); + } + private: // Copy and assignment NOT DEFINED Layer(const Layer &) = delete; @@ -202,36 +224,6 @@ 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 67b8c77313458d..5117407cb6ca84 100644 --- a/src/system/SystemLayerImplLwIP.cpp +++ b/src/system/SystemLayerImplLwIP.cpp @@ -22,7 +22,7 @@ */ #include -#include +#include #include #include #include @@ -122,18 +122,6 @@ 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 4ff2686d4e597e..867f198c0119e9 100644 --- a/src/system/SystemLayerImplLwIP.h +++ b/src/system/SystemLayerImplLwIP.h @@ -44,7 +44,6 @@ 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: