Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Unified Diff: webrtc/base/thread_unittest.cc

Issue 1439613004: Fix a data race in the thread unit tests. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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)));
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698