mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 19:25:51 +00:00
194 lines
5.5 KiB
Objective-C
194 lines
5.5 KiB
Objective-C
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
//==============================================================================
|
|
|
|
#ifndef BEAST_SHAREDSINGLETON_H_INCLUDED
|
|
#define BEAST_SHAREDSINGLETON_H_INCLUDED
|
|
|
|
/** Thread-safe singleton which comes into existence on first use. Use this
|
|
instead of creating objects with static storage duration. These singletons
|
|
are automatically reference counted, so if you hold a pointer to it in every
|
|
object that depends on it, the order of destruction of objects is assured
|
|
to be correct.
|
|
|
|
class Object must provide the function `Object* Object::createInstance()`
|
|
|
|
@class SharedSingleton
|
|
@ingroup beast_core
|
|
*/
|
|
/** @{ */
|
|
class BEAST_API SingletonLifetime
|
|
{
|
|
public:
|
|
// It would be nice if we didn't have to qualify the enumeration but
|
|
// Argument Dependent Lookup is inapplicable here because:
|
|
//
|
|
// "Base classes dependent on a template parameter aren't part of lookup."
|
|
// - ville
|
|
//
|
|
|
|
/** Construction options for SharedSingleton
|
|
|
|
@ingroup beast_core
|
|
*/
|
|
enum Lifetime
|
|
{
|
|
/** Created on first use, destroyed when the last reference is removed.
|
|
*/
|
|
createOnDemand,
|
|
|
|
/** The singleton is created on first use and persists until program exit.
|
|
*/
|
|
persistAfterCreation,
|
|
|
|
/** The singleton is created when needed and never destroyed.
|
|
|
|
This is useful for applications which do not have a clean exit.
|
|
*/
|
|
neverDestroyed
|
|
};
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
/** Wraps object to produce a reference counted singleton. */
|
|
template <class Object>
|
|
class SharedSingleton
|
|
: public Object
|
|
, private SharedObject
|
|
{
|
|
public:
|
|
typedef SharedPtr <SharedSingleton <Object> > Ptr;
|
|
|
|
static Ptr getInstance (SingletonLifetime::Lifetime lifetime
|
|
= SingletonLifetime::persistAfterCreation)
|
|
{
|
|
StaticData& staticData (getStaticData ());
|
|
SharedSingleton* instance = staticData.instance;
|
|
if (instance == nullptr)
|
|
{
|
|
LockType::ScopedLockType lock (staticData.mutex);
|
|
instance = staticData.instance;
|
|
if (instance == nullptr)
|
|
{
|
|
staticData.instance = &staticData.object;
|
|
::new (staticData.instance) SharedSingleton (lifetime);
|
|
instance = staticData.instance;
|
|
}
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
private:
|
|
explicit SharedSingleton (SingletonLifetime::Lifetime lifetime)
|
|
: m_lifetime (lifetime)
|
|
, m_exitHook (this)
|
|
{
|
|
if (m_lifetime == SingletonLifetime::persistAfterCreation)
|
|
this->incReferenceCount ();
|
|
}
|
|
|
|
~SharedSingleton ()
|
|
{
|
|
}
|
|
|
|
void performAtExit ()
|
|
{
|
|
if (m_lifetime == SingletonLifetime::persistAfterCreation)
|
|
this->decReferenceCount ();
|
|
}
|
|
|
|
void destroy () const
|
|
{
|
|
bool callDestructor;
|
|
|
|
// Handle the condition where one thread is releasing the last
|
|
// reference just as another thread is trying to acquire it.
|
|
//
|
|
{
|
|
StaticData& staticData (getStaticData ());
|
|
LockType::ScopedLockType lock (staticData.mutex);
|
|
|
|
if (this->getReferenceCount() != 0)
|
|
{
|
|
callDestructor = false;
|
|
}
|
|
else
|
|
{
|
|
callDestructor = true;
|
|
staticData.instance = nullptr;
|
|
}
|
|
}
|
|
|
|
if (callDestructor)
|
|
{
|
|
bassert (m_lifetime != SingletonLifetime::neverDestroyed);
|
|
|
|
this->~SharedSingleton();
|
|
}
|
|
}
|
|
|
|
typedef SpinLock LockType;
|
|
|
|
class ExitHook : public PerformedAtExit
|
|
{
|
|
public:
|
|
explicit ExitHook (SharedSingleton* owner)
|
|
: m_owner (owner)
|
|
{
|
|
}
|
|
|
|
void performAtExit ()
|
|
{
|
|
m_owner->performAtExit();
|
|
}
|
|
|
|
private:
|
|
SharedSingleton* m_owner;
|
|
};
|
|
|
|
// This structure gets zero-filled at static initialization time.
|
|
// No constructors are called.
|
|
//
|
|
struct StaticData
|
|
{
|
|
LockType mutex;
|
|
SharedSingleton* instance;
|
|
SharedSingleton object;
|
|
|
|
private:
|
|
StaticData();
|
|
~StaticData();
|
|
};
|
|
|
|
static StaticData& getStaticData ()
|
|
{
|
|
static uint8 storage [sizeof (StaticData)];
|
|
return *(reinterpret_cast <StaticData*> (&storage [0]));
|
|
}
|
|
|
|
friend class SharedPtr <SharedSingleton>;
|
|
|
|
SingletonLifetime::Lifetime m_lifetime;
|
|
ExitHook m_exitHook;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
#endif
|