Skip to content

Commit

Permalink
feat: add ExecuteUntil to event dispatchers, add EventDispatcherThrea…
Browse files Browse the repository at this point in the history
…dAware (#526)

* infra/event/EventDispatcher{WithWeakPtr}: Add ExecuteUntil

* Add infra/event/EventDispatcherThreadAware

* Apply suggestions from code review

Co-authored-by: Daan Timmer <[email protected]>

* Update infra/event/test/TestEventDispatcherThreadAware.cpp

Co-authored-by: Daan Timmer <[email protected]>

---------

Co-authored-by: Daan Timmer <[email protected]>
  • Loading branch information
richardapeters and daantimmer authored Jan 13, 2024
1 parent 9e7f949 commit d05d1f3
Show file tree
Hide file tree
Showing 12 changed files with 371 additions and 101 deletions.
7 changes: 7 additions & 0 deletions infra/event/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,12 @@ target_sources(infra.event PRIVATE
SystemStateManager.hpp
)

if (EMIL_HOST_BUILD)
target_sources(infra.event PRIVATE
EventDispatcherThreadAware.cpp
EventDispatcherThreadAware.hpp
)
endif()

add_subdirectory(test)
add_subdirectory(test_helper)
13 changes: 13 additions & 0 deletions infra/event/EventDispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ namespace infra
{}
}

void EventDispatcherWorkerImpl::ExecuteUntil(const infra::Function<bool()>& predicate)
{
while (!predicate())
{
ExecuteAllActions();

if (predicate())
break;

Idle();
}
}

void EventDispatcherWorkerImpl::ExecuteFirstAction()
{
if (scheduledActions[scheduledActionsPopIndex].second)
Expand Down
1 change: 1 addition & 0 deletions infra/event/EventDispatcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace infra

void Run();
void ExecuteAllActions();
void ExecuteUntil(const infra::Function<bool()>& predicate);

protected:
virtual void RequestExecution();
Expand Down
24 changes: 24 additions & 0 deletions infra/event/EventDispatcherThreadAware.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "infra/event/EventDispatcherThreadAware.hpp"

namespace infra
{
void EventDispatcherThreadAwareWorker::RequestExecution()
{
std::lock_guard lock{ mutex };

ready = true;
condition.notify_one();
}

void EventDispatcherThreadAwareWorker::Idle()
{
std::unique_lock lock{ mutex };

condition.wait(lock, [this]()
{
return ready;
});

ready = false;
}
}
28 changes: 28 additions & 0 deletions infra/event/EventDispatcherThreadAware.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef INFRA_EVENT_DISPATCHER_THREAD_AWARE_HPP
#define INFRA_EVENT_DISPATCHER_THREAD_AWARE_HPP

#include "infra/event/EventDispatcherWithWeakPtr.hpp"
#include <condition_variable>
#include <mutex>

namespace infra
{
class EventDispatcherThreadAwareWorker
: public infra::EventDispatcherWithWeakPtrWorker
{
public:
using EventDispatcherWithWeakPtrWorker::EventDispatcherWithWeakPtrWorker;

void RequestExecution() override;
void Idle() override;

private:
std::condition_variable condition;
std::mutex mutex;
bool ready{ false };
};

using EventDispatcherThreadAware = EventDispatcherWithWeakPtrConnector<EventDispatcherThreadAwareWorker>;
}

#endif
13 changes: 13 additions & 0 deletions infra/event/EventDispatcherWithWeakPtr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ namespace infra
{}
}

void EventDispatcherWithWeakPtrWorker::ExecuteUntil(const infra::Function<bool()>& predicate)
{
while (!predicate())
{
ExecuteAllActions();

if (predicate())
break;

Idle();
}
}

bool EventDispatcherWithWeakPtrWorker::IsIdle() const
{
return !scheduledActions[scheduledActionsPopIndex].second;
Expand Down
1 change: 1 addition & 0 deletions infra/event/EventDispatcherWithWeakPtr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ namespace infra

void Run();
void ExecuteAllActions();
void ExecuteUntil(const infra::Function<bool()>& predicate);

protected:
virtual void RequestExecution();
Expand Down
5 changes: 3 additions & 2 deletions infra/event/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ target_link_libraries(infra.event_test PUBLIC

target_sources(infra.event_test PRIVATE
TestClaimableResource.cpp
TestEventHandler.cpp
TestEventHandlerWithWeakPtr.cpp
TestEventDispatcher.cpp
TestEventDispatcherWithWeakPtr.cpp
TestEventDispatcherThreadAware.cpp
TestQueueForOneReaderOneIrqWriter.cpp
TestSystemStateManager.cpp
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ class EventDispatcherTest
, public infra::EventDispatcherFixture
{};

TEST_F(EventDispatcherTest, TestConstruction)
{}

TEST_F(EventDispatcherTest, TestSchedule)
TEST_F(EventDispatcherTest, scheduled_action_is_executed)
{
infra::MockCallback<void()> callback;
EXPECT_CALL(callback, callback());
Expand All @@ -24,7 +21,7 @@ TEST_F(EventDispatcherTest, TestSchedule)
ExecuteAllActions();
}

TEST_F(EventDispatcherTest, TestScheduleTwice)
TEST_F(EventDispatcherTest, two_actions_are_executed)
{
infra::MockCallback<void()> callback;
EXPECT_CALL(callback, callback()).Times(2);
Expand All @@ -40,7 +37,7 @@ TEST_F(EventDispatcherTest, TestScheduleTwice)
ExecuteAllActions();
}

TEST_F(EventDispatcherTest, TestExecuteOneEvent)
TEST_F(EventDispatcherTest, ExecuteFirstAction_executes_first_action)
{
infra::MockCallback<void()> callback;

Expand All @@ -63,6 +60,75 @@ TEST_F(EventDispatcherTest, TestExecuteOneEvent)
ExecuteFirstAction();
}

class EventDispatcherMock
: public infra::EventDispatcher::WithSize<50>
{
public:
MOCK_METHOD(void, RequestExecution, (), (override));
MOCK_METHOD(void, Idle, (), (override));
};

class EventDispatcherDetailedTest
: public testing::Test
, public EventDispatcherMock
{};

TEST_F(EventDispatcherDetailedTest, ExecuteUntil_executes_until_first_action_sets_predicate_true)
{
bool done = false;

EXPECT_CALL(*this, RequestExecution());
infra::EventDispatcher::Instance().Schedule([&]()
{
done = true;
});

ExecuteUntil([&]()
{
return done;
});
}

TEST_F(EventDispatcherDetailedTest, ExecuteUntil_executes_until_idle_sets_predicate_true)
{
bool done = false;

EXPECT_CALL(*this, RequestExecution());
infra::EventDispatcher::Instance().Schedule([&]() {});

EXPECT_CALL(*this, Idle()).WillOnce(testing::Invoke([&]()
{
done = true;
}));

ExecuteUntil([&]()
{
return done;
});
}

TEST_F(EventDispatcherDetailedTest, ExecuteUntil_executes_until_second_action_sets_predicate_true)
{
bool done = false;

EXPECT_CALL(*this, RequestExecution());
infra::EventDispatcher::Instance().Schedule([&]() {});

EXPECT_CALL(*this, Idle()).WillOnce(testing::Invoke([&]()
{
EXPECT_CALL(*this, RequestExecution());
infra::EventDispatcher::Instance().Schedule([&]()
{
done = true;
});
}));

ExecuteUntil([&]()
{
return done;
});
}

bool helper1turn = true;

void helper1()
Expand All @@ -77,7 +143,7 @@ void helper2()
helper1turn = true;
}

TEST_F(EventDispatcherTest, TestPerformance)
TEST_F(EventDispatcherTest, execute_a_lot)
{
for (int j = 0; j != 10; ++j)
{
Expand Down
47 changes: 47 additions & 0 deletions infra/event/test/TestEventDispatcherThreadAware.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "infra/event/EventDispatcherThreadAware.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <thread>

class EventDispatcherThreadAwareIdleCounting
: public infra::EventDispatcherThreadAware::WithSize<50>
{
protected:
void Idle() override
{
++idleCount;
infra::EventDispatcherThreadAware::WithSize<50>::Idle();
}

public:
int idleCount = 0;
};

class EventDispatcherThreadAwareTest
: public testing::Test
, public EventDispatcherThreadAwareIdleCounting
{};

TEST_F(EventDispatcherThreadAwareTest, scheduled_action_is_executed)
{
bool done = false;

std::thread t([&]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(50));

infra::EventDispatcher::Instance().Schedule([&]()
{
done = true;
});
});

ExecuteUntil([&]()
{
return done;
});

EXPECT_THAT(idleCount, testing::Eq(1));

t.join();
}
Loading

0 comments on commit d05d1f3

Please sign in to comment.