diff --git a/src/logid/backend/EventHandlerList.h b/src/logid/backend/EventHandlerList.h index edad88c..be67143 100644 --- a/src/logid/backend/EventHandlerList.h +++ b/src/logid/backend/EventHandlerList.h @@ -24,21 +24,64 @@ #include #include #include +#include template class EventHandlerLock; template -struct EventHandlerList { - typedef std::list list_t; - typedef typename list_t::const_iterator iterator_t; +class EventHandlerList { +public: + typedef std::list> list_t; + typedef typename list_t::iterator iterator_t; +private: + list_t list; + std::shared_mutex mutex; + std::shared_mutex add_mutex; - std::list list; - mutable std::shared_mutex mutex; + void cleanup() { + std::unique_lock lock(mutex, std::try_to_lock); + if (lock.owns_lock()) { + std::list to_remove; + for (auto it = list.begin(); it != list.end(); ++it) { + if (!it->second) + to_remove.push_back(it); + } + + for(auto& it : to_remove) + list.erase(it); + } + } +public: + iterator_t add(typename T::EventHandler handler) { + std::unique_lock add_lock(add_mutex); + list.emplace_front(std::move(handler), true); + return list.begin(); + } void remove(iterator_t iterator) { - std::unique_lock lock(mutex); - list.erase(iterator); + std::unique_lock lock(mutex, std::try_to_lock); + if (lock.owns_lock()) { + std::unique_lock add_lock(add_mutex); + list.erase(iterator); + } else { + iterator->second = false; + } + } + + template + void run_all(Arg arg) { + cleanup(); + std::shared_lock lock(mutex); + std::shared_lock add_lock(add_mutex); + for (auto& handler : list) { + add_lock.unlock(); + if (handler.second) { + if (handler.first.condition(arg)) + handler.first.callback(arg); + } + add_lock.lock(); + } } }; diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index f0da17c..e78a3bf 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -214,19 +214,14 @@ void Device::_init() { } EventHandlerLock Device::addEventHandler(EventHandler handler) { - std::unique_lock lock(_event_handlers->mutex); - _event_handlers->list.emplace_front(std::move(handler)); - return {_event_handlers, _event_handlers->list.cbegin()}; + return {_event_handlers, _event_handlers->add(std::move(handler))}; } void Device::handleEvent(Report& report) { if (responseReport(report)) return; - std::shared_lock lock(_event_handlers->mutex); - for (auto& handler: _event_handlers->list) - if (handler.condition(report)) - handler.callback(report); + _event_handlers->run_all(report); } Report Device::sendReport(const Report& report) { diff --git a/src/logid/backend/raw/RawDevice.cpp b/src/logid/backend/raw/RawDevice.cpp index 213b546..11a886a 100644 --- a/src/logid/backend/raw/RawDevice.cpp +++ b/src/logid/backend/raw/RawDevice.cpp @@ -156,9 +156,7 @@ void RawDevice::sendReport(const std::vector& report) { } EventHandlerLock RawDevice::addEventHandler(RawEventHandler handler) { - std::unique_lock lock(_event_handlers->mutex); - _event_handlers->list.emplace_front(std::move(handler)); - return {_event_handlers, _event_handlers->list.cbegin()}; + return {_event_handlers, _event_handlers->add(std::forward(handler))}; } void RawDevice::_readReports() { @@ -181,8 +179,5 @@ void RawDevice::_readReports() { } void RawDevice::_handleEvent(const std::vector& report) { - std::shared_lock lock(_event_handlers->mutex); - for (auto& handler : _event_handlers->list) - if (handler.condition(report)) - handler.callback(report); + _event_handlers->run_all(report); }