| 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)
|
|
|