Skip to content

Commit

Permalink
Fix ScheduleLambda and Add unit-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kghost committed Nov 4, 2021
1 parent baff164 commit 8b264ef
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 31 deletions.
2 changes: 0 additions & 2 deletions src/include/platform/PlatformManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,7 @@ class PlatformManager
friend class Internal::GenericThreadStackManagerImpl_OpenThread_LwIP;
template <class>
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_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<ImplClass>::_InitChipStack();
SuccessOrExit(err);
Expand Down Expand Up @@ -119,12 +121,17 @@ void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_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;

Expand Down Expand Up @@ -251,8 +258,8 @@ CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_Shutdown(void)
template <class ImplClass>
CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_StopEventLoopTask(void)
{
VerifyOrDieWithMsg(false, DeviceLayer, "StopEventLoopTask is not implemented");
return CHIP_ERROR_NOT_IMPLEMENTED;
mShouldRunEventLoop.store(false);
return CHIP_NO_ERROR;
}

} // namespace Internal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
#include "task.h"
#endif

#include <atomic>

namespace chip {
namespace DeviceLayer {
namespace Internal {
Expand Down Expand Up @@ -92,6 +94,7 @@ class GenericPlatformManagerImpl_FreeRTOS : public GenericPlatformManagerImpl<Im
StaticQueue_t mEventQueueStruct;
#endif

std::atomic<bool> 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ CHIP_ERROR GenericPlatformManagerImpl_Zephyr<ImplClass>::_InitChipStack(void)
k_msgq_init(&mChipEventQueue, reinterpret_cast<char *>(&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<ImplClass>::_InitChipStack();
SuccessOrExit(err);
Expand Down Expand Up @@ -97,8 +99,8 @@ CHIP_ERROR GenericPlatformManagerImpl_Zephyr<ImplClass>::_StartChipTimer(System:
template <class ImplClass>
CHIP_ERROR GenericPlatformManagerImpl_Zephyr<ImplClass>::_StopEventLoopTask(void)
{
VerifyOrDieWithMsg(false, DeviceLayer, "StopEventLoopTask is not implemented");
return CHIP_ERROR_NOT_IMPLEMENTED;
mShouldRunEventLoop.store(false);
return CHIP_NO_ERROR;
}

template <class ImplClass>
Expand Down Expand Up @@ -137,8 +139,15 @@ void GenericPlatformManagerImpl_Zephyr<ImplClass>::_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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <platform/CHIPDeviceConfig.h>
#include <platform/internal/GenericPlatformManagerImpl.h>

#include <atomic>
#include <sys/select.h>
#include <zephyr.h>

Expand Down Expand Up @@ -91,6 +92,7 @@ class GenericPlatformManagerImpl_Zephyr : public GenericPlatformManagerImpl<Impl
void SysProcess();
void ProcessDeviceEvents();

std::atomic<bool> mShouldRunEventLoop;
static void EventLoopTaskMain(void * thisPtr, void *, void *);
};

Expand Down
12 changes: 6 additions & 6 deletions src/lib/support/LambdaBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include <string.h>
#include <type_traits>

#include <lib/core/CHIPConfig.h>

Expand All @@ -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<CHIP_CONFIG_LAMBDA_EVENT_SIZE, CHIP_CONFIG_LAMBDA_EVENT_ALIGN> & body) {
(*reinterpret_cast<const Lambda *>(&body))();
};
memcpy(&mLambdaBody, &lambda, sizeof(Lambda));
mLambdaProxy = [](const LambdaStorage & body) { (*reinterpret_cast<const Lambda *>(&body))(); };
::memcpy(&mLambdaBody, &lambda, sizeof(Lambda));
}

void operator()() const { mLambdaProxy(mLambdaBody); }

private:
void (*mLambdaProxy)(const std::aligned_storage<CHIP_CONFIG_LAMBDA_EVENT_SIZE, CHIP_CONFIG_LAMBDA_EVENT_ALIGN> & body);
std::aligned_storage<CHIP_CONFIG_LAMBDA_EVENT_SIZE, CHIP_CONFIG_LAMBDA_EVENT_ALIGN> mLambdaBody;
using LambdaStorage = std::aligned_storage_t<CHIP_CONFIG_LAMBDA_EVENT_SIZE, CHIP_CONFIG_LAMBDA_EVENT_ALIGN>;
void (*mLambdaProxy)(const LambdaStorage & body);
LambdaStorage mLambdaBody;
};

static_assert(std::is_trivial<LambdaBridge>::value, "LambdaBridge is not trivial");
Expand Down
4 changes: 0 additions & 4 deletions src/platform/PlatformEventSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@

#include <platform/PlatformManager.h>

#if CHIP_SYSTEM_CONFIG_USE_LWIP

namespace chip {
namespace System {

Expand Down Expand Up @@ -62,5 +60,3 @@ CHIP_ERROR PlatformEventing::StartTimer(System::Layer & aLayer, System::Clock::T

} // namespace System
} // namespace chip

#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
56 changes: 51 additions & 5 deletions src/platform/fake/PlatformManagerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#include <platform/PlatformManager.h>

#include <queue>

namespace chip {
namespace DeviceLayer {

Expand All @@ -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);
Expand All @@ -75,6 +118,9 @@ class PlatformManagerImpl final : public PlatformManager
friend class Internal::BLEManagerImpl;

static PlatformManagerImpl sInstance;

bool mShouldRunEventLoop = true;
std::queue<ChipDeviceEvent> mQueue;
};

/**
Expand Down
5 changes: 1 addition & 4 deletions src/system/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ static_library("system") {
output_name = "libSystemLayer"

sources = [
"PlatformEventSupport.h",
"SystemAlignSize.h",
"SystemClock.cpp",
"SystemClock.h",
Expand Down Expand Up @@ -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" ]
Expand Down
2 changes: 0 additions & 2 deletions src/system/SystemLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@

#pragma once

#include <type_traits>

// Include configuration headers
#include <system/SystemConfig.h>

Expand Down
1 change: 1 addition & 0 deletions src/system/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ chip_test_suite("tests") {
"TestSystemErrorStr.cpp",
"TestSystemObject.cpp",
"TestSystemPacketBuffer.cpp",
"TestSystemScheduleLambda.cpp",
"TestSystemTimer.cpp",
"TestSystemWakeEvent.cpp",
"TestTimeSource.cpp",
Expand Down
98 changes: 98 additions & 0 deletions src/system/tests/TestSystemScheduleLambda.cpp
Original file line number Diff line number Diff line change
@@ -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 <system/SystemConfig.h>

#include <lib/support/CodeUtils.h>
#include <lib/support/ErrorStr.h>
#include <lib/support/UnitTestRegistration.h>
#include <nlunit-test.h>
#include <platform/CHIPDeviceLayer.h>

// 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)

0 comments on commit 8b264ef

Please sign in to comment.