AK: Add static Singleton::get function to allow destructible globals

This enable using global raw pointers rather than Singleton objects,
which solves some problems because global Singleton object could
be deleted when destructors are run.
This commit is contained in:
Tom 2021-01-08 12:01:53 -07:00 committed by Andreas Kling
commit 1fc7d65aad
Notes: sideshowbarker 2024-07-18 23:58:56 +09:00

View file

@ -56,36 +56,46 @@ class Singleton {
public: public:
Singleton() = default; Singleton() = default;
T* ptr() const template<bool allow_create = true>
static T* get(T*& obj_var)
{ {
T* obj = AK::atomic_load(&m_obj, AK::memory_order_consume); T* obj = AK::atomic_load(&obj_var, AK::memory_order_acquire);
if (FlatPtr(obj) <= 0x1) { if (FlatPtr(obj) <= 0x1) {
// If this is the first time, see if we get to initialize it // If this is the first time, see if we get to initialize it
#ifdef KERNEL #ifdef KERNEL
Kernel::ScopedCritical critical; Kernel::ScopedCritical critical;
#endif #endif
if (obj == nullptr && AK::atomic_compare_exchange_strong(&m_obj, obj, (T*)0x1, AK::memory_order_acq_rel)) { if constexpr (allow_create) {
// We're the first one if (obj == nullptr && AK::atomic_compare_exchange_strong(&obj_var, obj, (T*)0x1, AK::memory_order_acq_rel)) {
obj = InitFunction(); // We're the first one
AK::atomic_store(&m_obj, obj, AK::memory_order_release); obj = InitFunction();
} else { AK::atomic_store(&obj_var, obj, AK::memory_order_release);
// Someone else was faster, wait until they're done return obj;
while (obj == (T*)0x1) {
#ifdef KERNEL
Kernel::Processor::wait_check();
#else
// TODO: yield
#endif
obj = AK::atomic_load(&m_obj, AK::memory_order_consume);
} }
} }
// We should always return an instance // Someone else was faster, wait until they're done
ASSERT(obj != nullptr); while (obj == (T*)0x1) {
#ifdef KERNEL
Kernel::Processor::wait_check();
#else
// TODO: yield
#endif
obj = AK::atomic_load(&obj_var, AK::memory_order_acquire);
}
if constexpr (allow_create) {
// We should always return an instance if we allow creating one
ASSERT(obj != nullptr);
}
ASSERT(obj != (T*)0x1); ASSERT(obj != (T*)0x1);
} }
return obj; return obj;
} }
T* ptr() const
{
return get(m_obj);
}
T* operator->() const T* operator->() const
{ {
return ptr(); return ptr();