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