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