From 70651c20e9b9640cbf16a4d06fdae4845132045d Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 25 Jan 2016 09:09:09 +0100 Subject: Prevent recursive processing of event queue in EventLoop The old event loop had this protection, however it is missing in the new design. This adds this protection again as some external event loop implementations, e.g. the Qt event loop, directly process their event queue from an event handler. Test-Information: Unit and system tests pass on OS X 10.11.3. Change-Id: I10ce7160c3f201e2d5f53ab8289ddde1eb3262e8 diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp index b613645..8e7add5 100644 --- a/Swiften/EventLoop/EventLoop.cpp +++ b/Swiften/EventLoop/EventLoop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -15,8 +15,8 @@ #include #include -#include #include +#include namespace lambda = boost::lambda; @@ -31,11 +31,11 @@ inline void invokeCallback(const Event& event) { SWIFT_LOG(error) << "Uncaught exception in event loop: " << e.what() << std::endl; } catch (...) { - SWIFT_LOG(error) << "Uncaught non-exception in event loop" << std::endl; + SWIFT_LOG(error) << "Uncaught non-exception in event loop" << std::endl; } } -EventLoop::EventLoop() : nextEventID_(0) { +EventLoop::EventLoop() : nextEventID_(0), handlingEvents_(false) { } EventLoop::~EventLoop() { @@ -43,8 +43,12 @@ EventLoop::~EventLoop() { void EventLoop::handleNextEvents() { const int eventsBatched = 100; - bool callEventPosted = false; - { + // If handleNextEvents is already in progress, e.g. in case of a recursive call due to + // the event loop implementation, then do no handle further events. Instead call + // eventPosted() to continue event handling later. + bool callEventPosted = handlingEvents_; + if (!handlingEvents_) { + handlingEvents_ = true; boost::recursive_mutex::scoped_lock lock(removeEventsMutex_); { std::vector nextEvents; @@ -62,6 +66,7 @@ void EventLoop::handleNextEvents() { } } } + handlingEvents_ = false; } if (callEventPosted) { @@ -74,7 +79,7 @@ void EventLoop::postEvent(boost::function callback, boost::shared_ptr event, boost::shared_ptr owner = boost::shared_ptr()); - + /** * The \ref removeEventsFromOwner method removes all events from the specified \ref owner from the * event queue. @@ -47,6 +47,10 @@ namespace Swift { * at any point after the virtual \ref eventPosted method has been called. * This method does not block, except for short-time synchronization. * It can process multiple events before it reutrns. + * If called recursively, the event queue is not further processed. Instead, \ref eventPosted + * is called to notify the implementing event loop of the non-empty event queue. + * It is recommended to not call \ref handleNextEvents inside an event posted to the event loop + * as this can lead to an infinite loop. */ void handleNextEvents(); @@ -60,6 +64,7 @@ namespace Swift { private: unsigned int nextEventID_; std::list events_; + bool handlingEvents_; boost::recursive_mutex eventsMutex_; boost::recursive_mutex removeEventsMutex_; }; -- cgit v0.10.2-6-g49f6