diff --git a/src/include/platform/PlatformManager.h b/src/include/platform/PlatformManager.h index 5b8c71190348ab..549b39fae29ba9 100644 --- a/src/include/platform/PlatformManager.h +++ b/src/include/platform/PlatformManager.h @@ -222,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_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..1fdf2665eb98a3 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.store(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.store(false); + return CHIP_NO_ERROR; } template @@ -137,8 +139,15 @@ void GenericPlatformManagerImpl_Zephyr::_RunEventLoop(void) { Impl()->LockChipStack(); + 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; + } + SystemLayerSocketsLoop().EventLoopBegins(); - while (true) + while (mShouldRunEventLoop.load()) { SystemLayerSocketsLoop().PrepareEvents(); diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.h b/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.h index 684c7cabddcaf1..ecfb42d53e542e 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.h +++ b/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -91,6 +92,7 @@ class GenericPlatformManagerImpl_Zephyr : public GenericPlatformManagerImpl mShouldRunEventLoop; static void EventLoopTaskMain(void * thisPtr, void *, void *); }; diff --git a/src/lib/support/LambdaBridge.h b/src/lib/support/LambdaBridge.h index 32b0a17075fc80..390dc694803ffa 100644 --- a/src/lib/support/LambdaBridge.h +++ b/src/lib/support/LambdaBridge.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include @@ -35,17 +36,16 @@ class LambdaBridge 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)); + mLambdaProxy = [](const LambdaStorage & 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; + using LambdaStorage = std::aligned_storage_t; + void (*mLambdaProxy)(const LambdaStorage & body); + LambdaStorage mLambdaBody; }; static_assert(std::is_trivial::value, "LambdaBridge is not trivial"); diff --git a/src/platform/PlatformEventSupport.cpp b/src/platform/PlatformEventSupport.cpp index f7ed770bdf8f6f..7863aeea817bf2 100644 --- a/src/platform/PlatformEventSupport.cpp +++ b/src/platform/PlatformEventSupport.cpp @@ -27,8 +27,6 @@ #include -#if CHIP_SYSTEM_CONFIG_USE_LWIP - namespace chip { namespace System { @@ -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 e4538f9a930142..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", @@ -170,10 +171,6 @@ static_library("system") { } } - if (chip_system_config_use_lwip) { - sources += [ "PlatformEventSupport.h" ] - } - if (chip_with_nlfaultinjection) { sources += [ "SystemFaultInjection.cpp" ] public_deps += [ "${nlfaultinjection_root}:nlfaultinjection" ] diff --git a/src/system/SystemLayer.h b/src/system/SystemLayer.h index b61acf22c6fe70..d69c2ddb773a44 100644 --- a/src/system/SystemLayer.h +++ b/src/system/SystemLayer.h @@ -25,8 +25,6 @@ #pragma once -#include - // Include configuration headers #include 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)