/src/serenity/AK/Singleton.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2020, the SerenityOS developers. |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/Assertions.h> |
10 | | #include <AK/Atomic.h> |
11 | | #include <AK/Noncopyable.h> |
12 | | #ifdef KERNEL |
13 | | # include <Kernel/Arch/Processor.h> |
14 | | # include <Kernel/Library/ScopedCritical.h> |
15 | | # include <Kernel/Locking/SpinlockProtected.h> |
16 | | #elif defined(AK_OS_WINDOWS) |
17 | | // Forward declare to avoid pulling Windows.h into every file in existence. |
18 | | extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long); |
19 | | # ifndef sched_yield |
20 | | # define sched_yield() Sleep(0) |
21 | | # endif |
22 | | #else |
23 | | # include <sched.h> |
24 | | #endif |
25 | | |
26 | | #ifndef AK_OS_SERENITY |
27 | | # include <new> |
28 | | #endif |
29 | | |
30 | | namespace AK { |
31 | | |
32 | | template<typename T> |
33 | | struct SingletonInstanceCreator { |
34 | | static T* create() |
35 | 13 | { |
36 | 13 | return new T(); |
37 | 13 | } AK::SingletonInstanceCreator<AK::HashTable<AK::Detail::StringData const*, AK::FlyStringTableHashTraits, false> >::create() Line | Count | Source | 35 | 5 | { | 36 | 5 | return new T(); | 37 | 5 | } |
AK::SingletonInstanceCreator<AK::HashTable<AK::StringImpl const*, AK::DeprecatedFlyStringImplTraits, false> >::create() Line | Count | Source | 35 | 8 | { | 36 | 8 | return new T(); | 37 | 8 | } |
Unexecuted instantiation: AK::SingletonInstanceCreator<Core::SignalHandlersInfo>::create() |
38 | | }; |
39 | | |
40 | | #ifdef KERNEL |
41 | | |
42 | | template<typename T, Kernel::LockRank Rank> |
43 | | struct SingletonInstanceCreator<Kernel::SpinlockProtected<T, Rank>> { |
44 | | static Kernel::SpinlockProtected<T, Rank>* create() |
45 | | { |
46 | | return new Kernel::SpinlockProtected<T, Rank> {}; |
47 | | } |
48 | | }; |
49 | | #endif |
50 | | |
51 | | template<typename T, T* (*InitFunction)() = SingletonInstanceCreator<T>::create> |
52 | | class Singleton { |
53 | | AK_MAKE_NONCOPYABLE(Singleton); |
54 | | AK_MAKE_NONMOVABLE(Singleton); |
55 | | |
56 | | public: |
57 | | Singleton() = default; |
58 | | |
59 | | template<bool allow_create = true> |
60 | | static T* get(Atomic<T*>& obj_var) |
61 | 9.19M | { |
62 | 9.19M | T* obj = obj_var.load(AK::memory_order_acquire); |
63 | 9.19M | if (FlatPtr(obj) <= 0x1) { |
64 | | // If this is the first time, see if we get to initialize it |
65 | | #ifdef KERNEL |
66 | | Kernel::ScopedCritical critical; |
67 | | #endif |
68 | 13 | if constexpr (allow_create) { |
69 | 13 | if (obj == nullptr && obj_var.compare_exchange_strong(obj, (T*)0x1, AK::memory_order_acq_rel)) { |
70 | | // We're the first one |
71 | 13 | obj = InitFunction(); |
72 | 13 | obj_var.store(obj, AK::memory_order_release); |
73 | 13 | return obj; |
74 | 13 | } |
75 | 13 | } |
76 | | // Someone else was faster, wait until they're done |
77 | 13 | while (obj == (T*)0x1) { |
78 | | #ifdef KERNEL |
79 | | Kernel::Processor::wait_check(); |
80 | | #else |
81 | 0 | sched_yield(); |
82 | 0 | #endif |
83 | 0 | obj = obj_var.load(AK::memory_order_acquire); |
84 | 0 | } |
85 | 13 | if constexpr (allow_create) { |
86 | | // We should always return an instance if we allow creating one |
87 | 13 | VERIFY(obj != nullptr); |
88 | 13 | } |
89 | 13 | VERIFY(obj != (T*)0x1); |
90 | 13 | } |
91 | 9.19M | return obj; |
92 | 9.19M | } AK::HashTable<AK::Detail::StringData const*, AK::FlyStringTableHashTraits, false>* AK::Singleton<AK::HashTable<AK::Detail::StringData const*, AK::FlyStringTableHashTraits, false>, &AK::SingletonInstanceCreator<AK::HashTable<AK::Detail::StringData const*, AK::FlyStringTableHashTraits, false> >::create>::get<true>(AK::Atomic<AK::HashTable<AK::Detail::StringData const*, AK::FlyStringTableHashTraits, false>*, (AK::MemoryOrder)5>&) Line | Count | Source | 61 | 6.83M | { | 62 | 6.83M | T* obj = obj_var.load(AK::memory_order_acquire); | 63 | 6.83M | if (FlatPtr(obj) <= 0x1) { | 64 | | // If this is the first time, see if we get to initialize it | 65 | | #ifdef KERNEL | 66 | | Kernel::ScopedCritical critical; | 67 | | #endif | 68 | 5 | if constexpr (allow_create) { | 69 | 5 | if (obj == nullptr && obj_var.compare_exchange_strong(obj, (T*)0x1, AK::memory_order_acq_rel)) { | 70 | | // We're the first one | 71 | 5 | obj = InitFunction(); | 72 | 5 | obj_var.store(obj, AK::memory_order_release); | 73 | 5 | return obj; | 74 | 5 | } | 75 | 5 | } | 76 | | // Someone else was faster, wait until they're done | 77 | 5 | while (obj == (T*)0x1) { | 78 | | #ifdef KERNEL | 79 | | Kernel::Processor::wait_check(); | 80 | | #else | 81 | 0 | sched_yield(); | 82 | 0 | #endif | 83 | 0 | obj = obj_var.load(AK::memory_order_acquire); | 84 | 0 | } | 85 | 5 | if constexpr (allow_create) { | 86 | | // We should always return an instance if we allow creating one | 87 | 5 | VERIFY(obj != nullptr); | 88 | 5 | } | 89 | 5 | VERIFY(obj != (T*)0x1); | 90 | 5 | } | 91 | 6.83M | return obj; | 92 | 6.83M | } |
AK::HashTable<AK::StringImpl const*, AK::DeprecatedFlyStringImplTraits, false>* AK::Singleton<AK::HashTable<AK::StringImpl const*, AK::DeprecatedFlyStringImplTraits, false>, &AK::SingletonInstanceCreator<AK::HashTable<AK::StringImpl const*, AK::DeprecatedFlyStringImplTraits, false> >::create>::get<true>(AK::Atomic<AK::HashTable<AK::StringImpl const*, AK::DeprecatedFlyStringImplTraits, false>*, (AK::MemoryOrder)5>&) Line | Count | Source | 61 | 2.36M | { | 62 | 2.36M | T* obj = obj_var.load(AK::memory_order_acquire); | 63 | 2.36M | if (FlatPtr(obj) <= 0x1) { | 64 | | // If this is the first time, see if we get to initialize it | 65 | | #ifdef KERNEL | 66 | | Kernel::ScopedCritical critical; | 67 | | #endif | 68 | 8 | if constexpr (allow_create) { | 69 | 8 | if (obj == nullptr && obj_var.compare_exchange_strong(obj, (T*)0x1, AK::memory_order_acq_rel)) { | 70 | | // We're the first one | 71 | 8 | obj = InitFunction(); | 72 | 8 | obj_var.store(obj, AK::memory_order_release); | 73 | 8 | return obj; | 74 | 8 | } | 75 | 8 | } | 76 | | // Someone else was faster, wait until they're done | 77 | 8 | while (obj == (T*)0x1) { | 78 | | #ifdef KERNEL | 79 | | Kernel::Processor::wait_check(); | 80 | | #else | 81 | 0 | sched_yield(); | 82 | 0 | #endif | 83 | 0 | obj = obj_var.load(AK::memory_order_acquire); | 84 | 0 | } | 85 | 8 | if constexpr (allow_create) { | 86 | | // We should always return an instance if we allow creating one | 87 | 8 | VERIFY(obj != nullptr); | 88 | 8 | } | 89 | 8 | VERIFY(obj != (T*)0x1); | 90 | 8 | } | 91 | 2.36M | return obj; | 92 | 2.36M | } |
Unexecuted instantiation: Core::SignalHandlersInfo* AK::Singleton<Core::SignalHandlersInfo, &AK::SingletonInstanceCreator<Core::SignalHandlersInfo>::create>::get<true>(AK::Atomic<Core::SignalHandlersInfo*, (AK::MemoryOrder)5>&) |
93 | | |
94 | | T* ptr() const |
95 | 9.19M | { |
96 | 9.19M | return get(m_obj); |
97 | 9.19M | } AK::Singleton<AK::HashTable<AK::Detail::StringData const*, AK::FlyStringTableHashTraits, false>, &AK::SingletonInstanceCreator<AK::HashTable<AK::Detail::StringData const*, AK::FlyStringTableHashTraits, false> >::create>::ptr() const Line | Count | Source | 95 | 6.83M | { | 96 | 6.83M | return get(m_obj); | 97 | 6.83M | } |
AK::Singleton<AK::HashTable<AK::StringImpl const*, AK::DeprecatedFlyStringImplTraits, false>, &AK::SingletonInstanceCreator<AK::HashTable<AK::StringImpl const*, AK::DeprecatedFlyStringImplTraits, false> >::create>::ptr() const Line | Count | Source | 95 | 2.36M | { | 96 | 2.36M | return get(m_obj); | 97 | 2.36M | } |
Unexecuted instantiation: AK::Singleton<Core::SignalHandlersInfo, &AK::SingletonInstanceCreator<Core::SignalHandlersInfo>::create>::ptr() const |
98 | | |
99 | | T* operator->() const |
100 | | { |
101 | | return ptr(); |
102 | | } |
103 | | |
104 | | T& operator*() const |
105 | 9.19M | { |
106 | 9.19M | return *ptr(); |
107 | 9.19M | } AK::Singleton<AK::HashTable<AK::Detail::StringData const*, AK::FlyStringTableHashTraits, false>, &AK::SingletonInstanceCreator<AK::HashTable<AK::Detail::StringData const*, AK::FlyStringTableHashTraits, false> >::create>::operator*() const Line | Count | Source | 105 | 6.83M | { | 106 | 6.83M | return *ptr(); | 107 | 6.83M | } |
AK::Singleton<AK::HashTable<AK::StringImpl const*, AK::DeprecatedFlyStringImplTraits, false>, &AK::SingletonInstanceCreator<AK::HashTable<AK::StringImpl const*, AK::DeprecatedFlyStringImplTraits, false> >::create>::operator*() const Line | Count | Source | 105 | 2.36M | { | 106 | 2.36M | return *ptr(); | 107 | 2.36M | } |
|
108 | | |
109 | | operator T*() const |
110 | | { |
111 | | return ptr(); |
112 | | } |
113 | | |
114 | | operator T&() const |
115 | | { |
116 | | return *ptr(); |
117 | | } |
118 | | |
119 | | bool is_initialized() const |
120 | | { |
121 | | T* obj = m_obj.load(AK::MemoryOrder::memory_order_consume); |
122 | | return FlatPtr(obj) > 0x1; |
123 | | } |
124 | | |
125 | | void ensure_instance() |
126 | | { |
127 | | ptr(); |
128 | | } |
129 | | |
130 | | private: |
131 | | mutable Atomic<T*> m_obj { nullptr }; |
132 | | }; |
133 | | |
134 | | } |
135 | | |
136 | | #if USING_AK_GLOBALLY |
137 | | using AK::Singleton; |
138 | | #endif |