From eb407209bb9f2c06684fd1299169cd3b8ab4b58d Mon Sep 17 00:00:00 2001 From: Jedrzej Nowacki Date: Thu, 30 Sep 2010 13:17:39 +0200 Subject: Fix QScriptEngine::abortEvaluation. This patch reduce time in which QScriptEngine would abort an script executing multiple long-running native functions. Task-number: QTBUG-9433 Reviewed-by: Olivier Goffart --- src/script/api/qscriptengine.cpp | 7 ++- tests/auto/qscriptengine/tst_qscriptengine.cpp | 60 ++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 07aced4..128e9c3 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -46,6 +46,7 @@ #include "Error.h" #include "Interpreter.h" +#include "ExceptionHelpers.h" #include "PrototypeFunction.h" #include "InitializeThreading.h" #include "ObjectPrototype.h" @@ -4116,9 +4117,11 @@ bool QScriptEngine::isEvaluating() const void QScriptEngine::abortEvaluation(const QScriptValue &result) { Q_D(QScriptEngine); - - d->timeoutChecker()->setShouldAbort(true); + if (!isEvaluating()) + return; d->abortResult = result; + d->timeoutChecker()->setShouldAbort(true); + JSC::throwError(d->currentFrame, JSC::createInterruptedExecutionException(&d->currentFrame->globalData()).toObject(d->currentFrame)); } #ifndef QT_NO_QOBJECT diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index f96aea6..26eb1af 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -134,6 +134,7 @@ private slots: void numberParsing(); void automaticSemicolonInsertion(); void abortEvaluation(); + void abortEvaluation_QTBUG9433(); void isEvaluating(); void printFunctionWithCustomHandler(); void printThrowsException(); @@ -3007,7 +3008,8 @@ public: enum AbortionResult { None = 0, String = 1, - Error = 2 + Error = 2, + Number = 3 }; EventReceiver3(QScriptEngine *eng) { @@ -3027,6 +3029,8 @@ public: case Error: engine->abortEvaluation(engine->currentContext()->throwError("AbortedWithError")); break; + case Number: + engine->abortEvaluation(QScriptValue(1234)); } } return QObject::event(e); @@ -3059,7 +3063,7 @@ void tst_QScriptEngine::abortEvaluation() EventReceiver3 receiver(&eng); eng.setProcessEventsInterval(100); - for (int x = 0; x < 3; ++x) { + for (int x = 0; x < 4; ++x) { QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); receiver.resultType = EventReceiver3::AbortionResult(x); QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }")); @@ -3068,6 +3072,11 @@ void tst_QScriptEngine::abortEvaluation() QVERIFY(!eng.hasUncaughtException()); QVERIFY(!ret.isValid()); break; + case EventReceiver3::Number: + QVERIFY(!eng.hasUncaughtException()); + QVERIFY(ret.isNumber()); + QCOMPARE(ret.toInt32(), 1234); + break; case EventReceiver3::String: QVERIFY(!eng.hasUncaughtException()); QVERIFY(ret.isString()); @@ -3082,7 +3091,7 @@ void tst_QScriptEngine::abortEvaluation() } // scripts cannot intercept the abortion with try/catch - for (int y = 0; y < 3; ++y) { + for (int y = 0; y < 4; ++y) { QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); receiver.resultType = EventReceiver3::AbortionResult(y); QScriptValue ret = eng.evaluate(QString::fromLatin1( @@ -3098,6 +3107,11 @@ void tst_QScriptEngine::abortEvaluation() QVERIFY(!eng.hasUncaughtException()); QVERIFY(!ret.isValid()); break; + case EventReceiver3::Number: + QVERIFY(!eng.hasUncaughtException()); + QVERIFY(ret.isNumber()); + QCOMPARE(ret.toInt32(), 1234); + break; case EventReceiver3::String: QVERIFY(!eng.hasUncaughtException()); QVERIFY(ret.isString()); @@ -3118,6 +3132,46 @@ void tst_QScriptEngine::abortEvaluation() } } +class ThreadedEngine : public QThread { + Q_OBJECT; + +private: + QScriptEngine* m_engine; +protected: + void run() { + m_engine = new QScriptEngine(); + m_engine->setGlobalObject(m_engine->newQObject(this)); + m_engine->evaluate("while(1) { sleep(); }"); + delete m_engine; + } + +public slots: + void sleep() + { + QTest::qSleep(25); + m_engine->abortEvaluation(); + } +}; + +void tst_QScriptEngine::abortEvaluation_QTBUG9433() +{ + ThreadedEngine engine; + engine.start(); + QVERIFY(engine.isRunning()); + QTest::qSleep(50); + for (uint i = 0; i < 50; ++i) { // up to ~2500 ms + if (engine.isFinished()) + return; + QTest::qSleep(50); + } + if (!engine.isFinished()) { + engine.terminate(); + engine.wait(7000); + QFAIL("abortEvaluation doesn't work"); + } + +} + static QScriptValue myFunctionReturningIsEvaluating(QScriptContext *, QScriptEngine *eng) { return QScriptValue(eng, eng->isEvaluating()); -- cgit v0.12