OLD | NEW |
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 Loading... |
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 |
OLD | NEW |