diff options
| author | Remko Tronçon <git@el-tramo.be> | 2010-10-07 18:35:10 (GMT) | 
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2010-10-07 18:35:10 (GMT) | 
| commit | e433e70d3dd015db5124ee72085e758635260168 (patch) | |
| tree | 1d5d151deb2e474b841bbf9c92eeaa3690cd86d4 | |
| parent | 83c5c774b9e71133401e574b1ca7fc6d766bc492 (diff) | |
| download | swift-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.cpp | 19 | ||||
| -rw-r--r-- | Swiften/EventLoop/EventLoop.h | 3 | ||||
| -rw-r--r-- | Swiften/EventLoop/UnitTest/EventLoopTest.cpp | 25 | 
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_;  | 
 Swift