Chromium Code Reviews| 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 // defeat the purpose of testing atomics) until |flag| is set and then invokes | |
| 36 // |callback|. | |
| 37 void BusyWaitUntilFlagIsSet(AtomicFlag* flag, const base::Closure& callback) { | |
|
danakj
2016/07/28 19:57:22
nit: this would be easier to read if you just pass
gab
2016/08/01 17:46:45
Done.
| |
| 35 while (!flag->IsSet()) | 38 while (!flag->IsSet()) |
| 36 PlatformThread::YieldCurrentThread(); | 39 PlatformThread::YieldCurrentThread(); |
| 40 | |
| 41 callback.Run(); | |
| 37 } | 42 } |
| 38 | 43 |
| 39 } // namespace | 44 } // namespace |
| 40 | 45 |
| 41 TEST(AtomicFlagTest, SimpleSingleThreadedTest) { | 46 TEST(AtomicFlagTest, SimpleSingleThreadedTest) { |
| 42 AtomicFlag flag; | 47 AtomicFlag flag; |
| 43 ASSERT_FALSE(flag.IsSet()); | 48 ASSERT_FALSE(flag.IsSet()); |
| 44 flag.Set(); | 49 flag.Set(); |
| 45 ASSERT_TRUE(flag.IsSet()); | 50 ASSERT_TRUE(flag.IsSet()); |
| 46 } | 51 } |
| 47 | 52 |
| 48 TEST(AtomicFlagTest, DoubleSetTest) { | 53 TEST(AtomicFlagTest, DoubleSetTest) { |
| 49 AtomicFlag flag; | 54 AtomicFlag flag; |
| 50 ASSERT_FALSE(flag.IsSet()); | 55 ASSERT_FALSE(flag.IsSet()); |
| 51 flag.Set(); | 56 flag.Set(); |
| 52 ASSERT_TRUE(flag.IsSet()); | 57 ASSERT_TRUE(flag.IsSet()); |
| 53 flag.Set(); | 58 flag.Set(); |
| 54 ASSERT_TRUE(flag.IsSet()); | 59 ASSERT_TRUE(flag.IsSet()); |
| 55 } | 60 } |
| 56 | 61 |
| 57 TEST(AtomicFlagTest, ReadFromDifferentThread) { | 62 TEST(AtomicFlagTest, ReadFromDifferentThread) { |
| 58 AtomicFlag flag; | 63 // |tested_flag| is the one being tested below. |
| 64 AtomicFlag tested_flag; | |
| 65 // |expected_after_flag| is used to confirm that sequential consistency is | |
| 66 // obtained around |tested_flag|. | |
| 67 bool expected_after_flag = false; | |
| 68 // |reset_flag| is used to confirm the test flows as intended without using | |
| 69 // synchronization constructs which would defeat the purpose of exercising | |
| 70 // atomics. | |
| 71 AtomicFlag reset_flag; | |
| 72 | |
| 73 const base::Closure verify_and_signal = Bind( | |
| 74 [](bool* expected_after_flag, AtomicFlag* reset_flag) { | |
| 75 EXPECT_TRUE(*expected_after_flag); | |
| 76 reset_flag->Set(); | |
| 77 }, | |
| 78 &expected_after_flag, &reset_flag); | |
| 59 | 79 |
| 60 Thread thread("AtomicFlagTest.ReadFromDifferentThread"); | 80 Thread thread("AtomicFlagTest.ReadFromDifferentThread"); |
| 61 ASSERT_TRUE(thread.Start()); | 81 ASSERT_TRUE(thread.Start()); |
| 62 thread.task_runner()->PostTask(FROM_HERE, | 82 thread.task_runner()->PostTask( |
| 63 Bind(&BusyWaitUntilFlagIsSet, &flag)); | 83 FROM_HERE, |
| 84 Bind(&BusyWaitUntilFlagIsSet, &tested_flag, verify_and_signal)); | |
| 64 | 85 |
| 65 // To verify that IsSet() fetches the flag's value from memory every time it | 86 // 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 | 87 // is called (not just the first time that it is called on a thread), sleep |
| 67 // before setting the flag. | 88 // before setting the flag. |
| 68 PlatformThread::Sleep(TimeDelta::FromMilliseconds(25)); | 89 PlatformThread::Sleep(TimeDelta::FromMilliseconds(20)); |
| 69 | 90 |
| 70 flag.Set(); | 91 // |expected_after_flag| is used to verify that all memory operations |
| 92 // performed before |tested_flag| is Set() are visible to threads that can see | |
| 93 // IsSet(). | |
| 94 expected_after_flag = true; | |
| 95 tested_flag.Set(); | |
| 96 | |
| 97 // Sleep again to give the busy loop time to observe the flag and verify | |
| 98 // expectations. | |
| 99 PlatformThread::Sleep(TimeDelta::FromMilliseconds(20)); | |
| 100 | |
| 101 // Use |reset_flag| to confirm that the above completed (which the rest of | |
| 102 // this test assumes). | |
| 103 ASSERT_TRUE(reset_flag.IsSet()); | |
| 104 | |
| 105 tested_flag.UnsafeReset(); | |
| 106 EXPECT_FALSE(tested_flag.IsSet()); | |
| 107 expected_after_flag = false; | |
| 108 | |
| 109 // Perform the same test again after the controlled UnsafeReset(), |thread| is | |
| 110 // guaranteed to be synchronized past the |UnsafeReset()| call when the task | |
| 111 // runs per the implicit synchronization in the post task mechanism. | |
| 112 thread.task_runner()->PostTask( | |
| 113 FROM_HERE, | |
| 114 Bind(&BusyWaitUntilFlagIsSet, &tested_flag, verify_and_signal)); | |
| 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 |