diff options
author | Kent Hansen <kent.hansen@nokia.com> | 2012-06-04 21:51:04 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-06-06 13:27:32 +0200 |
commit | 302e6968f1152d5dee8d5debafb313bd53fa55ff (patch) | |
tree | 983df82f4846fd042efec5979dc0c46d8c85d31c /tests/auto/corelib/statemachine | |
parent | fc15a1d5e2cb064df7b6e7b9e821e9db20a91b85 (diff) |
statemachine: Make delayed event posting work from secondary thread
postDelayedEvent() and cancelDelayedEvent() are marked as thread-safe
in the documentation. Unfortunately, they didn't actually work when
called from another thread; they just produced some warnings:
QObject::startTimer: timers cannot be started from another thread
QObject::killTimer: timers cannot be stopped from another thread
As the warnings indicate, the issue was that postDelayedEvent()
(cancelDelayedEvent()) unconditionally called QObject::startTimer()
(stopTimer()), i.e. without considering which thread the function
was called from.
If the function is called from a different thread, the actual
starting/stopping of the associated timer is now done from the
correct thread, by asynchronously calling a private slot on the
state machine.
This also means that the raw timer id can no longer be used as the
id of the delayed event, since a valid event id must be returned
before the timer has started. The state machine now manages those
ids itself (using a QFreeList, just like startTimer() and
killTimer() do), and also keeps a mapping from timer id to event
id once the timer has been started. This is inherently more complex
than before, but at least the API should work as advertised/intended
now.
Task-number: QTBUG-17975
Change-Id: I3a866d01dca23174c8841112af50b87141df0943
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
Diffstat (limited to 'tests/auto/corelib/statemachine')
-rw-r--r-- | tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp index c5d33e7437..14a0bed1b4 100644 --- a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp @@ -101,6 +101,7 @@ private slots: void postEvent(); void cancelDelayedEvent(); void postDelayedEventAndStop(); + void postDelayedEventFromThread(); void stopAndPostEvent(); void stateFinished(); void parallelStates(); @@ -1731,6 +1732,55 @@ void tst_QStateMachine::postDelayedEventAndStop() QVERIFY(machine.configuration().contains(s1)); } +class DelayedEventPosterThread : public QThread +{ + Q_OBJECT +public: + DelayedEventPosterThread(QStateMachine *machine, QObject *parent = 0) + : QThread(parent), firstEventWasCancelled(false), + m_machine(machine), m_count(0) + { + moveToThread(this); + QObject::connect(m_machine, SIGNAL(started()), + this, SLOT(postEvent())); + } + + mutable bool firstEventWasCancelled; + +private Q_SLOTS: + void postEvent() + { + int id = m_machine->postDelayedEvent(new QEvent(QEvent::User), 1000); + firstEventWasCancelled = m_machine->cancelDelayedEvent(id); + + m_machine->postDelayedEvent(new QEvent(QEvent::User), 1); + + quit(); + } +private: + QStateMachine *m_machine; + int m_count; +}; + +void tst_QStateMachine::postDelayedEventFromThread() +{ + QStateMachine machine; + QState *s1 = new QState(&machine); + QFinalState *f = new QFinalState(&machine); + s1->addTransition(new EventTransition(QEvent::User, f)); + machine.setInitialState(s1); + + DelayedEventPosterThread poster(&machine); + poster.start(); + + QSignalSpy finishedSpy(&machine, SIGNAL(finished())); + QVERIFY(finishedSpy.isValid()); + machine.start(); + QTRY_COMPARE(finishedSpy.count(), 1); + + QVERIFY(poster.firstEventWasCancelled); +} + void tst_QStateMachine::stopAndPostEvent() { QStateMachine machine; |