/* * 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