aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/corelib/buildgraph/executor.cpp32
-rw-r--r--src/lib/corelib/buildgraph/rulesevaluationcontext.cpp5
-rw-r--r--src/lib/corelib/buildgraph/rulesevaluationcontext.h1
-rw-r--r--tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs71
-rw-r--r--tests/auto/blackbox/testdata/concurrent-executor/dummy1.input0
-rw-r--r--tests/auto/blackbox/testdata/concurrent-executor/dummy2.input0
-rw-r--r--tests/auto/blackbox/testdata/concurrent-executor/util.js8
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp7
-rw-r--r--tests/auto/blackbox/tst_blackbox.h1
9 files changed, 114 insertions, 11 deletions
diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp
index 8a028f0dd..7cfc3137a 100644
--- a/src/lib/corelib/buildgraph/executor.cpp
+++ b/src/lib/corelib/buildgraph/executor.cpp
@@ -435,6 +435,7 @@ void Executor::buildArtifact(Artifact *artifact)
void Executor::executeRuleNode(RuleNode *ruleNode)
{
+ QBS_CHECK(!m_evalContext->isActive());
ArtifactSet changedInputArtifacts;
if (ruleNode->rule()->isDynamic()) {
foreach (Artifact *artifact, m_changedSourceArtifacts) {
@@ -891,20 +892,28 @@ void Executor::possiblyInstallArtifact(const Artifact *artifact)
void Executor::onJobFinished(const qbs::ErrorInfo &err)
{
- if (err.hasError()) {
- if (m_buildOptions.keepGoing()) {
- ErrorInfo fullWarning(err);
- fullWarning.prepend(Tr::tr("Ignoring the following errors on user request:"));
- m_logger.printWarning(fullWarning);
- } else {
- if (!m_error.hasError())
- m_error = err; // All but the first one could be due to canceling.
- }
- }
-
try {
ExecutorJob * const job = qobject_cast<ExecutorJob *>(sender());
QBS_CHECK(job);
+ if (m_evalContext->isActive()) {
+ m_logger.qbsDebug() << "Executor job finished while rule execution is pausing. "
+ "Delaying slot execution.";
+ QMetaObject::invokeMethod(job, "finished", Qt::QueuedConnection,
+ Q_ARG(qbs::ErrorInfo, err));
+ return;
+ }
+
+ if (err.hasError()) {
+ if (m_buildOptions.keepGoing()) {
+ ErrorInfo fullWarning(err);
+ fullWarning.prepend(Tr::tr("Ignoring the following errors on user request:"));
+ m_logger.printWarning(fullWarning);
+ } else {
+ if (!m_error.hasError())
+ m_error = err; // All but the first one could be due to canceling.
+ }
+ }
+
finishJob(job, !err.hasError());
} catch (const ErrorInfo &error) {
handleError(error);
@@ -914,6 +923,7 @@ void Executor::onJobFinished(const qbs::ErrorInfo &err)
void Executor::finish()
{
QBS_ASSERT(m_state != ExecutorIdle, /* ignore */);
+ QBS_ASSERT(!m_evalContext || !m_evalContext->isActive(), /* ignore */);
QList<ResolvedProductPtr> unbuiltProducts;
foreach (const ResolvedProductPtr &product, m_productsToBuild) {
diff --git a/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp b/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp
index 1f412b454..eed00cdac 100644
--- a/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp
+++ b/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp
@@ -58,6 +58,11 @@ RulesEvaluationContext::~RulesEvaluationContext()
delete m_engine;
}
+bool RulesEvaluationContext::isActive() const
+{
+ return m_initScopeCalls > 0;
+}
+
void RulesEvaluationContext::initializeObserver(const QString &description, int maximumProgress)
{
if (m_observer)
diff --git a/src/lib/corelib/buildgraph/rulesevaluationcontext.h b/src/lib/corelib/buildgraph/rulesevaluationcontext.h
index 274d9bcae..f00b2c44d 100644
--- a/src/lib/corelib/buildgraph/rulesevaluationcontext.h
+++ b/src/lib/corelib/buildgraph/rulesevaluationcontext.h
@@ -61,6 +61,7 @@ public:
ScriptEngine *engine() const { return m_engine; }
QScriptValue scope() const { return m_scope; }
+ bool isActive() const;
void setObserver(ProgressObserver *observer) { m_observer = observer; }
ProgressObserver *observer() const { return m_observer; }
diff --git a/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs b/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs
new file mode 100644
index 000000000..672576263
--- /dev/null
+++ b/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs
@@ -0,0 +1,71 @@
+import qbs
+import qbs.File
+import qbs.TextFile
+import "util.js" as Utils
+
+Product {
+ type: ["final1", "final2"]
+ Group {
+ files: ["dummy1.input"]
+ fileTags: ["input1"]
+ }
+ Group {
+ files: ["dummy2.input"]
+ fileTags: ["input2"]
+ }
+ Rule {
+ inputs: ["input1"]
+ Artifact {
+ filePath: project.buildDirectory + "/dummy1.final"
+ fileTags: ["final1"]
+ }
+ prepare: {
+ var cmds = [];
+ for (var i = 0; i < 10; ++i) {
+ var cmd = new JavaScriptCommand();
+ cmd.silent = true;
+ cmd.createFile = i == 9;
+ cmd.sourceCode = function() {
+ if (createFile) {
+ print("Creating file");
+ var file = new TextFile(output.filePath, TextFile.WriteOnly);
+ file.close();
+ }
+ };
+ cmds.push(cmd);
+ }
+ return cmds;
+ }
+ }
+ Rule {
+ inputs: ["input2"]
+ Artifact {
+ filePath: "dummy.intermediate"
+ fileTags: ["intermediate"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.silent = true;
+ cmd.sourceCode = function() { };
+ return [cmd];
+ }
+ }
+ Rule {
+ inputs: ["intermediate"]
+ Artifact {
+ filePath: "dummy2.final"
+ fileTags: ["final2"]
+ }
+ prepare: {
+ do
+ Utils.sleep(6000);
+ while (!File.exists(project.buildDirectory + "/dummy1.final"));
+ var cmd = new JavaScriptCommand();
+ cmd.silent = true;
+ cmd.sourceCode = function() { };
+ return [cmd];
+ }
+ }
+}
+
+
diff --git a/tests/auto/blackbox/testdata/concurrent-executor/dummy1.input b/tests/auto/blackbox/testdata/concurrent-executor/dummy1.input
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/concurrent-executor/dummy1.input
diff --git a/tests/auto/blackbox/testdata/concurrent-executor/dummy2.input b/tests/auto/blackbox/testdata/concurrent-executor/dummy2.input
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/concurrent-executor/dummy2.input
diff --git a/tests/auto/blackbox/testdata/concurrent-executor/util.js b/tests/auto/blackbox/testdata/concurrent-executor/util.js
new file mode 100644
index 000000000..a37a8cbb1
--- /dev/null
+++ b/tests/auto/blackbox/testdata/concurrent-executor/util.js
@@ -0,0 +1,8 @@
+function sleep(timeInMs)
+{
+ var referenceTime = new Date();
+ var time = null;
+ do {
+ time = new Date();
+ } while (time - referenceTime < timeInMs);
+}
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 5d801dd86..7723332b2 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -654,6 +654,13 @@ void TestBlackbox::clean()
QVERIFY2(symlinkExists(symLink), qPrintable(symLink));
}
+void TestBlackbox::concurrentExecutor()
+{
+ QDir::setCurrent(testDataDir + "/concurrent-executor");
+ QCOMPARE(runQbs(QStringList() << "-j" << "2"), 0);
+ QVERIFY2(!m_qbsStderr.contains("ASSERT"), m_qbsStderr.constData());
+}
+
void TestBlackbox::renameDependency()
{
QDir::setCurrent(testDataDir + "/renameDependency");
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index 8d575fdd5..adec827f2 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.h
@@ -101,6 +101,7 @@ private slots:
void changeInDisabledProduct();
void checkProjectFilePath();
void clean();
+ void concurrentExecutor();
void dependenciesProperty();
void dynamicMultiplexRule();
void dynamicRuleOutputs();