2025-10-21 11:25:10 -03:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2025, Ryszard Goc <ryszardgoc@gmail.com>
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <AK/Atomic.h>
|
|
|
|
|
#include <AK/Concepts.h>
|
2025-10-30 09:29:29 -03:00
|
|
|
#include <LibSync/Mutex.h>
|
2025-10-21 11:25:10 -03:00
|
|
|
|
2025-10-30 09:29:29 -03:00
|
|
|
namespace Sync {
|
2025-10-21 11:25:10 -03:00
|
|
|
|
|
|
|
|
struct OnceFlag {
|
2025-10-30 09:29:29 -03:00
|
|
|
Sync::Mutex mutex;
|
2025-10-21 11:25:10 -03:00
|
|
|
Atomic<bool> has_been_called { false };
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<VoidFunction Callable>
|
|
|
|
|
void call_once(OnceFlag& flag, Callable&& callable)
|
|
|
|
|
{
|
|
|
|
|
if (!flag.has_been_called.load(MemoryOrder::memory_order_acquire)) {
|
2025-10-30 09:29:29 -03:00
|
|
|
Sync::MutexLocker lock(flag.mutex);
|
2025-10-21 11:25:10 -03:00
|
|
|
|
|
|
|
|
// Another thread may have called the function while we were waiting on the mutex
|
|
|
|
|
// The mutex guarantees exclusivity so we can use relaxed ordering
|
|
|
|
|
if (flag.has_been_called.load(MemoryOrder::memory_order_relaxed))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
callable();
|
|
|
|
|
flag.has_been_called.store(true, MemoryOrder::memory_order_release);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|