summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2016-01-25 08:09:09 (GMT)
committerTobias Markmann <tm@ayena.de>2016-01-25 09:23:19 (GMT)
commit70651c20e9b9640cbf16a4d06fdae4845132045d (patch)
treec57e107231e0e3b9621cdbd1c38c21d5197c0674
parent0952786705da1cd36992f4f5e24bf744187a37f8 (diff)
downloadswift-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
-rw-r--r--Swiften/EventLoop/EventLoop.cpp19
-rw-r--r--Swiften/EventLoop/EventLoop.h11
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_;
};