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