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