From aa61af14934c475f60e013ec50e5602b417a321c Mon Sep 17 00:00:00 2001
From: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Date: Fri, 4 Jun 2010 17:08:27 +0200
Subject: [PATCH] make the evaluator (even more) thread-safe

the async re-parsing code breaks the assumption that project
parsing only ever starts with a single non-concurrent evaluation
(of the top-level project file), so the population of the base
values in the shared ProFileOption was happily causing crashes.

Reviewed-by: dt
Task-number: QTCREATORBUG-1569
---
 .../qt4projectmanager/qt4projectmanager.pro   |  2 +-
 src/shared/proparser/profileevaluator.cpp     | 27 +++++++++++++++++++
 src/shared/proparser/profileevaluator.h       |  5 ++++
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.pro b/src/plugins/qt4projectmanager/qt4projectmanager.pro
index 448067a9e85..f4c492ac33b 100644
--- a/src/plugins/qt4projectmanager/qt4projectmanager.pro
+++ b/src/plugins/qt4projectmanager/qt4projectmanager.pro
@@ -96,7 +96,7 @@ FORMS += makestep.ui \
     wizards/targetsetuppage.ui
 RESOURCES += qt4projectmanager.qrc \
     wizards/wizards.qrc
-DEFINES += PROPARSER_THREAD_SAFE
+DEFINES += PROPARSER_THREAD_SAFE PROEVALUATOR_THREAD_SAFE
 include(../../shared/proparser/proparser.pri)
 include(qt-s60/qt-s60.pri)
 include(qt-maemo/qt-maemo.pri)
diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp
index 07717953b67..b4788904b0d 100644
--- a/src/shared/proparser/profileevaluator.cpp
+++ b/src/shared/proparser/profileevaluator.cpp
@@ -161,6 +161,10 @@ ProFileOption::ProFileOption()
 #endif
 
     cache = 0;
+
+#ifdef PROEVALUATOR_THREAD_SAFE
+    base_inProgress = false;
+#endif
 }
 
 ProFileOption::~ProFileOption()
@@ -1270,7 +1274,21 @@ ProItem::ProItemReturn ProFileEvaluator::Private::visitProFile(ProFile *pro)
 
         if (m_parsePreAndPostFiles) {
 
+#ifdef PROEVALUATOR_THREAD_SAFE
+          {
+            QMutexLocker locker(&m_option->mutex);
+            if (m_option->base_inProgress) {
+                QThreadPool::globalInstance()->releaseThread();
+                m_option->cond.wait(&m_option->mutex);
+                QThreadPool::globalInstance()->reserveThread();
+            } else
+#endif
             if (m_option->base_valuemap.isEmpty()) {
+#ifdef PROEVALUATOR_THREAD_SAFE
+                m_option->base_inProgress = true;
+                locker.unlock();
+#endif
+
                 // ### init QMAKE_QMAKE, QMAKE_SH
                 // ### init QMAKE_EXT_{C,H,CPP,OBJ}
                 // ### init TEMPLATE_PREFIX
@@ -1377,7 +1395,16 @@ ProItem::ProItemReturn ProFileEvaluator::Private::visitProFile(ProFile *pro)
 
                 evaluateFeatureFile(QLatin1String("default_pre.prf"),
                                     &m_option->base_valuemap, &m_option->base_functions);
+
+#ifdef PROEVALUATOR_THREAD_SAFE
+                locker.relock();
+                m_option->base_inProgress = false;
+                m_option->cond.wakeAll();
+#endif
             }
+#ifdef PROEVALUATOR_THREAD_SAFE
+          }
+#endif
 
             m_valuemapStack.top() = m_option->base_valuemap;
 
diff --git a/src/shared/proparser/profileevaluator.h b/src/shared/proparser/profileevaluator.h
index e4acafdd36a..57df396d5a0 100644
--- a/src/shared/proparser/profileevaluator.h
+++ b/src/shared/proparser/profileevaluator.h
@@ -182,6 +182,11 @@ struct ProFileOption
     ProFileEvaluator::FunctionDefs base_functions;
     QStringList feature_roots;
     QString qmakespec_name;
+#ifdef PROEVALUATOR_THREAD_SAFE
+    QMutex mutex;
+    QWaitCondition cond;
+    bool base_inProgress;
+#endif
 };
 
 QT_END_NAMESPACE
-- 
GitLab