#ifndef _H_GLOBALIZER
#define _H_GLOBALIZER
#include <security_utilities/threading.h>
#include <memory>
#include <set>
#include <dispatch/dispatch.h>
#include <libkern/OSAtomic.h>
namespace Security {
class GlobalNexus {
public:
class Error : public std::exception {
public:
virtual ~Error() throw();
const char * const message;
Error(const char *m) : message(m) { }
const char *what() const throw() { return message; }
};
};
class ModuleNexusCommon : public GlobalNexus {
private:
void do_create(void *(*make)());
protected:
void *create(void *(*make)());
void lock() {OSSpinLockLock(&access);}
void unlock() {OSSpinLockUnlock(&access);}
protected:
void *pointer;
dispatch_once_t once;
OSSpinLock access;
};
template <class Type>
class ModuleNexus : public ModuleNexusCommon {
public:
Type &operator () ()
{
lock();
try
{
if (pointer == NULL)
{
pointer = create(make);
}
unlock();
}
catch (...)
{
unlock();
throw;
}
return *reinterpret_cast<Type *>(pointer);
}
bool exists() const
{
bool result;
lock();
result = pointer != NULL;
unlock();
return result;
}
void reset()
{
lock();
if (pointer != NULL)
{
delete reinterpret_cast<Type *>(pointer);
pointer = NULL;
once = 0;
}
unlock();
}
private:
static void *make() { return new Type; }
};
template <class Type>
class CleanModuleNexus : public ModuleNexus<Type> {
public:
~CleanModuleNexus()
{
secdebug("nexus", "ModuleNexus %p destroyed object 0x%x",
this, ModuleNexus<Type>::pointer);
delete reinterpret_cast<Type *>(ModuleNexus<Type>::pointer);
}
};
typedef std::set<void*> RetentionSet;
template <class Type>
class ThreadNexus : public GlobalNexus {
public:
ThreadNexus() : mSlot(true) { }
Type &operator () ()
{
if (Type *p = mSlot)
return *p;
mSlot = new Type;
return *mSlot;
}
private:
PerThreadPointer<Type> mSlot;
};
class ProcessNexusBase : public GlobalNexus {
protected:
ProcessNexusBase(const char *identifier);
struct Store {
void *mObject;
Mutex mLock;
};
Store *mStore;
};
template <class Type>
class ProcessNexus : public ProcessNexusBase {
public:
ProcessNexus(const char *identifier) : ProcessNexusBase(identifier) { }
Type &operator () ();
private:
Type *mObject;
};
template <class Type>
Type &ProcessNexus<Type>::operator () ()
{
#if !defined(PTHREAD_STRICT)
if (mStore->mObject)
return *reinterpret_cast<Type *>(mStore->mObject);
#endif
StLock<Mutex> _(mStore->mLock);
if (mStore->mObject == NULL)
mStore->mObject = new Type;
return *reinterpret_cast<Type *>(mStore->mObject);
};
}
#endif //_H_GLOBALIZER