diff --git a/src/include/platform/CHIPDeviceEvent.h b/src/include/platform/CHIPDeviceEvent.h index 2476c441ae9c09..15d3ac7817b114 100644 --- a/src/include/platform/CHIPDeviceEvent.h +++ b/src/include/platform/CHIPDeviceEvent.h @@ -314,10 +314,7 @@ typedef void (*AsyncWorkFunct)(intptr_t arg); #include #include -#include -#include -#include -#include +#include namespace chip { namespace DeviceLayer { @@ -332,7 +329,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 7e35cf82d845ae..549b39fae29ba9 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 { @@ -225,9 +222,7 @@ class PlatformManager friend class Internal::GenericThreadStackManagerImpl_OpenThread_LwIP; template friend class Internal::GenericConfigurationManagerImpl; -#if CHIP_SYSTEM_CONFIG_USE_LWIP friend class System::PlatformEventing; -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP /* * PostEvent can be called safely on any thread without locking the stack. diff --git a/src/include/platform/internal/GenericPlatformManagerImpl.cpp b/src/include/platform/internal/GenericPlatformManagerImpl.cpp index e5f17473f5c670..ac80fa8a4617ee 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl.cpp +++ b/src/include/platform/internal/GenericPlatformManagerImpl.cpp @@ -227,7 +227,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/include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.cpp b/src/include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.cpp index e4dd42476fcd9f..06271f1e8d8fbf 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.cpp +++ b/src/include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.cpp @@ -71,6 +71,8 @@ CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS::_InitChipStack(void) ExitNow(err = CHIP_ERROR_NO_MEMORY); } + mShouldRunEventLoop.store(false); + // Call up to the base class _InitChipStack() to perform the bulk of the initialization. err = GenericPlatformManagerImpl::_InitChipStack(); SuccessOrExit(err); @@ -119,12 +121,17 @@ void GenericPlatformManagerImpl_FreeRTOS::_RunEventLoop(void) CHIP_ERROR err; ChipDeviceEvent event; - VerifyOrDie(mEventLoopTask != NULL); - // Lock the CHIP stack. Impl()->LockChipStack(); - while (true) + bool oldShouldRunEventLoop = false; + if (!mShouldRunEventLoop.compare_exchange_strong(oldShouldRunEventLoop /* expected */, true /* desired */)) + { + ChipLogError(DeviceLayer, "Error trying to run the event loop while it is already running"); + return; + } + + while (mShouldRunEventLoop.load()) { TickType_t waitTime; @@ -251,8 +258,8 @@ CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS::_Shutdown(void) template CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS::_StopEventLoopTask(void) { - VerifyOrDieWithMsg(false, DeviceLayer, "StopEventLoopTask is not implemented"); - return CHIP_ERROR_NOT_IMPLEMENTED; + mShouldRunEventLoop.store(false); + return CHIP_NO_ERROR; } } // namespace Internal diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.h b/src/include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.h index ab114ecb8d91f3..616970d9763af7 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.h +++ b/src/include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.h @@ -39,6 +39,8 @@ #include "task.h" #endif +#include + namespace chip { namespace DeviceLayer { namespace Internal { @@ -92,6 +94,7 @@ class GenericPlatformManagerImpl_FreeRTOS : public GenericPlatformManagerImpl mShouldRunEventLoop; #if defined(CHIP_CONFIG_FREERTOS_USE_STATIC_TASK) && CHIP_CONFIG_FREERTOS_USE_STATIC_TASK StackType_t mEventLoopStack[CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE / sizeof(StackType_t)]; StaticTask_t mventLoopTaskStruct; diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.cpp b/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.cpp index 9b584d6f8570db..b8358b59f269bf 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.cpp +++ b/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.cpp @@ -61,6 +61,8 @@ CHIP_ERROR GenericPlatformManagerImpl_Zephyr::_InitChipStack(void) k_msgq_init(&mChipEventQueue, reinterpret_cast(&mChipEventRingBuffer), sizeof(ChipDeviceEvent), CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE); + mShouldRunEventLoop = false; + // Call up to the base class _InitChipStack() to perform the bulk of the initialization. err = GenericPlatformManagerImpl::_InitChipStack(); SuccessOrExit(err); @@ -97,8 +99,8 @@ CHIP_ERROR GenericPlatformManagerImpl_Zephyr::_StartChipTimer(System: template CHIP_ERROR GenericPlatformManagerImpl_Zephyr::_StopEventLoopTask(void) { - VerifyOrDieWithMsg(false, DeviceLayer, "StopEventLoopTask is not implemented"); - return CHIP_ERROR_NOT_IMPLEMENTED; + mShouldRunEventLoop = false; + return CHIP_NO_ERROR; } template @@ -137,8 +139,15 @@ void GenericPlatformManagerImpl_Zephyr::_RunEventLoop(void) { Impl()->LockChipStack(); + if (mShouldRunEventLoop) + { + ChipLogError(DeviceLayer, "Error trying to run the event loop while it is already running"); + return; + } + mShouldRunEventLoop = true; + SystemLayerSocketsLoop().EventLoopBegins(); - while (true) + while (mShouldRunEventLoop) { SystemLayerSocketsLoop().PrepareEvents(); diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.h b/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.h index 684c7cabddcaf1..9fc1438f4beff6 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.h +++ b/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.h @@ -91,6 +91,7 @@ class GenericPlatformManagerImpl_Zephyr : public GenericPlatformManagerImpl +#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 LambdaStorage & body) { (*reinterpret_cast(&body))(); }; + ::memcpy(&mLambdaBody, &lambda, sizeof(Lambda)); + } + + void operator()() const { mLambdaProxy(mLambdaBody); } + +private: + using LambdaStorage = std::aligned_storage_t; + void (*mLambdaProxy)(const LambdaStorage & body); + LambdaStorage 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 2683e3c758a5c8..d4ea23afd4fc62 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -284,8 +284,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 93% rename from src/platform/LwIPEventSupport.cpp rename to src/platform/PlatformEventSupport.cpp index 0a4cead359ab50..7863aeea817bf2 100644 --- a/src/platform/LwIPEventSupport.cpp +++ b/src/platform/PlatformEventSupport.cpp @@ -27,18 +27,16 @@ #include -#if CHIP_SYSTEM_CONFIG_USE_LWIP - namespace chip { 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); } @@ -62,5 +60,3 @@ CHIP_ERROR PlatformEventing::StartTimer(System::Layer & aLayer, System::Clock::T } // namespace System } // namespace chip - -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP diff --git a/src/platform/fake/PlatformManagerImpl.h b/src/platform/fake/PlatformManagerImpl.h index 4bbd9df6908fae..e043c5fbc7e000 100644 --- a/src/platform/fake/PlatformManagerImpl.h +++ b/src/platform/fake/PlatformManagerImpl.h @@ -24,6 +24,8 @@ #include +#include + namespace chip { namespace DeviceLayer { @@ -43,21 +45,62 @@ class PlatformManagerImpl final : public PlatformManager // ===== Methods that implement the PlatformManager abstract interface. CHIP_ERROR _InitChipStack() { return CHIP_NO_ERROR; } + CHIP_ERROR _Shutdown() { return CHIP_NO_ERROR; } CHIP_ERROR _AddEventHandler(EventHandlerFunct handler, intptr_t arg = 0) { return CHIP_ERROR_NOT_IMPLEMENTED; } void _RemoveEventHandler(EventHandlerFunct handler, intptr_t arg = 0) {} void _ScheduleWork(AsyncWorkFunct workFunct, intptr_t arg = 0) {} - void _RunEventLoop() {} + + void _RunEventLoop() + { + do + { + ProcessDeviceEvents(); + } while (mShouldRunEventLoop); + } + + void ProcessDeviceEvents() + { + while (!mQueue.empty()) + { + const ChipDeviceEvent & event = mQueue.front(); + _DispatchEvent(&event); + mQueue.pop(); + } + } + CHIP_ERROR _StartEventLoopTask() { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR _StopEventLoopTask() { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR _PostEvent(const ChipDeviceEvent * event) { return CHIP_NO_ERROR; } - void _DispatchEvent(const ChipDeviceEvent * event) {} + + CHIP_ERROR _StopEventLoopTask() + { + mShouldRunEventLoop = false; + return CHIP_NO_ERROR; + } + + CHIP_ERROR _PostEvent(const ChipDeviceEvent * event) + { + mQueue.emplace(*event); + return CHIP_NO_ERROR; + } + + void _DispatchEvent(const ChipDeviceEvent * event) + { + switch (event->Type) + { + case DeviceEventType::kChipLambdaEvent: + event->LambdaEvent(); + break; + + default: + break; + } + } + CHIP_ERROR _StartChipTimer(System::Clock::Timeout duration) { return CHIP_ERROR_NOT_IMPLEMENTED; } void _LockChipStack() {} bool _TryLockChipStack() { return true; } void _UnlockChipStack() {} - CHIP_ERROR _Shutdown() { return CHIP_ERROR_NOT_IMPLEMENTED; } CHIP_ERROR _GetCurrentHeapFree(uint64_t & currentHeapFree); CHIP_ERROR _GetCurrentHeapUsed(uint64_t & currentHeapUsed); @@ -75,6 +118,9 @@ class PlatformManagerImpl final : public PlatformManager friend class Internal::BLEManagerImpl; static PlatformManagerImpl sInstance; + + bool mShouldRunEventLoop = true; + std::queue mQueue; }; /** diff --git a/src/system/BUILD.gn b/src/system/BUILD.gn index 83989935b6f7ef..0aaa7a9e192674 100644 --- a/src/system/BUILD.gn +++ b/src/system/BUILD.gn @@ -123,6 +123,7 @@ static_library("system") { output_name = "libSystemLayer" sources = [ + "PlatformEventSupport.h", "SystemAlignSize.h", "SystemClock.cpp", "SystemClock.h", @@ -131,6 +132,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", @@ -169,10 +171,6 @@ static_library("system") { } } - if (chip_system_config_use_lwip) { - sources += [ "LwIPEventSupport.h" ] - } - if (chip_with_nlfaultinjection) { sources += [ "SystemFaultInjection.cpp" ] public_deps += [ "${nlfaultinjection_root}: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..d69c2ddb773a44 100644 --- a/src/system/SystemLayer.h +++ b/src/system/SystemLayer.h @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -50,12 +51,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 +143,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 +222,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: diff --git a/src/system/tests/BUILD.gn b/src/system/tests/BUILD.gn index 6315029f2c6915..432bc11d366ac7 100644 --- a/src/system/tests/BUILD.gn +++ b/src/system/tests/BUILD.gn @@ -26,6 +26,7 @@ chip_test_suite("tests") { "TestSystemErrorStr.cpp", "TestSystemObject.cpp", "TestSystemPacketBuffer.cpp", + "TestSystemScheduleLambda.cpp", "TestSystemTimer.cpp", "TestSystemWakeEvent.cpp", "TestTimeSource.cpp", diff --git a/src/system/tests/TestSystemScheduleLambda.cpp b/src/system/tests/TestSystemScheduleLambda.cpp new file mode 100644 index 00000000000000..3ee8a99dc0b598 --- /dev/null +++ b/src/system/tests/TestSystemScheduleLambda.cpp @@ -0,0 +1,98 @@ +/* + * 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 +#include +#include +#include + +// Test input data. + +static void CheckScheduleLambda(nlTestSuite * inSuite, void * aContext) +{ + bool * called = new bool(false); + chip::DeviceLayer::SystemLayer().ScheduleLambda([called] { + *called = true; + chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); + }); + chip::DeviceLayer::PlatformMgr().RunEventLoop(); + NL_TEST_ASSERT(inSuite, *called); + delete called; +} + +// Test Suite + +/** + * Test Suite. It lists all the test functions. + */ +// clang-format off +static const nlTest sTests[] = +{ + NL_TEST_DEF("System::TestScheduleLambda", CheckScheduleLambda), + NL_TEST_SENTINEL() +}; +// clang-format on + +static int TestSetup(void * aContext); +static int TestTeardown(void * aContext); + +// clang-format off +static nlTestSuite kTheSuite = +{ + "chip-system-schedule-lambda", + &sTests[0], + TestSetup, + TestTeardown +}; +// clang-format on + +/** + * Set up the test suite. + */ +static int TestSetup(void * aContext) +{ + if (chip::DeviceLayer::PlatformMgr().InitChipStack() != CHIP_NO_ERROR) + return FAILURE; + + return (SUCCESS); +} + +/** + * Tear down the test suite. + * Free memory reserved at TestSetup. + */ +static int TestTeardown(void * aContext) +{ + CHIP_ERROR err = chip::DeviceLayer::PlatformMgr().Shutdown(); + // RTOS shutdown is not implemented, ignore CHIP_ERROR_NOT_IMPLEMENTED + if (err != CHIP_NO_ERROR && err != CHIP_ERROR_NOT_IMPLEMENTED) + return FAILURE; + + return (SUCCESS); +} + +int TestSystemScheduleLambda(void) +{ + // Run test suit againt one lContext. + nlTestRunner(&kTheSuite, nullptr); + + return nlTestRunnerStats(&kTheSuite); +} + +CHIP_REGISTER_TEST_SUITE(TestSystemScheduleLambda)