Index: webrtc/base/thread_unittest.cc |
diff --git a/webrtc/base/thread_unittest.cc b/webrtc/base/thread_unittest.cc |
index e50e45cd8ab9ef87ff02b6fb04dffaa72cece51e..0ee0b3c99acea44342ea3f83e0a323f6d5f4c994 100644 |
--- a/webrtc/base/thread_unittest.cc |
+++ b/webrtc/base/thread_unittest.cc |
@@ -137,16 +137,51 @@ class SignalWhenDestroyedThread : public Thread { |
Event* event_; |
}; |
+// A bool wrapped in a mutex, do 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. |
+// Since the use isn't performance critical, use a plain mutex for the |
+// time being. |
+ |
+class AtomicFlag |
+{ |
magjed_webrtc
2015/11/11 15:50:44
You are not following the C++ style guide. The Web
nisse-webrtc
2015/11/12 08:39:05
Done. I've also added a google style in my emacs c
magjed_webrtc
2015/11/12 09:20:51
You can also take a look at go/emacs.
|
+public: |
+ AtomicFlag(bool value) : flag(value) {} |
magjed_webrtc
2015/11/11 15:50:44
I'm not sure you are allowed to use implicit conve
nisse-webrtc
2015/11/12 08:39:05
I can make it explicit. Only reason for implicit w
tommi
2015/11/12 08:49:52
Adding a default ctor that initializes to false ma
magjed_webrtc
2015/11/12 09:20:51
FYI - Here is a link to the style guide:
"Do not d
nisse-webrtc
2015/11/12 09:58:23
I changed the constructor to explicit (and with a
nisse-webrtc
2015/11/12 09:58:23
Done.
tommi
2015/11/12 10:16:31
hah! Yeah, well, maybe the class could be called
magjed_webrtc
2015/11/12 11:04:38
Yes, you should probably make the conversion to bo
|
+ bool operator= (bool value) { |
nisse-webrtc
2015/11/12 08:39:05
What's the proper return type for this assignment
tommi
2015/11/12 08:49:52
yes, return a reference to *this.
magjed_webrtc
2015/11/12 09:20:51
The typical copy assignment operator would take th
nisse-webrtc
2015/11/12 09:58:23
Done.
|
+ cs.Enter(); |
magjed_webrtc
2015/11/11 15:50:44
Instead of manual Enter() and Leave(), you can use
nisse-webrtc
2015/11/12 08:39:05
Done.
|
+ flag = value; |
+ cs.Leave(); |
+ return value; |
+ } |
+ operator bool() const { |
+ bool value; |
+ cs.Enter(); |
+ value = flag; |
+ cs.Leave(); |
+ return value; |
+ } |
+private: |
+ mutable CriticalSection cs; |
+ bool flag; |
tommi
2015/11/11 16:00:03
fyi - pbos is working on a change that could be he
nisse-webrtc
2015/11/12 08:39:05
I'm adding a reference to rtc::AtomicInt in the co
|
+}; |
+ |
// Function objects to test Thread::Invoke. |
struct FunctorA { |
int operator()() { return 42; } |
}; |
class FunctorB { |
public: |
- explicit FunctorB(bool* flag) : flag_(flag) {} |
+ explicit FunctorB(AtomicFlag* flag) : flag_(flag) {} |
void operator()() { if (flag_) *flag_ = true; } |
private: |
- bool* flag_; |
+ AtomicFlag* flag_; |
}; |
struct FunctorC { |
int operator()() { |
@@ -266,7 +301,7 @@ TEST(ThreadTest, Invoke) { |
thread.Start(); |
// Try calling functors. |
EXPECT_EQ(42, thread.Invoke<int>(FunctorA())); |
- bool called = false; |
+ AtomicFlag called = false; |
FunctorB f2(&called); |
thread.Invoke<void>(f2); |
EXPECT_TRUE(called); |
@@ -408,7 +443,7 @@ TEST_F(AsyncInvokeTest, FireAndForget) { |
Thread thread; |
thread.Start(); |
// Try calling functor. |
- bool called = false; |
+ AtomicFlag called = false; |
invoker.AsyncInvoke<void>(&thread, FunctorB(&called)); |
EXPECT_TRUE_WAIT(called, kWaitTimeout); |
} |
@@ -478,8 +513,8 @@ TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) { |
TEST_F(AsyncInvokeTest, Flush) { |
AsyncInvoker invoker; |
- bool flag1 = false; |
- bool flag2 = false; |
+ AtomicFlag flag1 = false; |
+ AtomicFlag flag2 = false; |
// Queue two async calls to the current thread. |
invoker.AsyncInvoke<void>(Thread::Current(), |
FunctorB(&flag1)); |
@@ -496,8 +531,8 @@ TEST_F(AsyncInvokeTest, Flush) { |
TEST_F(AsyncInvokeTest, FlushWithIds) { |
AsyncInvoker invoker; |
- bool flag1 = false; |
- bool flag2 = false; |
+ AtomicFlag flag1 = false; |
+ AtomicFlag flag2 = false; |
// Queue two async calls to the current thread, one with a message id. |
invoker.AsyncInvoke<void>(Thread::Current(), |
FunctorB(&flag1), |
@@ -564,7 +599,7 @@ TEST_F(GuardedAsyncInvokeTest, KillThreadFireAndForget) { |
// Kill |thread|. |
thread = nullptr; |
// Try calling functor. |
- bool called = false; |
+ AtomicFlag called = false; |
EXPECT_FALSE(invoker->AsyncInvoke<void>(FunctorB(&called))); |
// With thread gone, nothing should happen. |
WAIT(called, kWaitTimeout); |
@@ -595,7 +630,7 @@ TEST_F(GuardedAsyncInvokeTest, KillThreadWithCallback) { |
TEST_F(GuardedAsyncInvokeTest, FireAndForget) { |
GuardedAsyncInvoker invoker; |
// Try calling functor. |
- bool called = false; |
+ AtomicFlag called = false; |
EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&called))); |
EXPECT_TRUE_WAIT(called, kWaitTimeout); |
} |
@@ -660,8 +695,8 @@ TEST_F(GuardedAsyncInvokeTest, KillInvokerBeforeExecute) { |
TEST_F(GuardedAsyncInvokeTest, Flush) { |
GuardedAsyncInvoker invoker; |
- bool flag1 = false; |
- bool flag2 = false; |
+ AtomicFlag flag1 = false; |
+ AtomicFlag flag2 = false; |
// Queue two async calls to the current thread. |
EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1))); |
EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2))); |
@@ -676,8 +711,8 @@ TEST_F(GuardedAsyncInvokeTest, Flush) { |
TEST_F(GuardedAsyncInvokeTest, FlushWithIds) { |
GuardedAsyncInvoker invoker; |
- bool flag1 = false; |
- bool flag2 = false; |
+ AtomicFlag flag1 = false; |
+ AtomicFlag flag2 = false; |
// 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))); |