xref: /llvm-project/llvm/unittests/ADT/LazyAtomicPointerTest.cpp (revision 716042a63f26cd020eb72960f72fa97b9a197382)
15d2a7101SSteven Wu //===- LazyAtomicPointerTest.cpp ------------------------------------------===//
25d2a7101SSteven Wu //
35d2a7101SSteven Wu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45d2a7101SSteven Wu // See https://llvm.org/LICENSE.txt for license information.
55d2a7101SSteven Wu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65d2a7101SSteven Wu //
75d2a7101SSteven Wu //===----------------------------------------------------------------------===//
85d2a7101SSteven Wu 
95d2a7101SSteven Wu #include "llvm/ADT/LazyAtomicPointer.h"
105d2a7101SSteven Wu #include "llvm/Config/llvm-config.h"
115d2a7101SSteven Wu #include "llvm/Support/ThreadPool.h"
125d2a7101SSteven Wu #include "gtest/gtest.h"
135d2a7101SSteven Wu 
145d2a7101SSteven Wu using namespace llvm;
155d2a7101SSteven Wu 
165d2a7101SSteven Wu namespace {
175d2a7101SSteven Wu 
TEST(LazyAtomicPointer,loadOrGenerate)185d2a7101SSteven Wu TEST(LazyAtomicPointer, loadOrGenerate) {
195d2a7101SSteven Wu   int Value = 0;
205d2a7101SSteven Wu   LazyAtomicPointer<int> Ptr;
21*716042a6SMehdi Amini   DefaultThreadPool Threads;
225d2a7101SSteven Wu   for (unsigned I = 0; I < 4; ++I)
235d2a7101SSteven Wu     Threads.async([&]() {
245d2a7101SSteven Wu       Ptr.loadOrGenerate([&]() {
255d2a7101SSteven Wu         // Make sure this is only called once.
265d2a7101SSteven Wu         static std::atomic<bool> Once(false);
275d2a7101SSteven Wu         bool Current = false;
285d2a7101SSteven Wu         EXPECT_TRUE(Once.compare_exchange_strong(Current, true));
295d2a7101SSteven Wu         return &Value;
305d2a7101SSteven Wu       });
315d2a7101SSteven Wu     });
325d2a7101SSteven Wu 
335d2a7101SSteven Wu   Threads.wait();
345d2a7101SSteven Wu   EXPECT_EQ(Ptr.load(), &Value);
355d2a7101SSteven Wu }
365d2a7101SSteven Wu 
375d2a7101SSteven Wu #if (LLVM_ENABLE_THREADS)
TEST(LazyAtomicPointer,BusyState)385d2a7101SSteven Wu TEST(LazyAtomicPointer, BusyState) {
395d2a7101SSteven Wu   int Value = 0;
405d2a7101SSteven Wu   LazyAtomicPointer<int> Ptr;
41*716042a6SMehdi Amini   DefaultThreadPool Threads;
425d2a7101SSteven Wu 
435d2a7101SSteven Wu   std::mutex BusyLock, EndLock;
445d2a7101SSteven Wu   std::condition_variable Busy, End;
455d2a7101SSteven Wu   bool IsBusy = false, IsEnd = false;
465d2a7101SSteven Wu   Threads.async([&]() {
475d2a7101SSteven Wu     Ptr.loadOrGenerate([&]() {
485d2a7101SSteven Wu       // Notify busy state.
495d2a7101SSteven Wu       {
505d2a7101SSteven Wu         std::lock_guard<std::mutex> Lock(BusyLock);
515d2a7101SSteven Wu         IsBusy = true;
525d2a7101SSteven Wu       }
535d2a7101SSteven Wu       Busy.notify_all();
545d2a7101SSteven Wu       std::unique_lock<std::mutex> LEnd(EndLock);
555d2a7101SSteven Wu       // Wait for end state.
565d2a7101SSteven Wu       End.wait(LEnd, [&]() { return IsEnd; });
575d2a7101SSteven Wu       return &Value;
585d2a7101SSteven Wu     });
595d2a7101SSteven Wu   });
605d2a7101SSteven Wu 
615d2a7101SSteven Wu   // Wait for busy state.
625d2a7101SSteven Wu   std::unique_lock<std::mutex> LBusy(BusyLock);
635d2a7101SSteven Wu   Busy.wait(LBusy, [&]() { return IsBusy; });
645d2a7101SSteven Wu   int *ExistingValue = nullptr;
655d2a7101SSteven Wu   // Busy state will not exchange the value.
665d2a7101SSteven Wu   EXPECT_FALSE(Ptr.compare_exchange_weak(ExistingValue, nullptr));
675d2a7101SSteven Wu   // Busy state return nullptr on load/compare_exchange_weak.
685d2a7101SSteven Wu   EXPECT_EQ(ExistingValue, nullptr);
695d2a7101SSteven Wu   EXPECT_EQ(Ptr.load(), nullptr);
705d2a7101SSteven Wu 
715d2a7101SSteven Wu   // End busy state.
725d2a7101SSteven Wu   {
735d2a7101SSteven Wu     std::lock_guard<std::mutex> Lock(EndLock);
745d2a7101SSteven Wu     IsEnd = true;
755d2a7101SSteven Wu   }
765d2a7101SSteven Wu   End.notify_all();
775d2a7101SSteven Wu   Threads.wait();
785d2a7101SSteven Wu   EXPECT_EQ(Ptr.load(), &Value);
795d2a7101SSteven Wu }
805d2a7101SSteven Wu #endif
815d2a7101SSteven Wu 
825d2a7101SSteven Wu } // namespace
83