Fix assert when emitting a signal from a different thread
If a signal is emitted more than once in a multithreaded application the QSignalEventGenerator::execute function asserts in the check for a valid signal index. It happens after abandoning the state and all the connections are disconnected. If we have pending signal to be processed the QObject::sender() won't be able to resolve the sender object. Task-number: QTBUG-61463 Change-Id: I9d4b7266c6dddc9ff2e7453b05a6989876ccb332 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>bb10
parent
d48c502ce5
commit
345be58100
|
|
@ -3096,10 +3096,12 @@ int QSignalEventGenerator::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
|||
|
||||
void QSignalEventGenerator::execute(void **_a)
|
||||
{
|
||||
auto machinePrivate = QStateMachinePrivate::get(qobject_cast<QStateMachine*>(parent()));
|
||||
if (machinePrivate->state != QStateMachinePrivate::Running)
|
||||
return;
|
||||
int signalIndex = senderSignalIndex();
|
||||
Q_ASSERT(signalIndex != -1);
|
||||
QStateMachine *machine = qobject_cast<QStateMachine*>(parent());
|
||||
QStateMachinePrivate::get(machine)->handleTransitionSignal(sender(), signalIndex, _a);
|
||||
machinePrivate->handleTransitionSignal(sender(), signalIndex, _a);
|
||||
}
|
||||
|
||||
QSignalEventGenerator::QSignalEventGenerator(QStateMachine *parent)
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ Q_OBJECT
|
|||
public:
|
||||
SignalEmitter(QObject *parent = 0)
|
||||
: QObject(parent) {}
|
||||
public Q_SLOTS:
|
||||
void emitSignalWithNoArg()
|
||||
{ emit signalWithNoArg(); }
|
||||
void emitSignalWithIntArg(int arg)
|
||||
|
|
@ -251,6 +252,7 @@ private slots:
|
|||
void qtbug_46059();
|
||||
void qtbug_46703();
|
||||
void postEventFromBeginSelectTransitions();
|
||||
void dontProcessSlotsWhenMachineIsNotRunning();
|
||||
};
|
||||
|
||||
class TestState : public QState
|
||||
|
|
@ -6658,5 +6660,35 @@ void tst_QStateMachine::postEventFromBeginSelectTransitions()
|
|||
QVERIFY(machine.isRunning());
|
||||
}
|
||||
|
||||
void tst_QStateMachine::dontProcessSlotsWhenMachineIsNotRunning()
|
||||
{
|
||||
QStateMachine machine;
|
||||
QState initialState;
|
||||
QFinalState finalState;
|
||||
|
||||
struct Emitter : SignalEmitter
|
||||
{
|
||||
QThread thread;
|
||||
Emitter(QObject *parent = nullptr) : SignalEmitter(parent)
|
||||
{
|
||||
moveToThread(&thread);
|
||||
thread.start();
|
||||
}
|
||||
} emitter;
|
||||
|
||||
initialState.addTransition(&emitter, &Emitter::signalWithNoArg, &finalState);
|
||||
QTimer::singleShot(0, [&]() {
|
||||
metaObject()->invokeMethod(&emitter, "emitSignalWithNoArg");
|
||||
metaObject()->invokeMethod(&emitter, "emitSignalWithNoArg");
|
||||
});
|
||||
machine.addState(&initialState);
|
||||
machine.addState(&finalState);
|
||||
machine.setInitialState(&initialState);
|
||||
machine.start();
|
||||
connect(&machine, &QStateMachine::finished, &emitter.thread, &QThread::quit);
|
||||
QSignalSpy signalSpy(&machine, &QStateMachine::finished);
|
||||
QTRY_COMPARE_WITH_TIMEOUT(signalSpy.count(), 1, 100);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QStateMachine)
|
||||
#include "tst_qstatemachine.moc"
|
||||
|
|
|
|||
Loading…
Reference in New Issue