summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2010-10-07 18:35:10 (GMT)
committerRemko Tronçon <git@el-tramo.be>2010-10-07 18:35:10 (GMT)
commite433e70d3dd015db5124ee72085e758635260168 (patch)
tree1d5d151deb2e474b841bbf9c92eeaa3690cd86d4
parent83c5c774b9e71133401e574b1ca7fc6d766bc492 (diff)
downloadswift-e433e70d3dd015db5124ee72085e758635260168.zip
swift-e433e70d3dd015db5124ee72085e758635260168.tar.bz2
Avoid recursive calling of event callbacks.
When EventLoop::handleEvent() was called recursively (i.e. by calling processEvents() from a slot), weird things happened, especially in the XMPP parser (assertion triggers, parse error from server, ...). Now, callbacks are put in a queue handled by the topmost handleEvent. Resolves: #592, #568
-rw-r--r--Swiften/EventLoop/EventLoop.cpp19
-rw-r--r--Swiften/EventLoop/EventLoop.h3
-rw-r--r--Swiften/EventLoop/UnitTest/EventLoopTest.cpp25
3 files changed, 42 insertions, 5 deletions
diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp
index 25dd19a..2e9e021 100644
--- a/Swiften/EventLoop/EventLoop.cpp
+++ b/Swiften/EventLoop/EventLoop.cpp
@@ -8,12 +8,13 @@
#include <algorithm>
#include <boost/bind.hpp>
+#include <iostream>
#include "Swiften/EventLoop/MainEventLoop.h"
namespace Swift {
-EventLoop::EventLoop() : nextEventID_(0) {
+EventLoop::EventLoop() : nextEventID_(0), handlingEvents_(false) {
MainEventLoop::setInstance(this);
}
@@ -22,6 +23,13 @@ EventLoop::~EventLoop() {
}
void EventLoop::handleEvent(const Event& event) {
+ 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_);
@@ -32,7 +40,16 @@ void EventLoop::handleEvent(const Event& event) {
}
}
if (doCallback) {
+ handlingEvents_ = true;
event.callback();
+ // 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();
+ nextEvent.callback();
+ }
+ handlingEvents_ = false;
}
}
diff --git a/Swiften/EventLoop/EventLoop.h b/Swiften/EventLoop/EventLoop.h
index efc68ea..ab58ffc 100644
--- a/Swiften/EventLoop/EventLoop.h
+++ b/Swiften/EventLoop/EventLoop.h
@@ -9,6 +9,7 @@
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <list>
+#include <deque>
#include "Swiften/EventLoop/Event.h"
@@ -40,5 +41,7 @@ namespace Swift {
boost::mutex eventsMutex_;
unsigned int nextEventID_;
std::list<Event> events_;
+ bool handlingEvents_;
+ std::deque<Event> eventsToHandle_;
};
}
diff --git a/Swiften/EventLoop/UnitTest/EventLoopTest.cpp b/Swiften/EventLoop/UnitTest/EventLoopTest.cpp
index b6023ff..b777c1b 100644
--- a/Swiften/EventLoop/UnitTest/EventLoopTest.cpp
+++ b/Swiften/EventLoop/UnitTest/EventLoopTest.cpp
@@ -11,20 +11,19 @@
#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
-{
+class EventLoopTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(EventLoopTest);
CPPUNIT_TEST(testPost);
CPPUNIT_TEST(testRemove);
+ CPPUNIT_TEST(testHandleEvent_Recursive);
CPPUNIT_TEST_SUITE_END();
public:
- EventLoopTest() {}
-
void setUp() {
events_.clear();
}
@@ -59,12 +58,30 @@ class EventLoopTest : public CppUnit::TestFixture
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_;