Coverage Report

Created: 2025-09-05 06:52

/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