aboutsummaryrefslogtreecommitdiff
path: root/webrtc/base/thread_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/base/thread_unittest.cc')
-rw-r--r--webrtc/base/thread_unittest.cc138
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)