Home | History | Annotate | Download | only in synchronization
      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