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

Unified Diff: base/synchronization/atomic_flag_unittest.cc

Issue 2187333002: Loosen/improve AtomicFlag semantics. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix compile post merge Created 4 years, 5 months 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 | « base/synchronization/atomic_flag.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/synchronization/atomic_flag_unittest.cc
diff --git a/base/synchronization/atomic_flag_unittest.cc b/base/synchronization/atomic_flag_unittest.cc
index b0dfd47e4653970789739e24126946bd5c790a1f..48d55afde48e0b20bea76c1b670df5032a6f0dcf 100644
--- a/base/synchronization/atomic_flag_unittest.cc
+++ b/base/synchronization/atomic_flag_unittest.cc
@@ -31,9 +31,18 @@ void ExpectSetFlagDeath(AtomicFlag* flag) {
EXPECT_DCHECK_DEATH(flag->Set(), "");
}
-void BusyWaitUntilFlagIsSet(AtomicFlag* flag) {
- while (!flag->IsSet())
+// Busy waits (to explicitly avoid using synchronization constructs that would
+// defeat the purpose of testing atomics) until |tested_flag| is set and then
+// verifies that non-atomic |*expected_after_flag| is true and sets |*done_flag|
+// before returning if it's non-null.
+void BusyWaitUntilFlagIsSet(AtomicFlag* tested_flag, bool* expected_after_flag,
+ AtomicFlag* done_flag) {
+ while (!tested_flag->IsSet())
PlatformThread::YieldCurrentThread();
+
+ EXPECT_TRUE(*expected_after_flag);
+ if (done_flag)
+ done_flag->Set();
}
} // namespace
@@ -55,32 +64,75 @@ TEST(AtomicFlagTest, DoubleSetTest) {
}
TEST(AtomicFlagTest, ReadFromDifferentThread) {
- AtomicFlag flag;
+ // |tested_flag| is the one being tested below.
+ AtomicFlag tested_flag;
+ // |expected_after_flag| is used to confirm that sequential consistency is
+ // obtained around |tested_flag|.
+ bool expected_after_flag = false;
+ // |reset_flag| is used to confirm the test flows as intended without using
+ // synchronization constructs which would defeat the purpose of exercising
+ // atomics.
+ AtomicFlag reset_flag;
Thread thread("AtomicFlagTest.ReadFromDifferentThread");
ASSERT_TRUE(thread.Start());
- thread.task_runner()->PostTask(FROM_HERE,
- Bind(&BusyWaitUntilFlagIsSet, &flag));
+ thread.task_runner()->PostTask(
+ FROM_HERE,
+ Bind(&BusyWaitUntilFlagIsSet, &tested_flag, &expected_after_flag,
+ &reset_flag));
// To verify that IsSet() fetches the flag's value from memory every time it
// is called (not just the first time that it is called on a thread), sleep
// before setting the flag.
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(25));
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(20));
- flag.Set();
+ // |expected_after_flag| is used to verify that all memory operations
+ // performed before |tested_flag| is Set() are visible to threads that can see
+ // IsSet().
+ expected_after_flag = true;
+ tested_flag.Set();
+
+ // Sleep again to give the busy loop time to observe the flag and verify
+ // expectations.
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(20));
+
+ // Use |reset_flag| to confirm that the above completed (which the rest of
+ // this test assumes).
+ ASSERT_TRUE(reset_flag.IsSet());
+
+ tested_flag.UnsafeResetForTesting();
+ EXPECT_FALSE(tested_flag.IsSet());
+ expected_after_flag = false;
+
+ // Perform the same test again after the controlled UnsafeResetForTesting(),
+ // |thread| is guaranteed to be synchronized past the
+ // |UnsafeResetForTesting()| call when the task runs per the implicit
+ // synchronization in the post task mechanism.
+ thread.task_runner()->PostTask(
+ FROM_HERE,
+ Bind(&BusyWaitUntilFlagIsSet, &tested_flag, &expected_after_flag,
+ nullptr));
+
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(20));
+
+ expected_after_flag = true;
+ tested_flag.Set();
// The |thread|'s destructor will block until the posted task completes, so
// the test will time out if it fails to see the flag be set.
}
-TEST(AtomicFlagTest, SetOnDifferentThreadDeathTest) {
- // Checks that Set() can't be called from any other thread. AtomicFlag should
- // die on a DCHECK if Set() is called from other thread.
+TEST(AtomicFlagTest, SetOnDifferentSequenceDeathTest) {
+ // Checks that Set() can't be called from another sequence after being called
+ // on this one. AtomicFlag should die on a DCHECK if Set() is called again
+ // from another sequence.
::testing::FLAGS_gtest_death_test_style = "threadsafe";
Thread t("AtomicFlagTest.SetOnDifferentThreadDeathTest");
ASSERT_TRUE(t.Start());
+ EXPECT_TRUE(t.WaitUntilThreadStarted());
AtomicFlag flag;
+ flag.Set();
t.task_runner()->PostTask(FROM_HERE, Bind(&ExpectSetFlagDeath, &flag));
}
« no previous file with comments | « base/synchronization/atomic_flag.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698