/* * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * 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@ */ // // handleobject - give an object a process-global unique handle // #ifndef _H_HANDLEOBJECT #define _H_HANDLEOBJECT #include #include #include #include #include #if __GNUC__ > 2 #include using __gnu_cxx::hash_map; #else #include #endif namespace Security { // // A HandledObject is a trivial mixin class whose only feature is that // it has a *handle*, in the form of (currently) a CSSM_HANDLE of some kind. // Subclasses need to assign such a handle during creation. // class HandledObject { public: typedef CSSM_HANDLE Handle; static const Handle invalidHandle = 0; Handle handle() const { return mMyHandle; } bool validHandle() const { return mValid; } protected: HandledObject(Handle h) : mMyHandle(h), mValid(true) { } HandledObject() { /*IFDEBUG(*/ mMyHandle = invalidHandle/*)*/ ; mValid = false; } 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? }; // // Mapping CSSM_HANDLE values to object pointers and back. // A HandleObject is a HandledObject (see above) that 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 HandleObject in // existence within one address space. We promise that if you hand that handle // to the various findHandle<>() variants, we will give you back the HandleObject // that created it. This is the entire contract. // We *will* make some efforts to diagnose invalid handles and throw exceptions on // them, but the find() operation is supposed to be *fast*, so no heroic measures // will be taken. // class HandleObject : public HandledObject { NOCOPY(HandleObject) class State; public: HandleObject() { state().make(this); } virtual ~HandleObject(); public: template static Subtype &find(CSSM_HANDLE handle, CSSM_RETURN error); template static Subtype &findAndLock(CSSM_HANDLE handle, CSSM_RETURN error); template static Subtype &findAndKill(CSSM_HANDLE handle, CSSM_RETURN error); template static RefPointer findRef(CSSM_HANDLE handle, CSSM_RETURN error); template static RefPointer findRefAndLock(CSSM_HANDLE handle, CSSM_RETURN error); template static RefPointer findRefAndKill(CSSM_HANDLE handle, CSSM_RETURN error); protected: virtual void lock(); virtual bool tryLock(); private: typedef hash_map HandleMap; class State : public Mutex { public: State(); void make(HandleObject *obj); HandleObject *find(Handle h, CSSM_RETURN error); HandleMap::iterator locate(Handle h, CSSM_RETURN error); void erase(HandleObject *obj); void erase(HandleMap::iterator &it); private: HandleMap handleMap; uint32 sequence; }; static ModuleNexus state; }; // // Type-specific ways to access the HandleObject map in various ways // template inline Subclass &HandleObject::find(CSSM_HANDLE handle, CSSM_RETURN error) { Subclass *sub; if (!(sub = dynamic_cast(state().find(handle, error)))) CssmError::throwMe(error); return *sub; } template inline Subclass &HandleObject::findAndLock(CSSM_HANDLE handle, CSSM_RETURN error) { for (;;) { 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 inline Subclass &HandleObject::findAndKill(CSSM_HANDLE handle, CSSM_RETURN error) { for (;;) { 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 inline RefPointer HandleObject::findRef(CSSM_HANDLE handle, CSSM_RETURN error) { 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 inline RefPointer HandleObject::findRefAndLock(CSSM_HANDLE handle, CSSM_RETURN error) { for (;;) { 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 inline RefPointer HandleObject::findRefAndKill(CSSM_HANDLE handle, CSSM_RETURN error) { for (;;) { 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 } } // // Compatibility with old (global function) accessors // template inline Subclass &findHandle(CSSM_HANDLE handle, CSSM_RETURN error = CSSMERR_CSSM_INVALID_ADDIN_HANDLE) { return HandleObject::find(handle, error); } template inline Subclass &findHandleAndLock(CSSM_HANDLE handle, CSSM_RETURN error = CSSMERR_CSSM_INVALID_ADDIN_HANDLE) { return HandleObject::findAndLock(handle, error); } template inline Subclass &killHandle(CSSM_HANDLE handle, CSSM_RETURN error = CSSMERR_CSSM_INVALID_ADDIN_HANDLE) { return HandleObject::findAndKill(handle, error); } } // end namespace Security #endif //_H_HANDLEOBJECT