Skip to content

Commit

Permalink
[Linux] Fix event loop task consecutive start/stop (#26195)
Browse files Browse the repository at this point in the history
* [Linux] Fix event loop task consecutive start/stop

* Wait for lambdas before stopping loop task

* Add comment for sleep() usage in test
  • Loading branch information
arkq authored and pull[bot] committed Dec 5, 2023
1 parent 0ca776b commit 1216328
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_InitChipStack()
// Call up to the base class _InitChipStack() to perform the bulk of the initialization.
ReturnErrorOnFailure(GenericPlatformManagerImpl<ImplClass>::_InitChipStack());

mShouldRunEventLoop.store(true, std::memory_order_relaxed);

int ret = pthread_cond_init(&mEventQueueStoppedCond, nullptr);
VerifyOrReturnError(ret == 0, CHIP_ERROR_POSIX(ret));

Expand Down Expand Up @@ -225,6 +227,8 @@ CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_StartEventLoopTask()
VerifyOrReturnError(err == 0, CHIP_ERROR_POSIX(err));
#endif

mShouldRunEventLoop.store(true, std::memory_order_relaxed);

//
// We need to grab the lock here since we have to protect setting
// mHasValidChipTask, which will be read right away upon creating the
Expand Down
48 changes: 44 additions & 4 deletions src/platform/tests/TestPlatformMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include <stdlib.h>
#include <string.h>

#include <atomic>

#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/UnitTestRegistration.h>
Expand Down Expand Up @@ -55,14 +57,52 @@ static void TestPlatformMgr_InitShutdown(nlTestSuite * inSuite, void * inContext

static void TestPlatformMgr_BasicEventLoopTask(nlTestSuite * inSuite, void * inContext)
{
std::atomic<int> counterRun{ 0 };

CHIP_ERROR err = PlatformMgr().InitChipStack();
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

err = PlatformMgr().StartEventLoopTask();
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
// Start/stop the event loop task a few times.
for (size_t i = 0; i < 3; i++)
{
err = PlatformMgr().StartEventLoopTask();
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

std::atomic<int> counterSync{ 2 };

// Verify that the event loop will not exit until we tell it to by
// scheduling few lambdas (for the test to pass, the event loop will
// have to process more than one event).
DeviceLayer::SystemLayer().ScheduleLambda([&]() {
counterRun++;
counterSync--;
});

// Sleep for a short time to allow the event loop to process the
// scheduled event and go to idle state. Without this sleep, the
// event loop may process both scheduled lambdas during single
// iteration of the event loop which would defeat the purpose of
// this test on POSIX platforms where the event loop is implemented
// using a "do { ... } while (shouldRun)" construct.
chip::test_utils::SleepMillis(10);

DeviceLayer::SystemLayer().ScheduleLambda([&]() {
counterRun++;
counterSync--;
});

// Wait for the event loop to process the scheduled events.
// Note, that we can not use any synchronization primitives like
// condition variables or barriers, because the test has to compile
// on all platforms. Instead we use a busy loop with a timeout.
for (size_t t = 0; counterSync != 0 && t < 1000; t++)
chip::test_utils::SleepMillis(1);

err = PlatformMgr().StopEventLoopTask();
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
}

err = PlatformMgr().StopEventLoopTask();
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, counterRun == (3 * 2));

PlatformMgr().Shutdown();
}
Expand Down

0 comments on commit 1216328

Please sign in to comment.