Index: webrtc/base/thread_unittest.cc |
diff --git a/webrtc/base/thread_unittest.cc b/webrtc/base/thread_unittest.cc |
index e50e45cd8ab9ef87ff02b6fb04dffaa72cece51e..3878676a4470e9db0a6ed4e31058a1d3ed9a9c1f 100644 |
--- a/webrtc/base/thread_unittest.cc |
+++ b/webrtc/base/thread_unittest.cc |
@@ -137,16 +137,48 @@ class SignalWhenDestroyedThread : public Thread { |
Event* event_; |
}; |
+// A bool wrapped in a mutex, to avoid data races. Using a volatile |
+// bool should be sufficient for correct code ("eventual consistency" |
+// between caches is sufficient), but we can't tell the compiler about |
+// that, and then tsan complains about a data race. |
+ |
+// See also discussion at |
+// http://stackoverflow.com/questions/7223164/is-mutex-needed-to-synchronize-a-simple-flag-between-pthreads |
+ |
+// Using std::atomic<bool> or std::atomic_flag in C++11 is probably |
+// the right thing to do, but those features are not yet allowed. Or |
+// rtc::AtomicInt, if/when that is added. Since the use isn't |
+// performance critical, use a plain critical section for the time |
+// being. |
+ |
+class AtomicBool { |
+ public: |
+ explicit AtomicBool(bool value = false) : flag_(value) {} |
+ AtomicBool& operator=(bool value) { |
+ CritScope scoped_lock(&cs_); |
+ flag_ = value; |
+ return *this; |
+ } |
+ bool get() const { |
+ CritScope scoped_lock(&cs_); |
+ return flag_; |
+ } |
+ |
+ private: |
+ mutable CriticalSection cs_; |
+ bool flag_; |
+}; |
+ |
// Function objects to test Thread::Invoke. |
struct FunctorA { |
int operator()() { return 42; } |
}; |
class FunctorB { |
public: |
- explicit FunctorB(bool* flag) : flag_(flag) {} |
+ explicit FunctorB(AtomicBool* flag) : flag_(flag) {} |
void operator()() { if (flag_) *flag_ = true; } |
private: |
- bool* flag_; |
+ AtomicBool* flag_; |
}; |
struct FunctorC { |
int operator()() { |
@@ -266,10 +298,10 @@ TEST(ThreadTest, Invoke) { |
thread.Start(); |
// Try calling functors. |
EXPECT_EQ(42, thread.Invoke<int>(FunctorA())); |
- bool called = false; |
+ AtomicBool called; |
FunctorB f2(&called); |
thread.Invoke<void>(f2); |
- EXPECT_TRUE(called); |
+ EXPECT_TRUE(called.get()); |
// Try calling bare functions. |
struct LocalFuncs { |
static int Func1() { return 999; } |
@@ -408,9 +440,9 @@ TEST_F(AsyncInvokeTest, FireAndForget) { |
Thread thread; |
thread.Start(); |
// Try calling functor. |
- bool called = false; |
+ AtomicBool called; |
invoker.AsyncInvoke<void>(&thread, FunctorB(&called)); |
- EXPECT_TRUE_WAIT(called, kWaitTimeout); |
+ EXPECT_TRUE_WAIT(called.get(), kWaitTimeout); |
} |
TEST_F(AsyncInvokeTest, WithCallback) { |
@@ -478,26 +510,26 @@ TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) { |
TEST_F(AsyncInvokeTest, Flush) { |
AsyncInvoker invoker; |
- bool flag1 = false; |
- bool flag2 = false; |
+ AtomicBool flag1; |
+ AtomicBool flag2; |
// Queue two async calls to the current thread. |
invoker.AsyncInvoke<void>(Thread::Current(), |
FunctorB(&flag1)); |
invoker.AsyncInvoke<void>(Thread::Current(), |
FunctorB(&flag2)); |
// Because we haven't pumped messages, these should not have run yet. |
- EXPECT_FALSE(flag1); |
- EXPECT_FALSE(flag2); |
+ EXPECT_FALSE(flag1.get()); |
+ EXPECT_FALSE(flag2.get()); |
// Force them to run now. |
invoker.Flush(Thread::Current()); |
- EXPECT_TRUE(flag1); |
- EXPECT_TRUE(flag2); |
+ EXPECT_TRUE(flag1.get()); |
+ EXPECT_TRUE(flag2.get()); |
} |
TEST_F(AsyncInvokeTest, FlushWithIds) { |
AsyncInvoker invoker; |
- bool flag1 = false; |
- bool flag2 = false; |
+ AtomicBool flag1; |
+ AtomicBool flag2; |
// Queue two async calls to the current thread, one with a message id. |
invoker.AsyncInvoke<void>(Thread::Current(), |
FunctorB(&flag1), |
@@ -505,17 +537,17 @@ TEST_F(AsyncInvokeTest, FlushWithIds) { |
invoker.AsyncInvoke<void>(Thread::Current(), |
FunctorB(&flag2)); |
// Because we haven't pumped messages, these should not have run yet. |
- EXPECT_FALSE(flag1); |
- EXPECT_FALSE(flag2); |
+ EXPECT_FALSE(flag1.get()); |
+ EXPECT_FALSE(flag2.get()); |
// Execute pending calls with id == 5. |
invoker.Flush(Thread::Current(), 5); |
- EXPECT_TRUE(flag1); |
- EXPECT_FALSE(flag2); |
+ EXPECT_TRUE(flag1.get()); |
+ EXPECT_FALSE(flag2.get()); |
flag1 = false; |
// Execute all pending calls. The id == 5 call should not execute again. |
invoker.Flush(Thread::Current()); |
- EXPECT_FALSE(flag1); |
- EXPECT_TRUE(flag2); |
+ EXPECT_FALSE(flag1.get()); |
+ EXPECT_TRUE(flag2.get()); |
} |
class GuardedAsyncInvokeTest : public testing::Test { |
@@ -564,11 +596,11 @@ TEST_F(GuardedAsyncInvokeTest, KillThreadFireAndForget) { |
// Kill |thread|. |
thread = nullptr; |
// Try calling functor. |
- bool called = false; |
+ AtomicBool called; |
EXPECT_FALSE(invoker->AsyncInvoke<void>(FunctorB(&called))); |
// With thread gone, nothing should happen. |
- WAIT(called, kWaitTimeout); |
- EXPECT_FALSE(called); |
+ WAIT(called.get(), kWaitTimeout); |
+ EXPECT_FALSE(called.get()); |
} |
// Test that we can call AsyncInvoke with callback after the thread died. |
@@ -595,9 +627,9 @@ TEST_F(GuardedAsyncInvokeTest, KillThreadWithCallback) { |
TEST_F(GuardedAsyncInvokeTest, FireAndForget) { |
GuardedAsyncInvoker invoker; |
// Try calling functor. |
- bool called = false; |
+ AtomicBool called; |
EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&called))); |
- EXPECT_TRUE_WAIT(called, kWaitTimeout); |
+ EXPECT_TRUE_WAIT(called.get(), kWaitTimeout); |
} |
TEST_F(GuardedAsyncInvokeTest, WithCallback) { |
@@ -660,39 +692,39 @@ TEST_F(GuardedAsyncInvokeTest, KillInvokerBeforeExecute) { |
TEST_F(GuardedAsyncInvokeTest, Flush) { |
GuardedAsyncInvoker invoker; |
- bool flag1 = false; |
- bool flag2 = false; |
+ AtomicBool flag1; |
+ AtomicBool flag2; |
// Queue two async calls to the current thread. |
EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1))); |
EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2))); |
// Because we haven't pumped messages, these should not have run yet. |
- EXPECT_FALSE(flag1); |
- EXPECT_FALSE(flag2); |
+ EXPECT_FALSE(flag1.get()); |
+ EXPECT_FALSE(flag2.get()); |
// Force them to run now. |
EXPECT_TRUE(invoker.Flush()); |
- EXPECT_TRUE(flag1); |
- EXPECT_TRUE(flag2); |
+ EXPECT_TRUE(flag1.get()); |
+ EXPECT_TRUE(flag2.get()); |
} |
TEST_F(GuardedAsyncInvokeTest, FlushWithIds) { |
GuardedAsyncInvoker invoker; |
- bool flag1 = false; |
- bool flag2 = false; |
+ AtomicBool flag1; |
+ AtomicBool flag2; |
// Queue two async calls to the current thread, one with a message id. |
EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1), 5)); |
EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2))); |
// Because we haven't pumped messages, these should not have run yet. |
- EXPECT_FALSE(flag1); |
- EXPECT_FALSE(flag2); |
+ EXPECT_FALSE(flag1.get()); |
+ EXPECT_FALSE(flag2.get()); |
// Execute pending calls with id == 5. |
EXPECT_TRUE(invoker.Flush(5)); |
- EXPECT_TRUE(flag1); |
- EXPECT_FALSE(flag2); |
+ EXPECT_TRUE(flag1.get()); |
+ EXPECT_FALSE(flag2.get()); |
flag1 = false; |
// Execute all pending calls. The id == 5 call should not execute again. |
EXPECT_TRUE(invoker.Flush()); |
- EXPECT_FALSE(flag1); |
- EXPECT_TRUE(flag2); |
+ EXPECT_FALSE(flag1.get()); |
+ EXPECT_TRUE(flag2.get()); |
} |
#if defined(WEBRTC_WIN) |