Details
Description
Our CI hangs sometimes in tst_blackbox::concurrentExecution(), but I have seen hangs in other testcases as well.
I am able to reproduce this behavior on my machine, but it takes a very long time and is not deterministic. In order to trigger the error faster, I have modified the codebase a bit:
diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp index 7c531e7..4bb1fe8 100644 --- a/src/lib/corelib/language/scriptengine.cpp +++ b/src/lib/corelib/language/scriptengine.cpp @@ -105,7 +105,7 @@ ScriptEngine::ScriptEngine(Logger &logger, EvalContext evalContext, QObject *par m_propertyCacheEnabled(true), m_active(false), m_logger(logger), m_evalContext(evalContext), m_observer(new PrepareScriptObserver(this, UnobserveMode::Disabled)) { - setProcessEventsInterval(1000); // For the cancelation mechanism to work. + setProcessEventsInterval(50); // For the cancelation mechanism to work. m_cancelationError = currentContext()->throwValue(tr("Execution canceled")); QScriptValue objectProto = globalObject().property(QStringLiteral("Object")); m_definePropertyFunction = objectProto.property(QStringLiteral("defineProperty")); diff --git a/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs b/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs index 802aa14..a609c4d 100644 --- a/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs +++ b/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs @@ -19,12 +19,15 @@ Product { fileTags: ["final1"] } prepare: { + console.warn("Prepare dummy1.final") var cmds = []; - for (var i = 0; i < 10; ++i) { + for (var i = 0; i < 6; ++i) { var cmd = new JavaScriptCommand(); cmd.silent = true; - cmd.createFile = i == 9; + cmd.createFile = i == 5; + cmd.i = i; cmd.sourceCode = function() { + console.info("Running iteration " + i + " of dumm1.final"); if (createFile) { console.info("Creating file"); var file = new TextFile(output.filePath, TextFile.WriteOnly); @@ -33,6 +36,7 @@ Product { }; cmds.push(cmd); } + console.warn("Done prepare dummy1.final") return cmds; } } @@ -43,9 +47,11 @@ Product { fileTags: ["intermediate"] } prepare: { + console.warn("Prepare dummy.intermediate") var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { }; + console.warn("Done prepare dummy.intermediate") return [cmd]; } } @@ -53,12 +59,14 @@ Product { inputs: ["intermediate"] outputFileTags: "final2" prepare: { - do - Utils.sleep(6000); - while (!File.exists(project.buildDirectory + "/dummy1.final")); + console.warn("Prepare final2") + do { + Utils.sleep(100); + } while (!File.exists(project.buildDirectory + "/dummy1.final")); var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { }; + console.warn("Done prepare final2") return [cmd]; } }
The error is very hard to trigger, so I ran the testcase in a loop:
set -eROOT=install-root/usr/local QBS=${ROOT}/bin/qbs PROJECT=qbs/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbswhile true; do rm -rf /tmp/blabla ${QBS} build -j2 -f ${PROJECT} -d /tmp/blabla done
The -j2 seems to be important. It can take some time. If the error doesn't occur in the first 10s, it will usually not occur. In that case, abort the script, create some non-deterministic background load and run it again.
Here is the output in case of an error:
Build graph does not yet exist for configuration 'default'. Starting from scratch. Resolving project for configuration default Setting up build graph for configuration default Building for configuration default WARNING: Prepare dummy1.final WARNING: Done prepare dummy1.final WARNING: Prepare dummy.intermediate WARNING: Done prepare dummy.intermediate Running iteration 0 of dumm1.final Running iteration 1 of dumm1.final WARNING: Prepare final2
In that case, Qbs hangs in the prepare script of the final2 rule, but doesn't execute further iterations of dummy1.final. I noticed that the script engine in the final2 rule is still active, but no more transformers of dummy.final are executed.