diff options
Diffstat (limited to 'webrtc/base/thread_unittest.cc')
-rw-r--r-- | webrtc/base/thread_unittest.cc | 138 |
1 files changed, 71 insertions, 67 deletions
diff --git a/webrtc/base/thread_unittest.cc b/webrtc/base/thread_unittest.cc index e50e45cd8a..7ed4326724 100644 --- a/webrtc/base/thread_unittest.cc +++ b/webrtc/base/thread_unittest.cc @@ -15,7 +15,6 @@ #include "webrtc/base/physicalsocketserver.h" #include "webrtc/base/socketaddress.h" #include "webrtc/base/thread.h" -#include "webrtc/test/testsupport/gtest_disable.h" #if defined(WEBRTC_WIN) #include <comdef.h> // NOLINT @@ -137,16 +136,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()() { @@ -220,33 +251,6 @@ TEST(ThreadTest, Names) { delete thread; } -// Test that setting thread priorities doesn't cause a malfunction. -// There's no easy way to verify the priority was set properly at this time. -TEST(ThreadTest, Priorities) { - Thread *thread; - thread = new Thread(); - EXPECT_TRUE(thread->SetPriority(PRIORITY_HIGH)); - EXPECT_TRUE(thread->Start()); - thread->Stop(); - delete thread; - thread = new Thread(); - EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL)); - EXPECT_TRUE(thread->Start()); - thread->Stop(); - delete thread; - - thread = new Thread(); - EXPECT_TRUE(thread->Start()); -#if defined(WEBRTC_WIN) - EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL)); -#else - EXPECT_FALSE(thread->SetPriority(PRIORITY_ABOVE_NORMAL)); -#endif - thread->Stop(); - delete thread; - -} - TEST(ThreadTest, Wrap) { Thread* current_thread = Thread::Current(); current_thread->UnwrapCurrent(); @@ -266,10 +270,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 +412,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 +482,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 +509,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 +568,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 +599,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 +664,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) |