summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/EventLoop')
-rw-r--r--Swiften/EventLoop/BoostASIOEventLoop.cpp37
-rw-r--r--Swiften/EventLoop/BoostASIOEventLoop.h35
-rw-r--r--Swiften/EventLoop/Cocoa/CocoaEvent.h18
-rw-r--r--Swiften/EventLoop/Cocoa/CocoaEvent.mm26
-rw-r--r--Swiften/EventLoop/Cocoa/CocoaEventLoop.h26
-rw-r--r--Swiften/EventLoop/Cocoa/CocoaEventLoop.mm40
-rw-r--r--Swiften/EventLoop/DummyEventLoop.cpp29
-rw-r--r--Swiften/EventLoop/DummyEventLoop.h45
-rw-r--r--Swiften/EventLoop/Event.cpp26
-rw-r--r--Swiften/EventLoop/Event.h35
-rw-r--r--Swiften/EventLoop/EventLoop.cpp133
-rw-r--r--Swiften/EventLoop/EventLoop.h90
-rw-r--r--Swiften/EventLoop/EventOwner.cpp6
-rw-r--r--Swiften/EventLoop/EventOwner.h14
-rw-r--r--Swiften/EventLoop/Qt/QtEventLoop.h84
-rw-r--r--Swiften/EventLoop/SConscript31
-rw-r--r--Swiften/EventLoop/SimpleEventLoop.cpp70
-rw-r--r--Swiften/EventLoop/SimpleEventLoop.h58
-rw-r--r--Swiften/EventLoop/SingleThreadedEventLoop.cpp66
-rw-r--r--Swiften/EventLoop/SingleThreadedEventLoop.h66
-rw-r--r--Swiften/EventLoop/UnitTest/EventLoopTest.cpp165
-rw-r--r--Swiften/EventLoop/UnitTest/SimpleEventLoopTest.cpp108
22 files changed, 684 insertions, 524 deletions
diff --git a/Swiften/EventLoop/BoostASIOEventLoop.cpp b/Swiften/EventLoop/BoostASIOEventLoop.cpp
new file mode 100644
index 0000000..45dd4a2
--- /dev/null
+++ b/Swiften/EventLoop/BoostASIOEventLoop.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2019 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/EventLoop/BoostASIOEventLoop.h>
+
+#include <boost/bind.hpp>
+
+namespace Swift {
+
+BoostASIOEventLoop::BoostASIOEventLoop(std::shared_ptr<boost::asio::io_service> ioService) : ioService_(ioService) {
+
+}
+
+BoostASIOEventLoop::~BoostASIOEventLoop() {
+
+}
+
+void BoostASIOEventLoop::handleASIOEvent() {
+ {
+ std::unique_lock<std::recursive_mutex> lock(isEventInASIOEventLoopMutex_);
+ isEventInASIOEventLoop_ = false;
+ }
+ handleNextEvent();
+}
+
+void BoostASIOEventLoop::eventPosted() {
+ std::unique_lock<std::recursive_mutex> lock(isEventInASIOEventLoopMutex_);
+ if (!isEventInASIOEventLoop_) {
+ isEventInASIOEventLoop_ = true;
+ ioService_->post(boost::bind(&BoostASIOEventLoop::handleASIOEvent, this));
+ }
+}
+
+}
diff --git a/Swiften/EventLoop/BoostASIOEventLoop.h b/Swiften/EventLoop/BoostASIOEventLoop.h
new file mode 100644
index 0000000..fbdf443
--- /dev/null
+++ b/Swiften/EventLoop/BoostASIOEventLoop.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+#include <mutex>
+
+#include <boost/asio/io_service.hpp>
+
+#include <Swiften/Base/API.h>
+#include <Swiften/EventLoop/Event.h>
+#include <Swiften/EventLoop/EventLoop.h>
+
+namespace Swift {
+ class SWIFTEN_API BoostASIOEventLoop : public EventLoop {
+ public:
+ BoostASIOEventLoop(std::shared_ptr<boost::asio::io_service> ioService);
+ virtual ~BoostASIOEventLoop();
+
+ protected:
+ void handleASIOEvent();
+
+ virtual void eventPosted();
+
+ private:
+ std::shared_ptr<boost::asio::io_service> ioService_;
+
+ bool isEventInASIOEventLoop_ = false;
+ std::recursive_mutex isEventInASIOEventLoopMutex_;
+ };
+}
diff --git a/Swiften/EventLoop/Cocoa/CocoaEvent.h b/Swiften/EventLoop/Cocoa/CocoaEvent.h
index 89d056f..945056e 100644
--- a/Swiften/EventLoop/Cocoa/CocoaEvent.h
+++ b/Swiften/EventLoop/Cocoa/CocoaEvent.h
@@ -1,16 +1,19 @@
/*
- * Copyright (c) 2010-2013 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
#include <Foundation/Foundation.h>
+// The following line is a workaround for a bug in Boost 1.60 when building as C++11.
+// See ticket #11897 and #11863 in Boost's bug tracker.
+#undef check
+
namespace Swift {
- class Event;
- class CocoaEventLoop;
+ class CocoaEventLoop;
}
// Using deprecated declaration of instance vars in interface, because this
@@ -19,14 +22,13 @@ namespace Swift {
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
@interface CocoaEvent : NSObject {
- Swift::Event* event;
- Swift::CocoaEventLoop* eventLoop;
+ Swift::CocoaEventLoop* eventLoop;
}
#pragma clang diagnostic pop
// Takes ownership of event
-- (id) initWithEvent: (Swift::Event*) e eventLoop: (Swift::CocoaEventLoop*) el;
+- (id) init:(Swift::CocoaEventLoop*) el;
- (void) process;
- (void) dealloc;
diff --git a/Swiften/EventLoop/Cocoa/CocoaEvent.mm b/Swiften/EventLoop/Cocoa/CocoaEvent.mm
index 7b1b4b0..fc9695b 100644
--- a/Swiften/EventLoop/Cocoa/CocoaEvent.mm
+++ b/Swiften/EventLoop/Cocoa/CocoaEvent.mm
@@ -1,25 +1,29 @@
+/*
+ * Copyright (c) 2015-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
#include <Swiften/EventLoop/Cocoa/CocoaEvent.h>
-#include <Swiften/EventLoop/Event.h>
+
#include <Swiften/EventLoop/Cocoa/CocoaEventLoop.h>
@implementation CocoaEvent
-- (id) initWithEvent: (Swift::Event*) e eventLoop: (Swift::CocoaEventLoop*) el {
- self = [super init];
- if (self != nil) {
- event = e;
- eventLoop = el;
- }
- return self;
+- (id) init:(Swift::CocoaEventLoop*) el {
+ self = [super init];
+ if (self != nil) {
+ eventLoop = el;
+ }
+ return self;
}
- (void) process {
- eventLoop->handleEvent(*event);
+ eventLoop->handleNextCocoaEvent();
}
- (void) dealloc {
- delete event;
- [super dealloc];
+ [super dealloc];
}
@end
diff --git a/Swiften/EventLoop/Cocoa/CocoaEventLoop.h b/Swiften/EventLoop/Cocoa/CocoaEventLoop.h
index 60ef32b..7f20e6c 100644
--- a/Swiften/EventLoop/Cocoa/CocoaEventLoop.h
+++ b/Swiften/EventLoop/Cocoa/CocoaEventLoop.h
@@ -1,20 +1,28 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
+#include <mutex>
+
#include <Swiften/EventLoop/EventLoop.h>
namespace Swift {
- class CocoaEventLoop : public EventLoop {
- public:
- CocoaEventLoop();
+ class CocoaEventLoop : public EventLoop {
+ public:
+ CocoaEventLoop();
+ virtual ~CocoaEventLoop();
+
+ void handleNextCocoaEvent();
- virtual void post(const Event& event);
+ protected:
+ virtual void eventPosted();
- using EventLoop::handleEvent;
- };
+ private:
+ bool isEventInCocoaEventLoop_;
+ std::recursive_mutex isEventInCocoaEventLoopMutex_;
+ };
}
diff --git a/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm b/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm
index ba73884..39dc7ec 100644
--- a/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm
+++ b/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm
@@ -1,3 +1,9 @@
+/*
+ * Copyright (c) 2015-2019 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
#include <Swiften/EventLoop/Cocoa/CocoaEventLoop.h>
#include <Swiften/EventLoop/Cocoa/CocoaEvent.h>
@@ -5,17 +11,33 @@
namespace Swift {
-CocoaEventLoop::CocoaEventLoop() {
+CocoaEventLoop::CocoaEventLoop() : isEventInCocoaEventLoop_(false) {
+}
+
+CocoaEventLoop::~CocoaEventLoop() {
+
}
-void CocoaEventLoop::post(const Event& event) {
- Event* eventCopy = new Event(event);
- CocoaEvent* cocoaEvent = [[CocoaEvent alloc] initWithEvent: eventCopy eventLoop: this];
- [cocoaEvent
- performSelectorOnMainThread:@selector(process)
- withObject: nil
- waitUntilDone: NO];
- [cocoaEvent release];
+void CocoaEventLoop::handleNextCocoaEvent() {
+ {
+ std::unique_lock<std::recursive_mutex> lock(isEventInCocoaEventLoopMutex_);
+ isEventInCocoaEventLoop_ = false;
+ }
+ handleNextEvent();
+}
+
+void CocoaEventLoop::eventPosted() {
+ std::unique_lock<std::recursive_mutex> lock(isEventInCocoaEventLoopMutex_);
+ if (!isEventInCocoaEventLoop_) {
+ isEventInCocoaEventLoop_ = true;
+
+ CocoaEvent* cocoaEvent = [[CocoaEvent alloc] init: this];
+ [cocoaEvent
+ performSelectorOnMainThread:@selector(process)
+ withObject: nil
+ waitUntilDone: NO];
+ [cocoaEvent release];
+ }
}
}
diff --git a/Swiften/EventLoop/DummyEventLoop.cpp b/Swiften/EventLoop/DummyEventLoop.cpp
index 3741eec..234ba7a 100644
--- a/Swiften/EventLoop/DummyEventLoop.cpp
+++ b/Swiften/EventLoop/DummyEventLoop.cpp
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2019 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#include <Swiften/EventLoop/DummyEventLoop.h>
-#include <iostream>
+#include <Swiften/Base/Log.h>
namespace Swift {
@@ -14,11 +14,24 @@ DummyEventLoop::DummyEventLoop() {
}
DummyEventLoop::~DummyEventLoop() {
- if (!events_.empty()) {
- std::cerr << "DummyEventLoop: Unhandled events at destruction time" << std::endl;
- }
- events_.clear();
+ if (hasEvents()) {
+ SWIFT_LOG(warning) << "DummyEventLoop: Unhandled events at destruction time";
+ }
}
+void DummyEventLoop::processEvents() {
+ while(hasEvents()) {
+ hasEvents_ = false;
+ handleNextEvent();
+ }
+}
+
+bool DummyEventLoop::hasEvents() {
+ return hasEvents_;
+}
+
+void DummyEventLoop::eventPosted() {
+ hasEvents_ = true;
+}
}
diff --git a/Swiften/EventLoop/DummyEventLoop.h b/Swiften/EventLoop/DummyEventLoop.h
index 0e5e06d..da2a360 100644
--- a/Swiften/EventLoop/DummyEventLoop.h
+++ b/Swiften/EventLoop/DummyEventLoop.h
@@ -1,38 +1,29 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
-#include <deque>
+#include <atomic>
#include <Swiften/Base/API.h>
#include <Swiften/EventLoop/EventLoop.h>
namespace Swift {
- class SWIFTEN_API DummyEventLoop : public EventLoop {
- public:
- DummyEventLoop();
- ~DummyEventLoop();
-
- void processEvents() {
- while (!events_.empty()) {
- handleEvent(events_[0]);
- events_.pop_front();
- }
- }
-
- bool hasEvents() {
- return !events_.empty();
- }
-
- virtual void post(const Event& event) {
- events_.push_back(event);
- }
-
- private:
- std::deque<Event> events_;
- };
+ class SWIFTEN_API DummyEventLoop : public EventLoop {
+ public:
+ DummyEventLoop();
+ virtual ~DummyEventLoop();
+
+ void processEvents();
+
+ bool hasEvents();
+
+ virtual void eventPosted();
+
+ private:
+ std::atomic<bool> hasEvents_ = ATOMIC_VAR_INIT(false);
+ };
}
diff --git a/Swiften/EventLoop/Event.cpp b/Swiften/EventLoop/Event.cpp
index aa002d3..15d7146 100644
--- a/Swiften/EventLoop/Event.cpp
+++ b/Swiften/EventLoop/Event.cpp
@@ -1,22 +1,22 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#include <Swiften/EventLoop/Event.h>
-#include <typeinfo>
#include <iostream>
+#include <typeinfo>
std::ostream& operator<<(std::ostream& os, const Swift::Event& e) {
- os << "Event(" << e.id << ",";
- if (e.owner) {
- os << typeid(*e.owner.get()).name();
- }
- else {
- os << "null";
- }
- os << ")";
- return os;
+ os << "Event(" << e.id << ",";
+ if (e.owner) {
+ os << typeid(*e.owner.get()).name();
+ }
+ else {
+ os << "null";
+ }
+ os << ")";
+ return os;
}
diff --git a/Swiften/EventLoop/Event.h b/Swiften/EventLoop/Event.h
index b1d7cac..e92bb33 100644
--- a/Swiften/EventLoop/Event.h
+++ b/Swiften/EventLoop/Event.h
@@ -1,30 +1,31 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
-#include <boost/shared_ptr.hpp>
+#include <memory>
+
#include <boost/function.hpp>
#include <Swiften/EventLoop/EventOwner.h>
namespace Swift {
- class Event {
- public:
- Event(boost::shared_ptr<EventOwner> owner, const boost::function<void()>& callback) : id(~0U), owner(owner), callback(callback) {
- }
-
- bool operator==(const Event& o) const {
- return o.id == id;
- }
-
- unsigned int id;
- boost::shared_ptr<EventOwner> owner;
- boost::function<void()> callback;
- };
+ class Event {
+ public:
+ Event(std::shared_ptr<EventOwner> owner, const boost::function<void()>& callback) : id(~0U), owner(owner), callback(callback) {
+ }
+
+ bool operator==(const Event& o) const {
+ return o.id == id;
+ }
+
+ unsigned int id;
+ std::shared_ptr<EventOwner> owner;
+ boost::function<void()> callback;
+ };
}
std::ostream& operator<<(std::ostream& os, const Swift::Event& e);
diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp
index 502bc49..1852f3f 100644
--- a/Swiften/EventLoop/EventLoop.cpp
+++ b/Swiften/EventLoop/EventLoop.cpp
@@ -1,36 +1,32 @@
/*
- * Copyright (c) 2010-2013 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2019 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#include <Swiften/EventLoop/EventLoop.h>
#include <algorithm>
-#include <iostream>
#include <cassert>
-#include <boost/bind.hpp>
-#include <boost/lambda/lambda.hpp>
-#include <boost/lambda/bind.hpp>
-#include <boost/thread/locks.hpp>
+#include <vector>
-#include <Swiften/Base/Log.h>
+#include <boost/optional.hpp>
-namespace lambda = boost::lambda;
+#include <Swiften/Base/Log.h>
namespace Swift {
inline void invokeCallback(const Event& event) {
- try {
- assert(!event.callback.empty());
- event.callback();
- }
- catch (const std::exception& e) {
- std::cerr << "Uncaught exception in event loop: " << e.what() << std::endl;
- }
- catch (...) {
- std::cerr << "Uncaught non-exception in event loop" << std::endl;
- }
+ try {
+ assert(!event.callback.empty());
+ event.callback();
+ }
+ catch (const std::exception& e) {
+ SWIFT_LOG(error) << "Uncaught exception in event loop: " << e.what();
+ }
+ catch (...) {
+ SWIFT_LOG(error) << "Uncaught non-exception in event loop";
+ }
}
EventLoop::EventLoop() : nextEventID_(0), handlingEvents_(false) {
@@ -39,55 +35,62 @@ EventLoop::EventLoop() : nextEventID_(0), handlingEvents_(false) {
EventLoop::~EventLoop() {
}
-void EventLoop::handleEvent(const Event& event) {
- //SWIFT_LOG(debug) << "Handling event " << event.id << std::endl;
-
- if (handlingEvents_) {
- // We're being called recursively. Push in the list of events to
- // handle in the parent handleEvent()
- eventsToHandle_.push_back(event);
- return;
- }
-
- bool doCallback = false;
- {
- boost::lock_guard<boost::mutex> lock(eventsMutex_);
- std::list<Event>::iterator i = std::find(events_.begin(), events_.end(), event);
- if (i != events_.end()) {
- doCallback = true;
- events_.erase(i);
- }
- }
- if (doCallback) {
- handlingEvents_ = true;
- invokeCallback(event);
-
- // Process events that were passed to handleEvent during the callback
- // (i.e. through recursive calls of handleEvent)
- while (!eventsToHandle_.empty()) {
- Event nextEvent = eventsToHandle_.front();
- eventsToHandle_.pop_front();
- invokeCallback(nextEvent);
- }
- handlingEvents_ = false;
- }
+void EventLoop::handleNextEvent() {
+ // If handleNextEvent 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;
+ std::unique_lock<std::recursive_mutex> lock(removeEventsMutex_);
+ {
+ boost::optional<Event> nextEvent;
+ {
+ std::unique_lock<std::recursive_mutex> eventsLock(eventsMutex_);
+ if (!events_.empty()) {
+ nextEvent = events_.front();
+ events_.pop_front();
+ }
+ callEventPosted = !events_.empty();
+ }
+ if (nextEvent) {
+ invokeCallback(*nextEvent);
+ }
+ }
+ handlingEvents_ = false;
+ }
+
+ if (callEventPosted) {
+ eventPosted();
+ }
}
-void EventLoop::postEvent(boost::function<void ()> callback, boost::shared_ptr<EventOwner> owner) {
- Event event(owner, callback);
- {
- boost::lock_guard<boost::mutex> lock(eventsMutex_);
- event.id = nextEventID_;
- nextEventID_++;
- events_.push_back(event);
- }
- //SWIFT_LOG(debug) << "Posting event " << event.id << std::endl;
- post(event);
+void EventLoop::postEvent(boost::function<void ()> callback, std::shared_ptr<EventOwner> owner) {
+ Event event(owner, callback);
+ bool callEventPosted = false;
+ {
+ std::unique_lock<std::recursive_mutex> lock(eventsMutex_);
+
+ callEventPosted = events_.empty();
+
+ event.id = nextEventID_;
+ nextEventID_++;
+ events_.push_back(event);
+ }
+ if (callEventPosted) {
+ eventPosted();
+ }
}
-void EventLoop::removeEventsFromOwner(boost::shared_ptr<EventOwner> owner) {
- boost::lock_guard<boost::mutex> lock(eventsMutex_);
- events_.remove_if(lambda::bind(&Event::owner, lambda::_1) == owner);
+void EventLoop::removeEventsFromOwner(std::shared_ptr<EventOwner> owner) {
+ std::unique_lock<std::recursive_mutex> removeLock(removeEventsMutex_, std::defer_lock);
+ std::unique_lock<std::recursive_mutex> eventsLock(eventsMutex_, std::defer_lock);
+
+ std::lock(removeLock, eventsLock);
+
+ events_.remove_if([&](const Event& event) {
+ return event.owner == owner;
+ });
}
}
diff --git a/Swiften/EventLoop/EventLoop.h b/Swiften/EventLoop/EventLoop.h
index 587ba22..f61b9bc 100644
--- a/Swiften/EventLoop/EventLoop.h
+++ b/Swiften/EventLoop/EventLoop.h
@@ -1,44 +1,70 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2019 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
-#include <boost/function.hpp>
-#include <boost/thread/mutex.hpp>
#include <list>
-#include <deque>
+#include <mutex>
+
+#include <boost/function.hpp>
#include <Swiften/Base/API.h>
#include <Swiften/EventLoop/Event.h>
namespace Swift {
- class EventOwner;
-
- class SWIFTEN_API EventLoop {
- public:
- EventLoop();
- virtual ~EventLoop();
-
- void postEvent(boost::function<void ()> event, boost::shared_ptr<EventOwner> owner = boost::shared_ptr<EventOwner>());
- void removeEventsFromOwner(boost::shared_ptr<EventOwner> owner);
-
- protected:
- /**
- * Reimplement this to call handleEvent(event) from the thread in which
- * the event loop is residing.
- */
- virtual void post(const Event& event) = 0;
-
- void handleEvent(const Event& event);
-
- private:
- boost::mutex eventsMutex_;
- unsigned int nextEventID_;
- std::list<Event> events_;
- bool handlingEvents_;
- std::deque<Event> eventsToHandle_;
- };
+ class EventOwner;
+
+ /**
+ * 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.
+ */
+ class SWIFTEN_API EventLoop {
+ public:
+ EventLoop();
+ virtual ~EventLoop();
+
+ /**
+ * The \ref postEvent method allows events to be added to the event queue of the \ref EventLoop.
+ * An optional \ref EventOwner can be passed as \p owner, allowing later removal of events that have not yet been
+ * executed using the \ref removeEventsFromOwner method.
+ */
+ void postEvent(boost::function<void ()> event, std::shared_ptr<EventOwner> owner = std::shared_ptr<EventOwner>());
+
+ /**
+ * The \ref removeEventsFromOwner method removes all events from the specified \p owner from the
+ * event queue.
+ */
+ void removeEventsFromOwner(std::shared_ptr<EventOwner> owner);
+
+ protected:
+ /**
+ * The \ref handleNextEvent method is called by an implementation of the abstract \ref EventLoop class
+ * at any point after the virtual \ref eventPosted method has been called.
+ * This method does not block, except for short-time synchronization.
+ * 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 handleNextEvent inside an event posted to the event loop
+ * as this can lead to an infinite loop.
+ */
+ void handleNextEvent();
+
+ /**
+ * The \ref eventPosted virtual method serves as notification for when events are still available in the queue.
+ * It is called after the first event is posted to an empty queue or after an event has been handled in
+ * \ref handleNextEvent and there are still remaining events in the queue.
+ */
+ virtual void eventPosted() = 0;
+
+ private:
+ unsigned int nextEventID_;
+ std::list<Event> events_;
+ bool handlingEvents_;
+ std::recursive_mutex eventsMutex_;
+ std::recursive_mutex removeEventsMutex_;
+ };
}
diff --git a/Swiften/EventLoop/EventOwner.cpp b/Swiften/EventLoop/EventOwner.cpp
index 9970499..56e0faa 100644
--- a/Swiften/EventLoop/EventOwner.cpp
+++ b/Swiften/EventLoop/EventOwner.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#include <Swiften/EventLoop/EventOwner.h>
diff --git a/Swiften/EventLoop/EventOwner.h b/Swiften/EventLoop/EventOwner.h
index 43a059b..cd4a80b 100644
--- a/Swiften/EventLoop/EventOwner.h
+++ b/Swiften/EventLoop/EventOwner.h
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
@@ -9,8 +9,8 @@
#include <Swiften/Base/API.h>
namespace Swift {
- class SWIFTEN_API EventOwner {
- public:
- virtual ~EventOwner();
- };
+ class SWIFTEN_API EventOwner {
+ public:
+ virtual ~EventOwner();
+ };
}
diff --git a/Swiften/EventLoop/Qt/QtEventLoop.h b/Swiften/EventLoop/Qt/QtEventLoop.h
index 0097cf9..cf374ab 100644
--- a/Swiften/EventLoop/Qt/QtEventLoop.h
+++ b/Swiften/EventLoop/Qt/QtEventLoop.h
@@ -1,47 +1,59 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2019 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
-#include <QObject>
-#include <QEvent>
+#include <mutex>
+
#include <QCoreApplication>
+#include <QEvent>
+#include <QObject>
#include <Swiften/EventLoop/EventLoop.h>
namespace Swift {
- class QtEventLoop : public QObject, public EventLoop {
- public:
- QtEventLoop() {}
- ~QtEventLoop() {
- QCoreApplication::removePostedEvents(this);
- }
-
- virtual void post(const Swift::Event& event) {
- QCoreApplication::postEvent(this, new Event(event));
- }
-
- virtual bool event(QEvent* qevent) {
- Event* event = dynamic_cast<Event*>(qevent);
- if (event) {
- handleEvent(event->event_);
- //event->deleteLater(); FIXME: Leak?
- return true;
- }
-
- return false;
- }
-
- private:
- struct Event : public QEvent {
- Event(const Swift::Event& event) :
- QEvent(QEvent::User), event_(event) {
- }
-
- Swift::Event event_;
- };
- };
+ class QtEventLoop : public QObject, public EventLoop {
+ public:
+ QtEventLoop() : isEventInQtEventLoop_(false) {}
+ virtual ~QtEventLoop() {
+ QCoreApplication::removePostedEvents(this);
+ }
+
+ protected:
+ virtual void eventPosted() {
+ std::unique_lock<std::recursive_mutex> lock(isEventInQtEventLoopMutex_);
+ if (!isEventInQtEventLoop_) {
+ isEventInQtEventLoop_ = true;
+ QCoreApplication::postEvent(this, new Event());
+ }
+ }
+
+ virtual bool event(QEvent* qevent) {
+ Event* event = dynamic_cast<Event*>(qevent);
+ if (event) {
+ {
+ std::unique_lock<std::recursive_mutex> lock(isEventInQtEventLoopMutex_);
+ isEventInQtEventLoop_ = false;
+ }
+ handleNextEvent();
+ //event->deleteLater(); FIXME: Leak?
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ struct Event : public QEvent {
+ Event() :
+ QEvent(QEvent::User) {
+ }
+ };
+
+ bool isEventInQtEventLoop_;
+ std::recursive_mutex isEventInQtEventLoopMutex_;
+ };
}
diff --git a/Swiften/EventLoop/SConscript b/Swiften/EventLoop/SConscript
index 8bef8fb..7aea53f 100644
--- a/Swiften/EventLoop/SConscript
+++ b/Swiften/EventLoop/SConscript
@@ -1,22 +1,23 @@
Import("swiften_env")
sources = [
- "EventLoop.cpp",
- "EventOwner.cpp",
- "Event.cpp",
- "SimpleEventLoop.cpp",
- "DummyEventLoop.cpp",
- "SingleThreadedEventLoop.cpp",
- ]
+ "BoostASIOEventLoop.cpp",
+ "DummyEventLoop.cpp",
+ "Event.cpp",
+ "EventLoop.cpp",
+ "EventOwner.cpp",
+ "SimpleEventLoop.cpp",
+ "SingleThreadedEventLoop.cpp",
+ ]
objects = swiften_env.SwiftenObject(sources)
swiften_env.Append(SWIFTEN_OBJECTS = [objects])
-if swiften_env["PLATFORM"] == "darwin" and swiften_env["target"] == "native":
- myenv = swiften_env.Clone()
- myenv.Append(CXXFLAGS = myenv["OBJCCFLAGS"])
- objects = myenv.SwiftenObject([
- "Cocoa/CocoaEventLoop.mm",
- "Cocoa/CocoaEvent.mm"
- ])
- swiften_env.Append(SWIFTEN_OBJECTS = [objects])
+if swiften_env["PLATFORM"] == "darwin" and swiften_env["target"] == "native" or swiften_env["target"] == 'xcode':
+ myenv = swiften_env.Clone()
+ myenv.Append(CXXFLAGS = myenv["OBJCCFLAGS"])
+ objects = myenv.SwiftenObject([
+ "Cocoa/CocoaEventLoop.mm",
+ "Cocoa/CocoaEvent.mm"
+ ])
+ swiften_env.Append(SWIFTEN_OBJECTS = [objects])
diff --git a/Swiften/EventLoop/SimpleEventLoop.cpp b/Swiften/EventLoop/SimpleEventLoop.cpp
index 42a5481..745fadb 100644
--- a/Swiften/EventLoop/SimpleEventLoop.cpp
+++ b/Swiften/EventLoop/SimpleEventLoop.cpp
@@ -1,72 +1,56 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2019 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#include <Swiften/EventLoop/SimpleEventLoop.h>
#include <boost/bind.hpp>
-#include <iostream>
-
-#include <Swiften/Base/foreach.h>
-
namespace Swift {
-SimpleEventLoop::SimpleEventLoop() : isRunning_(true) {
+SimpleEventLoop::SimpleEventLoop() : isRunning_(true), eventAvailable_(false) {
}
SimpleEventLoop::~SimpleEventLoop() {
- if (!events_.empty()) {
- std::cerr << "Warning: Pending events in SimpleEventLoop at destruction time" << std::endl;
- }
}
void SimpleEventLoop::doRun(bool breakAfterEvents) {
- while (isRunning_) {
- std::vector<Event> events;
- {
- boost::unique_lock<boost::mutex> lock(eventsMutex_);
- while (events_.empty()) {
- eventsAvailable_.wait(lock);
- }
- events.swap(events_);
- }
- foreach(const Event& event, events) {
- handleEvent(event);
- }
- if (breakAfterEvents) {
- return;
- }
- }
+ while (isRunning_) {
+ {
+ std::unique_lock<std::mutex> lock(eventAvailableMutex_);
+ while (!eventAvailable_) {
+ eventAvailableCondition_.wait(lock);
+ }
+
+ eventAvailable_ = false;
+ }
+ runOnce();
+ if (breakAfterEvents) {
+ return;
+ }
+ }
}
void SimpleEventLoop::runOnce() {
- std::vector<Event> events;
- {
- boost::unique_lock<boost::mutex> lock(eventsMutex_);
- events.swap(events_);
- }
- foreach(const Event& event, events) {
- handleEvent(event);
- }
+ handleNextEvent();
}
void SimpleEventLoop::stop() {
- postEvent(boost::bind(&SimpleEventLoop::doStop, this));
+ postEvent(boost::bind(&SimpleEventLoop::doStop, this));
}
void SimpleEventLoop::doStop() {
- isRunning_ = false;
+ isRunning_ = false;
}
-void SimpleEventLoop::post(const Event& event) {
- {
- boost::lock_guard<boost::mutex> lock(eventsMutex_);
- events_.push_back(event);
- }
- eventsAvailable_.notify_one();
+void SimpleEventLoop::eventPosted() {
+ {
+ std::unique_lock<std::mutex> lock(eventAvailableMutex_);
+ eventAvailable_ = true;
+ }
+ eventAvailableCondition_.notify_one();
}
diff --git a/Swiften/EventLoop/SimpleEventLoop.h b/Swiften/EventLoop/SimpleEventLoop.h
index da1c039..fe5f509 100644
--- a/Swiften/EventLoop/SimpleEventLoop.h
+++ b/Swiften/EventLoop/SimpleEventLoop.h
@@ -1,47 +1,47 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
-#include <vector>
-#include <boost/function.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/condition_variable.hpp>
+#include <condition_variable>
+#include <mutex>
#include <Swiften/Base/API.h>
#include <Swiften/EventLoop/EventLoop.h>
namespace Swift {
- class SWIFTEN_API SimpleEventLoop : public EventLoop {
- public:
- SimpleEventLoop();
- ~SimpleEventLoop();
+ class SWIFTEN_API SimpleEventLoop : public EventLoop {
+ public:
+ SimpleEventLoop();
+ virtual ~SimpleEventLoop();
- void run() {
- doRun(false);
- }
+ void run() {
+ doRun(false);
+ }
- void runUntilEvents() {
- doRun(true);
- }
+ void runUntilEvents() {
+ doRun(true);
+ }
- void runOnce();
+ void runOnce();
- void stop();
+ void stop();
- virtual void post(const Event& event);
+ protected:
+ virtual void eventPosted();
- private:
- void doRun(bool breakAfterEvents);
- void doStop();
+ private:
+ void doRun(bool breakAfterEvents);
+ void doStop();
- private:
- bool isRunning_;
- std::vector<Event> events_;
- boost::mutex eventsMutex_;
- boost::condition_variable eventsAvailable_;
- };
+ private:
+ bool isRunning_;
+
+ bool eventAvailable_;
+ std::mutex eventAvailableMutex_;
+ std::condition_variable eventAvailableCondition_;
+ };
}
diff --git a/Swiften/EventLoop/SingleThreadedEventLoop.cpp b/Swiften/EventLoop/SingleThreadedEventLoop.cpp
index c2235b1..89b4460 100644
--- a/Swiften/EventLoop/SingleThreadedEventLoop.cpp
+++ b/Swiften/EventLoop/SingleThreadedEventLoop.cpp
@@ -4,62 +4,58 @@
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
-#include "Swiften/EventLoop/SingleThreadedEventLoop.h"
+/*
+ * Copyright (c) 2016-2019 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
-#include <boost/bind.hpp>
-#include <iostream>
+#include <Swiften/EventLoop/SingleThreadedEventLoop.h>
-#include "Swiften/Base/foreach.h"
+#include <iostream>
+#include <boost/bind.hpp>
namespace Swift {
-SingleThreadedEventLoop::SingleThreadedEventLoop()
-: shouldShutDown_(false)
+SingleThreadedEventLoop::SingleThreadedEventLoop()
+: shouldShutDown_(false), eventAvailable_(false)
{
}
SingleThreadedEventLoop::~SingleThreadedEventLoop() {
- if (!events_.empty()) {
- std::cerr << "Warning: Pending events in SingleThreadedEventLoop at destruction time." << std::endl;
- }
+
}
void SingleThreadedEventLoop::waitForEvents() {
- boost::unique_lock<boost::mutex> lock(eventsMutex_);
- while (events_.empty() && !shouldShutDown_) {
- eventsAvailable_.wait(lock);
- }
-
- if (shouldShutDown_)
- throw EventLoopCanceledException();
+ std::unique_lock<std::mutex> lock(eventAvailableMutex_);
+ while (!eventAvailable_ && !shouldShutDown_) {
+ eventAvailableCondition_.wait(lock);
+ }
+
+ if (shouldShutDown_) {
+ throw EventLoopCanceledException();
+ }
}
void SingleThreadedEventLoop::handleEvents() {
- // Make a copy of the list of events so we don't block any threads that post
- // events while we process them.
- std::vector<Event> events;
- {
- boost::unique_lock<boost::mutex> lock(eventsMutex_);
- events.swap(events_);
- }
-
- // Loop through all the events and handle them
- foreach(const Event& event, events) {
- handleEvent(event);
- }
+ {
+ std::lock_guard<std::mutex> lock(eventAvailableMutex_);
+ eventAvailable_ = false;
+ }
+ handleNextEvent();
}
void SingleThreadedEventLoop::stop() {
- boost::unique_lock<boost::mutex> lock(eventsMutex_);
- shouldShutDown_ = true;
- eventsAvailable_.notify_one();
+ std::unique_lock<std::mutex> lock(eventAvailableMutex_);
+ shouldShutDown_ = true;
+ eventAvailableCondition_.notify_one();
}
-void SingleThreadedEventLoop::post(const Event& event) {
- boost::lock_guard<boost::mutex> lock(eventsMutex_);
- events_.push_back(event);
- eventsAvailable_.notify_one();
+void SingleThreadedEventLoop::eventPosted() {
+ std::lock_guard<std::mutex> lock(eventAvailableMutex_);
+ eventAvailable_ = true;
+ eventAvailableCondition_.notify_one();
}
} // namespace Swift
diff --git a/Swiften/EventLoop/SingleThreadedEventLoop.h b/Swiften/EventLoop/SingleThreadedEventLoop.h
index 75ffad0..9f8cb0a 100644
--- a/Swiften/EventLoop/SingleThreadedEventLoop.h
+++ b/Swiften/EventLoop/SingleThreadedEventLoop.h
@@ -4,13 +4,19 @@
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
#pragma once
+#include <condition_variable>
+#include <mutex>
#include <vector>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/condition_variable.hpp>
-#include "Swiften/EventLoop/EventLoop.h"
+#include <Swiften/EventLoop/EventLoop.h>
// DESCRIPTION:
//
@@ -22,37 +28,39 @@
// The SingleThreadedEventLoop class implements an event loop that can be used from such applications.
//
// USAGE:
-//
-// Spawn a new thread in the desired framework and call SingleThreadedEventLoop::waitForEvents(). The method
+//
+// Spawn a new thread in the desired framework and call SingleThreadedEventLoop::waitForEvents(). The method
// blocks until a new event has arrived at which time it'll return, or until the wait is canceled
-// at which time it throws EventLoopCanceledException.
+// at which time it throws EventLoopCanceledException.
//
// When a new event has arrived and SingleThreadedEventLoop::waitForEvents() returns, the caller should then
-// call SingleThreadedEventLoop::handleEvents() on the main GUI thread. For WPF applications, for instance,
+// call SingleThreadedEventLoop::handleEvents() on the main GUI thread. For WPF applications, for instance,
// the Dispatcher class can be used to execute the call on the GUI thread.
//
namespace Swift {
- class SingleThreadedEventLoop : public EventLoop {
- public:
- class EventLoopCanceledException : public std::exception { };
-
- public:
- SingleThreadedEventLoop();
- ~SingleThreadedEventLoop();
-
- // Blocks while waiting for new events and returns when new events are available.
- // Throws EventLoopCanceledException when the wait is canceled.
- void waitForEvents();
- void handleEvents();
- void stop();
-
- virtual void post(const Event& event);
-
- private:
- bool shouldShutDown_;
- std::vector<Event> events_;
- boost::mutex eventsMutex_;
- boost::condition_variable eventsAvailable_;
- };
+ class SingleThreadedEventLoop : public EventLoop {
+ public:
+ class EventLoopCanceledException : public std::exception { };
+
+ public:
+ SingleThreadedEventLoop();
+ virtual ~SingleThreadedEventLoop();
+
+ // Blocks while waiting for new events and returns when new events are available.
+ // Throws EventLoopCanceledException when the wait is canceled.
+ void waitForEvents();
+ void handleEvents();
+ void stop();
+
+ protected:
+ virtual void eventPosted();
+
+ private:
+ bool shouldShutDown_;
+
+ bool eventAvailable_;
+ std::mutex eventAvailableMutex_;
+ std::condition_variable eventAvailableCondition_;
+ };
}
diff --git a/Swiften/EventLoop/UnitTest/EventLoopTest.cpp b/Swiften/EventLoop/UnitTest/EventLoopTest.cpp
index 58396e6..26c56d3 100644
--- a/Swiften/EventLoop/UnitTest/EventLoopTest.cpp
+++ b/Swiften/EventLoop/UnitTest/EventLoopTest.cpp
@@ -1,90 +1,105 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
+#include <thread>
+
+#include <boost/bind.hpp>
+
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
-#include <boost/thread.hpp>
-#include <boost/bind.hpp>
+#include <Swiften/Base/sleep.h>
+#include <Swiften/EventLoop/DummyEventLoop.h>
#include <Swiften/EventLoop/EventOwner.h>
#include <Swiften/EventLoop/SimpleEventLoop.h>
-#include <Swiften/EventLoop/DummyEventLoop.h>
-#include <Swiften/Base/sleep.h>
using namespace Swift;
class EventLoopTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(EventLoopTest);
- CPPUNIT_TEST(testPost);
- CPPUNIT_TEST(testRemove);
- CPPUNIT_TEST(testHandleEvent_Recursive);
- CPPUNIT_TEST_SUITE_END();
-
- public:
- void setUp() {
- events_.clear();
- }
-
- void testPost() {
- SimpleEventLoop testling;
-
- testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 1));
- testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 2));
- testling.stop();
- testling.run();
-
- CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(events_.size()));
- CPPUNIT_ASSERT_EQUAL(1, events_[0]);
- CPPUNIT_ASSERT_EQUAL(2, events_[1]);
- }
-
- void testRemove() {
- SimpleEventLoop testling;
- boost::shared_ptr<MyEventOwner> eventOwner1(new MyEventOwner());
- boost::shared_ptr<MyEventOwner> eventOwner2(new MyEventOwner());
-
- testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 1), eventOwner1);
- testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 2), eventOwner2);
- testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 3), eventOwner1);
- testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 4), eventOwner2);
- testling.removeEventsFromOwner(eventOwner2);
- testling.stop();
- testling.run();
-
- CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(events_.size()));
- CPPUNIT_ASSERT_EQUAL(1, events_[0]);
- CPPUNIT_ASSERT_EQUAL(3, events_[1]);
- }
-
- void testHandleEvent_Recursive() {
- DummyEventLoop testling;
- boost::shared_ptr<MyEventOwner> eventOwner(new MyEventOwner());
-
- testling.postEvent(boost::bind(&EventLoopTest::runEventLoop, this, &testling, eventOwner), eventOwner);
- testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 0), eventOwner);
- testling.processEvents();
-
- CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(events_.size()));
- CPPUNIT_ASSERT_EQUAL(0, events_[0]);
- CPPUNIT_ASSERT_EQUAL(1, events_[1]);
- }
-
- private:
- struct MyEventOwner : public EventOwner {};
- void logEvent(int i) {
- events_.push_back(i);
- }
- void runEventLoop(DummyEventLoop* loop, boost::shared_ptr<MyEventOwner> eventOwner) {
- loop->processEvents();
- CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(events_.size()));
- loop->postEvent(boost::bind(&EventLoopTest::logEvent, this, 1), eventOwner);
- }
-
- private:
- std::vector<int> events_;
+ CPPUNIT_TEST_SUITE(EventLoopTest);
+ CPPUNIT_TEST(testPost);
+ CPPUNIT_TEST(testRemove);
+ CPPUNIT_TEST(testHandleEvent_Recursive);
+ CPPUNIT_TEST(testHandleEvent_FirstEventRemovesSecondEvent);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ events_.clear();
+ }
+
+ void testPost() {
+ SimpleEventLoop testling;
+
+ testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 1));
+ testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 2));
+ testling.stop();
+ testling.run();
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(events_.size()));
+ CPPUNIT_ASSERT_EQUAL(1, events_[0]);
+ CPPUNIT_ASSERT_EQUAL(2, events_[1]);
+ }
+
+ void testRemove() {
+ SimpleEventLoop testling;
+ std::shared_ptr<MyEventOwner> eventOwner1(new MyEventOwner());
+ std::shared_ptr<MyEventOwner> eventOwner2(new MyEventOwner());
+
+ testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 1), eventOwner1);
+ testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 2), eventOwner2);
+ testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 3), eventOwner1);
+ testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 4), eventOwner2);
+ testling.removeEventsFromOwner(eventOwner2);
+ testling.stop();
+ testling.run();
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(events_.size()));
+ CPPUNIT_ASSERT_EQUAL(1, events_[0]);
+ CPPUNIT_ASSERT_EQUAL(3, events_[1]);
+ }
+
+ void testHandleEvent_Recursive() {
+ DummyEventLoop testling;
+ std::shared_ptr<MyEventOwner> eventOwner(new MyEventOwner());
+
+ testling.postEvent(boost::bind(&EventLoopTest::runEventLoop, this, &testling, eventOwner), eventOwner);
+ testling.postEvent(boost::bind(&EventLoopTest::logEvent, this, 0), eventOwner);
+ testling.processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(events_.size()));
+ CPPUNIT_ASSERT_EQUAL(0, events_[0]);
+ CPPUNIT_ASSERT_EQUAL(1, events_[1]);
+ }
+
+ void testHandleEvent_FirstEventRemovesSecondEvent() {
+ DummyEventLoop testling;
+ auto eventOwner = std::make_shared<MyEventOwner>();
+ auto secondEventFired = false;
+
+ testling.postEvent([&](){ testling.removeEventsFromOwner(eventOwner); }, eventOwner);
+ testling.postEvent([&](){ secondEventFired = true; }, eventOwner);
+ testling.processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(false, secondEventFired);
+ }
+
+ private:
+ struct MyEventOwner : public EventOwner {};
+ void logEvent(int i) {
+ events_.push_back(i);
+ }
+ void runEventLoop(DummyEventLoop* loop, std::shared_ptr<MyEventOwner> eventOwner) {
+ loop->processEvents();
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(events_.size()));
+ loop->postEvent(boost::bind(&EventLoopTest::logEvent, this, 1), eventOwner);
+ }
+
+ private:
+ std::vector<int> events_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(EventLoopTest);
diff --git a/Swiften/EventLoop/UnitTest/SimpleEventLoopTest.cpp b/Swiften/EventLoop/UnitTest/SimpleEventLoopTest.cpp
index 475b6b5..3d096d3 100644
--- a/Swiften/EventLoop/UnitTest/SimpleEventLoopTest.cpp
+++ b/Swiften/EventLoop/UnitTest/SimpleEventLoopTest.cpp
@@ -1,67 +1,69 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
+#include <thread>
+
+#include <boost/bind.hpp>
+
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
-#include <boost/thread.hpp>
-#include <boost/bind.hpp>
-#include <Swiften/EventLoop/SimpleEventLoop.h>
#include <Swiften/Base/sleep.h>
+#include <Swiften/EventLoop/SimpleEventLoop.h>
using namespace Swift;
class SimpleEventLoopTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(SimpleEventLoopTest);
- // FIXME: Temporarily disabling run, because it generates a "vector
- // iterator not incrementable" on XP
- //CPPUNIT_TEST(testRun);
- CPPUNIT_TEST(testPostFromMainThread);
- CPPUNIT_TEST_SUITE_END();
-
- public:
- void setUp() {
- counter_ = 0;
- }
-
- void testRun() {
- SimpleEventLoop testling;
- boost::thread thread(boost::bind(&SimpleEventLoopTest::runIncrementingThread, this, &testling));
- testling.run();
-
- CPPUNIT_ASSERT_EQUAL(10, counter_);
- }
-
- void testPostFromMainThread() {
- SimpleEventLoop testling;
- testling.postEvent(boost::bind(&SimpleEventLoopTest::incrementCounterAndStop, this, &testling));
- testling.run();
-
- CPPUNIT_ASSERT_EQUAL(1, counter_);
- }
-
- private:
- void runIncrementingThread(SimpleEventLoop* loop) {
- for (unsigned int i = 0; i < 10; ++i) {
- Swift::sleep(1);
- loop->postEvent(boost::bind(&SimpleEventLoopTest::incrementCounter, this));
- }
- loop->stop();
- }
-
- void incrementCounter() {
- counter_++;
- }
-
- void incrementCounterAndStop(SimpleEventLoop* loop) {
- counter_++;
- loop->stop();
- }
-
- int counter_;
+ CPPUNIT_TEST_SUITE(SimpleEventLoopTest);
+ // FIXME: Temporarily disabling run, because it generates a "vector
+ // iterator not incrementable" on XP
+ //CPPUNIT_TEST(testRun);
+ CPPUNIT_TEST(testPostFromMainThread);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ counter_ = 0;
+ }
+
+ void testRun() {
+ SimpleEventLoop testling;
+ std::thread thread(boost::bind(&SimpleEventLoopTest::runIncrementingThread, this, &testling));
+ testling.run();
+
+ CPPUNIT_ASSERT_EQUAL(10, counter_);
+ }
+
+ void testPostFromMainThread() {
+ SimpleEventLoop testling;
+ testling.postEvent(boost::bind(&SimpleEventLoopTest::incrementCounterAndStop, this, &testling));
+ testling.run();
+
+ CPPUNIT_ASSERT_EQUAL(1, counter_);
+ }
+
+ private:
+ void runIncrementingThread(SimpleEventLoop* loop) {
+ for (unsigned int i = 0; i < 10; ++i) {
+ Swift::sleep(1);
+ loop->postEvent(boost::bind(&SimpleEventLoopTest::incrementCounter, this));
+ }
+ loop->stop();
+ }
+
+ void incrementCounter() {
+ counter_++;
+ }
+
+ void incrementCounterAndStop(SimpleEventLoop* loop) {
+ counter_++;
+ loop->stop();
+ }
+
+ int counter_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(SimpleEventLoopTest);