X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cdsa_utilities/lib/handletemplates.h diff --git a/Security/libsecurity_cdsa_utilities/lib/handletemplates.h b/Security/libsecurity_cdsa_utilities/lib/handletemplates.h new file mode 100644 index 00000000..ed9da369 --- /dev/null +++ b/Security/libsecurity_cdsa_utilities/lib/handletemplates.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2008,2011-2012 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// Templates to support HandleObject-like objects +// +#ifndef _H_HANDLETEMPLATES +#define _H_HANDLETEMPLATES + +#include +#include +#include +#include +#include + +#if __GNUC__ > 2 +#include +using __gnu_cxx::hash_map; +#else +#include +#endif + +namespace Security +{ + +// +// A TypedHandle is a trivial mixin class whose only feature is that +// it has a *handle* whose type is of the caller's choosing. Subclasses +// need to assign such a handle during creation. +// +template +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); // guard against redefinition + mMyHandle = h; + mValid = true; + } + void clearHandle() + { + assert(mValid); + mValid = false; + } + +private: + _Handle mMyHandle; // our handle value + bool mValid; // is the handle (still) valid? +}; + +// +// MappingHandle wraps a map indexed by handles of the chosen type. +// A MappingHandle makes up its own handle based on some mechanism that you +// know nothing about. +// +// Please be very careful about the limits of the object contract here. +// We promise to invent a suitable, unique handle for each MappingHandle in +// existence within one address space. We promise that if you hand that +// handle to the various MappingHandle<>::find() variants, we will give you +// back the MappingHandle that created it. We promise to throw if you pass +// a bad handle to those MappingHandle<>::find() variants. This is the +// entire contract. +// +template +class MappingHandle : public TypedHandle<_Handle> +{ +protected: + class State; + +public: + typedef typename TypedHandle<_Handle>::Handle Handle; + virtual ~MappingHandle() + { + State &st = state(); + StLock _(st); + st.erase(this); + } + + template + static SubType &find(_Handle handle, CSSM_RETURN error); + + template + static Subtype &findAndLock(_Handle handle, CSSM_RETURN error); + + template + static Subtype &findAndKill(_Handle handle, CSSM_RETURN error); + + template + static RefPointer findRef(_Handle handle, CSSM_RETURN error); + + template + static RefPointer findRefAndLock(_Handle handle, CSSM_RETURN error); + + template + static RefPointer findRefAndKill(_Handle handle, CSSM_RETURN error); + + // @@@ Remove when 4003540 is fixed + template + static void findAllRefs(std::vector<_Handle> &refs) { + state().template findAllRefs(refs); + } + +protected: + virtual void lock(); + virtual bool tryLock(); + + typedef hash_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); + // @@@ Remove when 4003540 is fixed + template void findAllRefs(std::vector<_Handle> &refs); + + private: + uint32_t sequence; + }; + +private: + // + // Create the handle to be used by the map + // + void make(); + + static ModuleNexus::State> state; +}; + +// +// MappingHandle class methods +// Type-specific ways to access the map in various ways +// +template +template +inline Subclass &MappingHandle<_Handle>::find(_Handle handle, CSSM_RETURN error) +{ + Subclass *sub; + if (!(sub = dynamic_cast(state().find(handle, error)))) + CssmError::throwMe(error); + return *sub; +} + +template +template +inline Subclass &MappingHandle<_Handle>::findAndLock(_Handle handle, + CSSM_RETURN error) +{ + for (;;) { + typename HandleMap::iterator it = state().locate(handle, error); + StLock _(state(), true); // locate() locked it + Subclass *sub; + if (!(sub = dynamic_cast(it->second))) + CssmError::throwMe(error); // bad type + if (it->second->tryLock()) // try to lock it + return *sub; // okay, go + Thread::yield(); // object lock failed, backoff and retry + } +} + +template +template +inline Subclass &MappingHandle<_Handle>::findAndKill(_Handle handle, + CSSM_RETURN error) +{ + for (;;) { + typename HandleMap::iterator it = state().locate(handle, error); + StLock _(state(), true); // locate() locked it + Subclass *sub; + if (!(sub = dynamic_cast(it->second))) + CssmError::throwMe(error); // bad type + if (it->second->tryLock()) { // try to lock it + state().erase(it); // kill the handle + return *sub; // okay, go + } + Thread::yield(); // object lock failed, backoff and retry + } +} + +template +template +inline RefPointer MappingHandle<_Handle>::findRef(_Handle handle, + CSSM_RETURN error) +{ + typename HandleMap::iterator it = state().locate(handle, error); + StLock _(state(), true); // locate() locked it + Subclass *sub; + if (!(sub = dynamic_cast(it->second))) + CssmError::throwMe(error); + return sub; +} + +template +template +inline RefPointer MappingHandle<_Handle>::findRefAndLock(_Handle handle, + CSSM_RETURN error) +{ + for (;;) { + typename HandleMap::iterator it = state().locate(handle, error); + StLock _(state(), true); // locate() locked it + Subclass *sub; + if (!(sub = dynamic_cast(it->second))) + CssmError::throwMe(error); // bad type + if (it->second->tryLock()) // try to lock it + return sub; // okay, go + Thread::yield(); // object lock failed, backoff and retry + } +} + +template +template +inline RefPointer MappingHandle<_Handle>::findRefAndKill(_Handle handle, + CSSM_RETURN error) +{ + for (;;) { + typename HandleMap::iterator it = state().locate(handle, error); + StLock _(state(), true); // locate() locked it + Subclass *sub; + if (!(sub = dynamic_cast(it->second))) + CssmError::throwMe(error); // bad type + if (it->second->tryLock()) { // try to lock it + state().erase(it); // kill the handle + return sub; // okay, go + } + Thread::yield(); // object lock failed, backoff and retry + } +} + +// +// @@@ Remove when 4003540 is fixed +// +// This is a hack to fix 3981388 and should NOT be used elsewhere. +// Also, do not follow this code's example: State methods should not +// implement type-specific behavior. +// +template +template +void MappingHandle<_Handle>::State::findAllRefs(std::vector<_Handle> &refs) +{ + StLock _(*this); + typename HandleMap::iterator it = (*this).begin(); + for (; it != (*this).end(); ++it) + { + Subtype *obj = dynamic_cast(it->second); + if (obj) + refs.push_back(it->first); + } +} + + +} // end namespace Security + +#endif //_H_HANDLETEMPLATES