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

Side by Side 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, 4 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 unified diff | Download patch
« no previous file with comments | « base/synchronization/atomic_flag.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/synchronization/atomic_flag.h" 5 #include "base/synchronization/atomic_flag.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/single_thread_task_runner.h" 9 #include "base/single_thread_task_runner.h"
10 #include "base/synchronization/waitable_event.h" 10 #include "base/synchronization/waitable_event.h"
(...skipping 13 matching lines...) Expand all
24 24
25 namespace base { 25 namespace base {
26 26
27 namespace { 27 namespace {
28 28
29 void ExpectSetFlagDeath(AtomicFlag* flag) { 29 void ExpectSetFlagDeath(AtomicFlag* flag) {
30 ASSERT_TRUE(flag); 30 ASSERT_TRUE(flag);
31 EXPECT_DCHECK_DEATH(flag->Set(), ""); 31 EXPECT_DCHECK_DEATH(flag->Set(), "");
32 } 32 }
33 33
34 void BusyWaitUntilFlagIsSet(AtomicFlag* flag) { 34 // Busy waits (to explicitly avoid using synchronization constructs that would
35 while (!flag->IsSet()) 35 // defeat the purpose of testing atomics) until |tested_flag| is set and then
36 // verifies that non-atomic |*expected_after_flag| is true and sets |*done_flag|
37 // before returning if it's non-null.
38 void BusyWaitUntilFlagIsSet(AtomicFlag* tested_flag, bool* expected_after_flag,
39 AtomicFlag* done_flag) {
40 while (!tested_flag->IsSet())
36 PlatformThread::YieldCurrentThread(); 41 PlatformThread::YieldCurrentThread();
42
43 EXPECT_TRUE(*expected_after_flag);
44 if (done_flag)
45 done_flag->Set();
37 } 46 }
38 47
39 } // namespace 48 } // namespace
40 49
41 TEST(AtomicFlagTest, SimpleSingleThreadedTest) { 50 TEST(AtomicFlagTest, SimpleSingleThreadedTest) {
42 AtomicFlag flag; 51 AtomicFlag flag;
43 ASSERT_FALSE(flag.IsSet()); 52 ASSERT_FALSE(flag.IsSet());
44 flag.Set(); 53 flag.Set();
45 ASSERT_TRUE(flag.IsSet()); 54 ASSERT_TRUE(flag.IsSet());
46 } 55 }
47 56
48 TEST(AtomicFlagTest, DoubleSetTest) { 57 TEST(AtomicFlagTest, DoubleSetTest) {
49 AtomicFlag flag; 58 AtomicFlag flag;
50 ASSERT_FALSE(flag.IsSet()); 59 ASSERT_FALSE(flag.IsSet());
51 flag.Set(); 60 flag.Set();
52 ASSERT_TRUE(flag.IsSet()); 61 ASSERT_TRUE(flag.IsSet());
53 flag.Set(); 62 flag.Set();
54 ASSERT_TRUE(flag.IsSet()); 63 ASSERT_TRUE(flag.IsSet());
55 } 64 }
56 65
57 TEST(AtomicFlagTest, ReadFromDifferentThread) { 66 TEST(AtomicFlagTest, ReadFromDifferentThread) {
58 AtomicFlag flag; 67 // |tested_flag| is the one being tested below.
68 AtomicFlag tested_flag;
69 // |expected_after_flag| is used to confirm that sequential consistency is
70 // obtained around |tested_flag|.
71 bool expected_after_flag = false;
72 // |reset_flag| is used to confirm the test flows as intended without using
73 // synchronization constructs which would defeat the purpose of exercising
74 // atomics.
75 AtomicFlag reset_flag;
59 76
60 Thread thread("AtomicFlagTest.ReadFromDifferentThread"); 77 Thread thread("AtomicFlagTest.ReadFromDifferentThread");
61 ASSERT_TRUE(thread.Start()); 78 ASSERT_TRUE(thread.Start());
62 thread.task_runner()->PostTask(FROM_HERE, 79 thread.task_runner()->PostTask(
63 Bind(&BusyWaitUntilFlagIsSet, &flag)); 80 FROM_HERE,
81 Bind(&BusyWaitUntilFlagIsSet, &tested_flag, &expected_after_flag,
82 &reset_flag));
64 83
65 // To verify that IsSet() fetches the flag's value from memory every time it 84 // To verify that IsSet() fetches the flag's value from memory every time it
66 // is called (not just the first time that it is called on a thread), sleep 85 // is called (not just the first time that it is called on a thread), sleep
67 // before setting the flag. 86 // before setting the flag.
68 PlatformThread::Sleep(TimeDelta::FromMilliseconds(25)); 87 PlatformThread::Sleep(TimeDelta::FromMilliseconds(20));
69 88
70 flag.Set(); 89 // |expected_after_flag| is used to verify that all memory operations
90 // performed before |tested_flag| is Set() are visible to threads that can see
91 // IsSet().
92 expected_after_flag = true;
93 tested_flag.Set();
94
95 // Sleep again to give the busy loop time to observe the flag and verify
96 // expectations.
97 PlatformThread::Sleep(TimeDelta::FromMilliseconds(20));
98
99 // Use |reset_flag| to confirm that the above completed (which the rest of
100 // this test assumes).
101 ASSERT_TRUE(reset_flag.IsSet());
102
103 tested_flag.UnsafeResetForTesting();
104 EXPECT_FALSE(tested_flag.IsSet());
105 expected_after_flag = false;
106
107 // Perform the same test again after the controlled UnsafeResetForTesting(),
108 // |thread| is guaranteed to be synchronized past the
109 // |UnsafeResetForTesting()| call when the task runs per the implicit
110 // synchronization in the post task mechanism.
111 thread.task_runner()->PostTask(
112 FROM_HERE,
113 Bind(&BusyWaitUntilFlagIsSet, &tested_flag, &expected_after_flag,
114 nullptr));
115
116 PlatformThread::Sleep(TimeDelta::FromMilliseconds(20));
117
118 expected_after_flag = true;
119 tested_flag.Set();
71 120
72 // The |thread|'s destructor will block until the posted task completes, so 121 // The |thread|'s destructor will block until the posted task completes, so
73 // the test will time out if it fails to see the flag be set. 122 // the test will time out if it fails to see the flag be set.
74 } 123 }
75 124
76 TEST(AtomicFlagTest, SetOnDifferentThreadDeathTest) { 125 TEST(AtomicFlagTest, SetOnDifferentSequenceDeathTest) {
77 // Checks that Set() can't be called from any other thread. AtomicFlag should 126 // Checks that Set() can't be called from another sequence after being called
78 // die on a DCHECK if Set() is called from other thread. 127 // on this one. AtomicFlag should die on a DCHECK if Set() is called again
128 // from another sequence.
79 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; 129 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
80 Thread t("AtomicFlagTest.SetOnDifferentThreadDeathTest"); 130 Thread t("AtomicFlagTest.SetOnDifferentThreadDeathTest");
81 ASSERT_TRUE(t.Start()); 131 ASSERT_TRUE(t.Start());
132 EXPECT_TRUE(t.WaitUntilThreadStarted());
82 133
83 AtomicFlag flag; 134 AtomicFlag flag;
135 flag.Set();
84 t.task_runner()->PostTask(FROM_HERE, Bind(&ExpectSetFlagDeath, &flag)); 136 t.task_runner()->PostTask(FROM_HERE, Bind(&ExpectSetFlagDeath, &flag));
85 } 137 }
86 138
87 } // namespace base 139 } // namespace base
OLDNEW
« 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