blob: 1a940691d9f1fbd9186d445007b49c3cec83a678 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef INITLOCK_H
#define INITLOCK_H
#include <atomic>
#include <mutex>
/**
* Almost entirely analogous to std::once_flag, but with the ability to be reset if the caller knows it is safe to do so.
*/
class InitLock
{
public:
template <typename F>
void init(F &&f) const
{
// Make sure the fast path is a single load-acquire - not guaranteed with std::once_flag.
[[likely]] if (inited.load(std::memory_order_acquire)) {
return;
}
std::call_once(once, [&] {
f();
inited.store(true, std::memory_order_release);
});
}
void reset()
{
inited.store(false, std::memory_order_relaxed);
// Abomination, but tenuously allowed by Standard.
// (The alternative, std::mutex, is too large - we want to create a lot of these objects.)
once.~once_flag();
new (&once) std::once_flag();
}
private:
mutable std::once_flag once;
mutable std::atomic<bool> inited = false;
};
#endif // INITLOCK_H
|