#ifndef _H_HANDLETEMPLATES
#define _H_HANDLETEMPLATES
#include <security_utilities/refcount.h>
#include <security_utilities/threading.h>
#include <security_utilities/globalizer.h>
#include <security_cdsa_utilities/cssmerrors.h>
#include <vector>
#include <unordered_map>
namespace Security
{
template <class _Handle>
struct TypedHandle
{
public:
typedef _Handle Handle;
static const _Handle invalidHandle = 0;
_Handle handle() const { return mMyHandle; }
bool validHandle() const { return mValid; }
protected:
TypedHandle(_Handle h);
TypedHandle();
void setHandle(_Handle h)
{
assert(!mValid); mMyHandle = h;
mValid = true;
}
void clearHandle()
{
assert(mValid);
mValid = false;
}
private:
_Handle mMyHandle; bool mValid; };
template <class _Handle>
class MappingHandle : public TypedHandle<_Handle>
{
protected:
class State;
public:
typedef typename TypedHandle<_Handle>::Handle Handle;
virtual ~MappingHandle()
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-var-template"
State &st = state();
#pragma clang diagnostic pop
StLock<Mutex> _(st);
st.erase(this);
}
template <class SubType>
static SubType &find(_Handle handle, CSSM_RETURN error);
template <class Subtype>
static Subtype &findAndLock(_Handle handle, CSSM_RETURN error);
template <class Subtype>
static Subtype &findAndKill(_Handle handle, CSSM_RETURN error);
template <class Subtype>
static RefPointer<Subtype> findRef(_Handle handle, CSSM_RETURN error);
template <class Subtype>
static RefPointer<Subtype> findRefAndLock(_Handle handle, CSSM_RETURN error);
template <class Subtype>
static RefPointer<Subtype> findRefAndKill(_Handle handle, CSSM_RETURN error);
template <class Subtype>
static void findAllRefs(std::vector<_Handle> &refs) {
state().template findAllRefs<Subtype>(refs);
}
protected:
virtual void lock();
virtual bool tryLock();
typedef std::unordered_map<_Handle, MappingHandle<_Handle> *> HandleMap;
MappingHandle();
class State : public Mutex, public HandleMap
{
public:
State();
uint32_t nextSeq() { return ++sequence; }
bool handleInUse(_Handle h);
MappingHandle<_Handle> *find(_Handle h, CSSM_RETURN error);
typename HandleMap::iterator locate(_Handle h, CSSM_RETURN error);
void add(_Handle h, MappingHandle<_Handle> *obj);
void erase(MappingHandle<_Handle> *obj);
void erase(typename HandleMap::iterator &it);
template <class SubType> void findAllRefs(std::vector<_Handle> &refs);
private:
uint32_t sequence;
};
private:
void make();
static ModuleNexus<typename MappingHandle<_Handle>::State> state;
};
template <class _Handle>
template <class Subclass>
inline Subclass &MappingHandle<_Handle>::find(_Handle handle, CSSM_RETURN error)
{
Subclass *sub;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-var-template"
if (!(sub = dynamic_cast<Subclass *>(state().find(handle, error))))
CssmError::throwMe(error);
#pragma clang diagnostic pop
return *sub;
}
template <class _Handle>
template <class Subclass>
inline Subclass &MappingHandle<_Handle>::findAndLock(_Handle handle,
CSSM_RETURN error)
{
for (;;) {
typename HandleMap::iterator it = state().locate(handle, error);
StLock<Mutex> _(state(), true); Subclass *sub;
if (!(sub = dynamic_cast<Subclass *>(it->second)))
CssmError::throwMe(error); if (it->second->tryLock()) return *sub; Thread::yield(); }
}
template <class _Handle>
template <class Subclass>
inline Subclass &MappingHandle<_Handle>::findAndKill(_Handle handle,
CSSM_RETURN error)
{
for (;;) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-var-template"
typename HandleMap::iterator it = state().locate(handle, error);
#pragma clang diagnostic pop
StLock<Mutex> _(state(), true); Subclass *sub;
if (!(sub = dynamic_cast<Subclass *>(it->second)))
CssmError::throwMe(error); if (it->second->tryLock()) { state().erase(it); return *sub; }
Thread::yield(); }
}
template <class _Handle>
template <class Subclass>
inline RefPointer<Subclass> MappingHandle<_Handle>::findRef(_Handle handle,
CSSM_RETURN error)
{
typename HandleMap::iterator it = state().locate(handle, error);
StLock<Mutex> _(state(), true); Subclass *sub;
if (!(sub = dynamic_cast<Subclass *>(it->second)))
CssmError::throwMe(error);
return sub;
}
template <class _Handle>
template <class Subclass>
inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndLock(_Handle handle,
CSSM_RETURN error)
{
for (;;) {
typename HandleMap::iterator it = state().locate(handle, error);
StLock<Mutex> _(state(), true); Subclass *sub;
if (!(sub = dynamic_cast<Subclass *>(it->second)))
CssmError::throwMe(error); if (it->second->tryLock()) return sub; Thread::yield(); }
}
template <class _Handle>
template <class Subclass>
inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndKill(_Handle handle,
CSSM_RETURN error)
{
for (;;) {
typename HandleMap::iterator it = state().locate(handle, error);
StLock<Mutex> _(state(), true); Subclass *sub;
if (!(sub = dynamic_cast<Subclass *>(it->second)))
CssmError::throwMe(error); if (it->second->tryLock()) { state().erase(it); return sub; }
Thread::yield(); }
}
template <class _Handle>
template <class Subtype>
void MappingHandle<_Handle>::State::findAllRefs(std::vector<_Handle> &refs)
{
StLock<Mutex> _(*this);
typename HandleMap::iterator it = (*this).begin();
for (; it != (*this).end(); ++it)
{
Subtype *obj = dynamic_cast<Subtype *>(it->second);
if (obj)
refs.push_back(it->first);
}
}
}
#endif //_H_HANDLETEMPLATES