xref: /llvm-project/llvm/unittests/ADT/LazyAtomicPointerTest.cpp (revision 716042a63f26cd020eb72960f72fa97b9a197382)
1 //===- LazyAtomicPointerTest.cpp ------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ADT/LazyAtomicPointer.h"
10 #include "llvm/Config/llvm-config.h"
11 #include "llvm/Support/ThreadPool.h"
12 #include "gtest/gtest.h"
13 
14 using namespace llvm;
15 
16 namespace {
17 
TEST(LazyAtomicPointer,loadOrGenerate)18 TEST(LazyAtomicPointer, loadOrGenerate) {
19   int Value = 0;
20   LazyAtomicPointer<int> Ptr;
21   DefaultThreadPool Threads;
22   for (unsigned I = 0; I < 4; ++I)
23     Threads.async([&]() {
24       Ptr.loadOrGenerate([&]() {
25         // Make sure this is only called once.
26         static std::atomic<bool> Once(false);
27         bool Current = false;
28         EXPECT_TRUE(Once.compare_exchange_strong(Current, true));
29         return &Value;
30       });
31     });
32 
33   Threads.wait();
34   EXPECT_EQ(Ptr.load(), &Value);
35 }
36 
37 #if (LLVM_ENABLE_THREADS)
TEST(LazyAtomicPointer,BusyState)38 TEST(LazyAtomicPointer, BusyState) {
39   int Value = 0;
40   LazyAtomicPointer<int> Ptr;
41   DefaultThreadPool Threads;
42 
43   std::mutex BusyLock, EndLock;
44   std::condition_variable Busy, End;
45   bool IsBusy = false, IsEnd = false;
46   Threads.async([&]() {
47     Ptr.loadOrGenerate([&]() {
48       // Notify busy state.
49       {
50         std::lock_guard<std::mutex> Lock(BusyLock);
51         IsBusy = true;
52       }
53       Busy.notify_all();
54       std::unique_lock<std::mutex> LEnd(EndLock);
55       // Wait for end state.
56       End.wait(LEnd, [&]() { return IsEnd; });
57       return &Value;
58     });
59   });
60 
61   // Wait for busy state.
62   std::unique_lock<std::mutex> LBusy(BusyLock);
63   Busy.wait(LBusy, [&]() { return IsBusy; });
64   int *ExistingValue = nullptr;
65   // Busy state will not exchange the value.
66   EXPECT_FALSE(Ptr.compare_exchange_weak(ExistingValue, nullptr));
67   // Busy state return nullptr on load/compare_exchange_weak.
68   EXPECT_EQ(ExistingValue, nullptr);
69   EXPECT_EQ(Ptr.load(), nullptr);
70 
71   // End busy state.
72   {
73     std::lock_guard<std::mutex> Lock(EndLock);
74     IsEnd = true;
75   }
76   End.notify_all();
77   Threads.wait();
78   EXPECT_EQ(Ptr.load(), &Value);
79 }
80 #endif
81 
82 } // namespace
83