1/* 2 * Copyright (c) 2008,2011-2012 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// Templates to support HandleObject-like objects 27// 28#ifndef _H_HANDLETEMPLATES 29#define _H_HANDLETEMPLATES 30 31#include <security_utilities/refcount.h> 32#include <security_utilities/threading.h> 33#include <security_utilities/globalizer.h> 34#include <security_cdsa_utilities/cssmerrors.h> 35#include <vector> 36 37#if __GNUC__ > 2 38#include <ext/hash_map> 39using __gnu_cxx::hash_map; 40#else 41#include <hash_map> 42#endif 43 44namespace Security 45{ 46 47// 48// A TypedHandle is a trivial mixin class whose only feature is that 49// it has a *handle* whose type is of the caller's choosing. Subclasses 50// need to assign such a handle during creation. 51// 52template <class _Handle> 53struct TypedHandle 54{ 55public: 56 typedef _Handle Handle; 57 58 static const _Handle invalidHandle = 0; 59 60 _Handle handle() const { return mMyHandle; } 61 bool validHandle() const { return mValid; } 62 63protected: 64 TypedHandle(_Handle h); 65 TypedHandle(); 66 67 void setHandle(_Handle h) 68 { 69 assert(!mValid); // guard against redefinition 70 mMyHandle = h; 71 mValid = true; 72 } 73 void clearHandle() 74 { 75 assert(mValid); 76 mValid = false; 77 } 78 79private: 80 _Handle mMyHandle; // our handle value 81 bool mValid; // is the handle (still) valid? 82}; 83 84// 85// MappingHandle wraps a map indexed by handles of the chosen type. 86// A MappingHandle makes up its own handle based on some mechanism that you 87// know nothing about. 88// 89// Please be very careful about the limits of the object contract here. 90// We promise to invent a suitable, unique handle for each MappingHandle in 91// existence within one address space. We promise that if you hand that 92// handle to the various MappingHandle<>::find() variants, we will give you 93// back the MappingHandle that created it. We promise to throw if you pass 94// a bad handle to those MappingHandle<>::find() variants. This is the 95// entire contract. 96// 97template <class _Handle> 98class MappingHandle : public TypedHandle<_Handle> 99{ 100protected: 101 class State; 102 103public: 104 typedef typename TypedHandle<_Handle>::Handle Handle; 105 virtual ~MappingHandle() 106 { 107 State &st = state(); 108 StLock<Mutex> _(st); 109 st.erase(this); 110 } 111 112 template <class SubType> 113 static SubType &find(_Handle handle, CSSM_RETURN error); 114 115 template <class Subtype> 116 static Subtype &findAndLock(_Handle handle, CSSM_RETURN error); 117 118 template <class Subtype> 119 static Subtype &findAndKill(_Handle handle, CSSM_RETURN error); 120 121 template <class Subtype> 122 static RefPointer<Subtype> findRef(_Handle handle, CSSM_RETURN error); 123 124 template <class Subtype> 125 static RefPointer<Subtype> findRefAndLock(_Handle handle, CSSM_RETURN error); 126 127 template <class Subtype> 128 static RefPointer<Subtype> findRefAndKill(_Handle handle, CSSM_RETURN error); 129 130 // @@@ Remove when 4003540 is fixed 131 template <class Subtype> 132 static void findAllRefs(std::vector<_Handle> &refs) { 133 state().template findAllRefs<Subtype>(refs); 134 } 135 136protected: 137 virtual void lock(); 138 virtual bool tryLock(); 139 140 typedef hash_map<_Handle, MappingHandle<_Handle> *> HandleMap; 141 142 MappingHandle(); 143 144 class State : public Mutex, public HandleMap 145 { 146 public: 147 State(); 148 uint32_t nextSeq() { return ++sequence; } 149 150 bool handleInUse(_Handle h); 151 MappingHandle<_Handle> *find(_Handle h, CSSM_RETURN error); 152 typename HandleMap::iterator locate(_Handle h, CSSM_RETURN error); 153 void add(_Handle h, MappingHandle<_Handle> *obj); 154 void erase(MappingHandle<_Handle> *obj); 155 void erase(typename HandleMap::iterator &it); 156 // @@@ Remove when 4003540 is fixed 157 template <class SubType> void findAllRefs(std::vector<_Handle> &refs); 158 159 private: 160 uint32_t sequence; 161 }; 162 163private: 164 // 165 // Create the handle to be used by the map 166 // 167 void make(); 168 169 static ModuleNexus<typename MappingHandle<_Handle>::State> state; 170}; 171 172// 173// MappingHandle class methods 174// Type-specific ways to access the map in various ways 175// 176template <class _Handle> 177template <class Subclass> 178inline Subclass &MappingHandle<_Handle>::find(_Handle handle, CSSM_RETURN error) 179{ 180 Subclass *sub; 181 if (!(sub = dynamic_cast<Subclass *>(state().find(handle, error)))) 182 CssmError::throwMe(error); 183 return *sub; 184} 185 186template <class _Handle> 187template <class Subclass> 188inline Subclass &MappingHandle<_Handle>::findAndLock(_Handle handle, 189 CSSM_RETURN error) 190{ 191 for (;;) { 192 typename HandleMap::iterator it = state().locate(handle, error); 193 StLock<Mutex> _(state(), true); // locate() locked it 194 Subclass *sub; 195 if (!(sub = dynamic_cast<Subclass *>(it->second))) 196 CssmError::throwMe(error); // bad type 197 if (it->second->tryLock()) // try to lock it 198 return *sub; // okay, go 199 Thread::yield(); // object lock failed, backoff and retry 200 } 201} 202 203template <class _Handle> 204template <class Subclass> 205inline Subclass &MappingHandle<_Handle>::findAndKill(_Handle handle, 206 CSSM_RETURN error) 207{ 208 for (;;) { 209 typename HandleMap::iterator it = state().locate(handle, error); 210 StLock<Mutex> _(state(), true); // locate() locked it 211 Subclass *sub; 212 if (!(sub = dynamic_cast<Subclass *>(it->second))) 213 CssmError::throwMe(error); // bad type 214 if (it->second->tryLock()) { // try to lock it 215 state().erase(it); // kill the handle 216 return *sub; // okay, go 217 } 218 Thread::yield(); // object lock failed, backoff and retry 219 } 220} 221 222template <class _Handle> 223template <class Subclass> 224inline RefPointer<Subclass> MappingHandle<_Handle>::findRef(_Handle handle, 225 CSSM_RETURN error) 226{ 227 typename HandleMap::iterator it = state().locate(handle, error); 228 StLock<Mutex> _(state(), true); // locate() locked it 229 Subclass *sub; 230 if (!(sub = dynamic_cast<Subclass *>(it->second))) 231 CssmError::throwMe(error); 232 return sub; 233} 234 235template <class _Handle> 236template <class Subclass> 237inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndLock(_Handle handle, 238 CSSM_RETURN error) 239{ 240 for (;;) { 241 typename HandleMap::iterator it = state().locate(handle, error); 242 StLock<Mutex> _(state(), true); // locate() locked it 243 Subclass *sub; 244 if (!(sub = dynamic_cast<Subclass *>(it->second))) 245 CssmError::throwMe(error); // bad type 246 if (it->second->tryLock()) // try to lock it 247 return sub; // okay, go 248 Thread::yield(); // object lock failed, backoff and retry 249 } 250} 251 252template <class _Handle> 253template <class Subclass> 254inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndKill(_Handle handle, 255 CSSM_RETURN error) 256{ 257 for (;;) { 258 typename HandleMap::iterator it = state().locate(handle, error); 259 StLock<Mutex> _(state(), true); // locate() locked it 260 Subclass *sub; 261 if (!(sub = dynamic_cast<Subclass *>(it->second))) 262 CssmError::throwMe(error); // bad type 263 if (it->second->tryLock()) { // try to lock it 264 state().erase(it); // kill the handle 265 return sub; // okay, go 266 } 267 Thread::yield(); // object lock failed, backoff and retry 268 } 269} 270 271// 272// @@@ Remove when 4003540 is fixed 273// 274// This is a hack to fix 3981388 and should NOT be used elsewhere. 275// Also, do not follow this code's example: State methods should not 276// implement type-specific behavior. 277// 278template <class _Handle> 279template <class Subtype> 280void MappingHandle<_Handle>::State::findAllRefs(std::vector<_Handle> &refs) 281{ 282 StLock<Mutex> _(*this); 283 typename HandleMap::iterator it = (*this).begin(); 284 for (; it != (*this).end(); ++it) 285 { 286 Subtype *obj = dynamic_cast<Subtype *>(it->second); 287 if (obj) 288 refs.push_back(it->first); 289 } 290} 291 292 293} // end namespace Security 294 295#endif //_H_HANDLETEMPLATES 296