Fix thread-sanitizer warning about a data race

Not 100% sure if this is a bug in tsan, but turning expected into an
atomic variable will avoid the warnings.

Change-Id: I6d6a5d58f90258d201ae3880473228638de0a215
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
This commit is contained in:
Lars Knoll 2020-12-02 15:07:46 +01:00
parent 224fccdaec
commit a8a38f7caa

View File

@ -1016,7 +1016,7 @@ class WatchDog : public QThread
}; };
bool waitFor(std::unique_lock<QtPrivate::mutex> &m, Expectation e) { bool waitFor(std::unique_lock<QtPrivate::mutex> &m, Expectation e) {
auto expectationChanged = [this, e] { return expecting != e; }; auto expectationChanged = [this, e] { return expecting.load(std::memory_order_relaxed) != e; };
switch (e) { switch (e) {
case TestFunctionEnd: case TestFunctionEnd:
return waitCondition.wait_for(m, defaultTimeout(), expectationChanged); return waitCondition.wait_for(m, defaultTimeout(), expectationChanged);
@ -1035,14 +1035,14 @@ public:
{ {
setObjectName(QLatin1String("QtTest Watchdog")); setObjectName(QLatin1String("QtTest Watchdog"));
auto locker = qt_unique_lock(mutex); auto locker = qt_unique_lock(mutex);
expecting = ThreadStart; expecting.store(ThreadStart, std::memory_order_relaxed);
start(); start();
waitFor(locker, ThreadStart); waitFor(locker, ThreadStart);
} }
~WatchDog() { ~WatchDog() {
{ {
const auto locker = qt_scoped_lock(mutex); const auto locker = qt_scoped_lock(mutex);
expecting = ThreadEnd; expecting.store(ThreadEnd, std::memory_order_relaxed);
waitCondition.notify_all(); waitCondition.notify_all();
} }
wait(); wait();
@ -1050,29 +1050,30 @@ public:
void beginTest() { void beginTest() {
const auto locker = qt_scoped_lock(mutex); const auto locker = qt_scoped_lock(mutex);
expecting = TestFunctionEnd; expecting.store(TestFunctionEnd, std::memory_order_relaxed);
waitCondition.notify_all(); waitCondition.notify_all();
} }
void testFinished() { void testFinished() {
const auto locker = qt_scoped_lock(mutex); const auto locker = qt_scoped_lock(mutex);
expecting = TestFunctionStart; expecting.store(TestFunctionStart, std::memory_order_relaxed);
waitCondition.notify_all(); waitCondition.notify_all();
} }
void run() override { void run() override {
auto locker = qt_unique_lock(mutex); auto locker = qt_unique_lock(mutex);
expecting = TestFunctionStart; expecting.store(TestFunctionStart, std::memory_order_release);
waitCondition.notify_all(); waitCondition.notify_all();
while (true) { while (true) {
switch (expecting) { Expectation e = expecting.load(std::memory_order_acquire);
switch (e) {
case ThreadEnd: case ThreadEnd:
return; return;
case ThreadStart: case ThreadStart:
Q_UNREACHABLE(); Q_UNREACHABLE();
case TestFunctionStart: case TestFunctionStart:
case TestFunctionEnd: case TestFunctionEnd:
if (Q_UNLIKELY(!waitFor(locker, expecting))) { if (Q_UNLIKELY(!waitFor(locker, e))) {
stackTrace(); stackTrace();
qFatal("Test function timed out"); qFatal("Test function timed out");
} }
@ -1083,7 +1084,7 @@ public:
private: private:
QtPrivate::mutex mutex; QtPrivate::mutex mutex;
QtPrivate::condition_variable waitCondition; QtPrivate::condition_variable waitCondition;
Expectation expecting; std::atomic<Expectation> expecting;
}; };
#else // !QT_CONFIG(thread) #else // !QT_CONFIG(thread)