diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index a58684849ebd3d02a087ea63434dd8a3891a0596..9ca0827a31f44b904de3e24bc2b4e562e37bc12d 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -1351,27 +1351,41 @@ ManagerImpl::removeStream(Call& call) getRingBufferPool().unBindAll(call_id); } +// Not thread-safe, SHOULD be called in same thread that run poolEvents() void ManagerImpl::registerEventHandler(uintptr_t handlerId, EventHandler handler) { - eventHandlerMap_.insert(std::make_pair(handlerId, handler)); + eventHandlerMap_[handlerId] = handler; } +// Not thread-safe, SHOULD be called in same thread that run poolEvents() void ManagerImpl::unregisterEventHandler(uintptr_t handlerId) { - eventHandlerMap_.erase(handlerId); + auto iter = eventHandlerMap_.find(handlerId); + if (iter != eventHandlerMap_.end()) { + if (iter == nextEventHandler_) + nextEventHandler_ = eventHandlerMap_.erase(iter); + else + eventHandlerMap_.erase(iter); + } } // Must be invoked periodically by a timer from the main event loop void ManagerImpl::pollEvents() { - // Make a copy of handlers map as handlers can modify this map - const auto handlers = eventHandlerMap_; - for (const auto& it : handlers) { + auto iter = eventHandlerMap_.begin(); + while (iter != eventHandlerMap_.end()) { if (finished_) return; - it.second(); + + // WARN: following callback can do anything and typically + // calls (un)registerEventHandler. + // Think twice before modify this code. + + nextEventHandler_ = std::next(iter); + iter->second(); + iter = nextEventHandler_; } } diff --git a/daemon/src/managerimpl.h b/daemon/src/managerimpl.h index bb7a4a6f887ff839e7844c9d832fbd86a9e45628..0371145f715fb4da502a9a9a3bb5486506c999b9 100644 --- a/daemon/src/managerimpl.h +++ b/daemon/src/managerimpl.h @@ -968,7 +968,8 @@ class ManagerImpl { private: NON_COPYABLE(ManagerImpl); - std::map<uintptr_t, EventHandler> eventHandlerMap_{}; + std::map<uintptr_t, EventHandler> eventHandlerMap_; + decltype(eventHandlerMap_)::iterator nextEventHandler_; /** * Test if call is a valid call, i.e. have been created and stored in