From e74f1092c7844190ac67b7fdcf4fe821f8278b81 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Fri, 2 Oct 2015 18:12:00 +0200 Subject: [PATCH] Fixed crash when events were (un)subscribed while events were processing --- include/Core/EventBroker.h | 8 +++++ src/game/Core/EventBroker.cpp | 67 ++++++++++++++++++++++++++--------- src/tests/EventFixture.h | 2 +- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/include/Core/EventBroker.h b/include/Core/EventBroker.h index cb5e39c..ce2a5a4 100644 --- a/include/Core/EventBroker.h +++ b/include/Core/EventBroker.h @@ -24,6 +24,7 @@ #include #include #include +#include #define EVENT_SUBSCRIBE_MEMBER(relay, handler) \ relay = decltype(relay)(std::bind(handler, this, std::placeholders::_1)); \ @@ -123,16 +124,23 @@ public: void Unsubscribe(BaseEventRelay &relay); private: + bool m_IsProcessing = false; + typedef std::string ContextTypeName_t; // typeid(ContextType).name() typedef std::string EventTypeName_t; // typeid(EventType).name() typedef std::unordered_multimap EventRelays_t; typedef std::unordered_map ContextRelays_t; ContextRelays_t m_ContextRelays; + std::vector m_RelaysToSubscribe; + std::vector m_RelaysToUnsubscribe; typedef std::list>> EventQueue_t; std::shared_ptr m_EventQueueRead; std::shared_ptr m_EventQueueWrite; + + void subscribeImmediate(BaseEventRelay& relay); + void unsubscribeImmediate(BaseEventRelay& relay); }; template diff --git a/src/game/Core/EventBroker.cpp b/src/game/Core/EventBroker.cpp index c8015c1..ce91fd9 100644 --- a/src/game/Core/EventBroker.cpp +++ b/src/game/Core/EventBroker.cpp @@ -29,32 +29,26 @@ dd::BaseEventRelay::~BaseEventRelay() void dd::EventBroker::Unsubscribe(BaseEventRelay &relay) // ? { - auto contextIt = m_ContextRelays.find(relay.m_ContextTypeName); - if (contextIt == m_ContextRelays.end()) - return; - - auto eventRelays = contextIt->second; - - auto itpair = eventRelays.equal_range(relay.m_EventTypeName); - for (auto it = itpair.first; it != itpair.second; ++it) - { - if (it->second == &relay) - { - relay.m_Broker = nullptr; - eventRelays.erase(it); - break; - } + if (m_IsProcessing) { + m_RelaysToUnsubscribe.push_back(&relay); + } else { + unsubscribeImmediate(relay); } } void dd::EventBroker::Subscribe(BaseEventRelay &relay) { - relay.m_Broker = this; - m_ContextRelays[relay.m_ContextTypeName].insert(std::make_pair(relay.m_EventTypeName, &relay)); + if (m_IsProcessing) { + m_RelaysToSubscribe.push_back(&relay); + } else { + subscribeImmediate(relay); + } } int dd::EventBroker::Process(std::string contextTypeName) { + m_IsProcessing = true; + auto it = m_ContextRelays.find(contextTypeName); if (it == m_ContextRelays.end()) return 0; @@ -77,6 +71,20 @@ int dd::EventBroker::Process(std::string contextTypeName) } } + m_IsProcessing = false; + + // Process pending subscriptions + for (auto& r : m_RelaysToSubscribe) { + subscribeImmediate(*r); + } + m_RelaysToSubscribe.clear(); + + // Process pending unsubscriptions + for (auto& r : m_RelaysToUnsubscribe) { + unsubscribeImmediate(*r); + } + m_RelaysToUnsubscribe.clear(); + return eventsProcessed; } @@ -84,4 +92,29 @@ void dd::EventBroker::Swap() { std::swap(m_EventQueueRead, m_EventQueueWrite); m_EventQueueWrite->clear(); + +} + +void dd::EventBroker::subscribeImmediate(dd::BaseEventRelay& relay) +{ + relay.m_Broker = this; + m_ContextRelays[relay.m_ContextTypeName].insert(std::make_pair(relay.m_EventTypeName, &relay)); +} + +void dd::EventBroker::unsubscribeImmediate(dd::BaseEventRelay& relay) +{ + auto contextIt = m_ContextRelays.find(relay.m_ContextTypeName); + if (contextIt == m_ContextRelays.end()) { + return; + } + + auto eventRelays = contextIt->second; + auto itpair = eventRelays.equal_range(relay.m_EventTypeName); + for (auto it = itpair.first; it != itpair.second; ++it) { + if (it->second == &relay) { + relay.m_Broker = nullptr; + eventRelays.erase(it); + break; + } + } } diff --git a/src/tests/EventFixture.h b/src/tests/EventFixture.h index 1548a08..4f78080 100644 --- a/src/tests/EventFixture.h +++ b/src/tests/EventFixture.h @@ -10,7 +10,7 @@ struct EventFixture EventFixture() { this->EventBroker = new dd::EventBroker(); - m_EEventType = decltype(m_EEventType)(std::bind(&OnEvent, this, std::placeholders::_1)); + m_EEventType = decltype(m_EEventType)(std::bind(&EventFixture::OnEvent, this, std::placeholders::_1)); this->EventBroker->Subscribe(m_EEventType); Run(); Check();