diff options
author | Tobias Markmann <tm@ayena.de> | 2016-01-25 08:09:09 (GMT) |
---|---|---|
committer | Tobias Markmann <tm@ayena.de> | 2016-01-25 09:23:19 (GMT) |
commit | 70651c20e9b9640cbf16a4d06fdae4845132045d (patch) | |
tree | c57e107231e0e3b9621cdbd1c38c21d5197c0674 /Swiften | |
parent | 0952786705da1cd36992f4f5e24bf744187a37f8 (diff) | |
download | swift-70651c20e9b9640cbf16a4d06fdae4845132045d.zip swift-70651c20e9b9640cbf16a4d06fdae4845132045d.tar.bz2 |
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
Diffstat (limited to 'Swiften')
-rw-r--r-- | Swiften/EventLoop/EventLoop.cpp | 19 | ||||
-rw-r--r-- | Swiften/EventLoop/EventLoop.h | 11 |
2 files changed, 20 insertions, 10 deletions
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 <boost/optional.hpp> #include <boost/thread/locks.hpp> -#include <Swiften/Base/foreach.h> #include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> 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<Event> nextEvents; @@ -62,6 +66,7 @@ void EventLoop::handleNextEvents() { } } } + handlingEvents_ = false; } if (callEventPosted) { @@ -74,7 +79,7 @@ void EventLoop::postEvent(boost::function<void ()> callback, boost::shared_ptr<E bool callEventPosted = false; { boost::recursive_mutex::scoped_lock lock(eventsMutex_); - + callEventPosted = events_.empty(); event.id = nextEventID_; diff --git a/Swiften/EventLoop/EventLoop.h b/Swiften/EventLoop/EventLoop.h index 27a8c9c..2687501 100644 --- a/Swiften/EventLoop/EventLoop.h +++ b/Swiften/EventLoop/EventLoop.h @@ -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. */ @@ -19,7 +19,7 @@ namespace Swift { /** * The \ref EventLoop class provides the abstract interface for implementing event loops to use with Swiften. - * + * * Events are added to the event queue using the \ref postEvent method and can be removed from the queue using * the \ref removeEventsFromOwner method. */ @@ -34,7 +34,7 @@ namespace Swift { * executed using the \ref removeEventsFromOwner method. */ void postEvent(boost::function<void ()> event, boost::shared_ptr<EventOwner> owner = boost::shared_ptr<EventOwner>()); - + /** * 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<Event> events_; + bool handlingEvents_; boost::recursive_mutex eventsMutex_; boost::recursive_mutex removeEventsMutex_; }; |