]> git.saurik.com Git - apple/security.git/blob - libsecurity_cdsa_utilities/lib/handletemplates.h
Security-55178.0.1.tar.gz
[apple/security.git] / libsecurity_cdsa_utilities / lib / handletemplates.h
1 /*
2 * Copyright (c) 2008 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
36 #if __GNUC__ > 2
37 #include <ext/hash_map>
38 using __gnu_cxx::hash_map;
39 #else
40 #include <hash_map>
41 #endif
42
43 namespace Security
44 {
45
46 //
47 // A TypedHandle is a trivial mixin class whose only feature is that
48 // it has a *handle* whose type is of the caller's choosing. Subclasses
49 // need to assign such a handle during creation.
50 //
51 template <class _Handle>
52 struct TypedHandle
53 {
54 public:
55 typedef _Handle Handle;
56
57 static const _Handle invalidHandle = 0;
58
59 _Handle handle() const { return mMyHandle; }
60 bool validHandle() const { return mValid; }
61
62 protected:
63 TypedHandle(_Handle h);
64 TypedHandle();
65
66 void setHandle(_Handle h)
67 {
68 assert(!mValid); // guard against redefinition
69 mMyHandle = h;
70 mValid = true;
71 }
72 void clearHandle()
73 {
74 assert(mValid);
75 mValid = false;
76 }
77
78 private:
79 _Handle mMyHandle; // our handle value
80 bool mValid; // is the handle (still) valid?
81 };
82
83 //
84 // MappingHandle wraps a map indexed by handles of the chosen type.
85 // A MappingHandle makes up its own handle based on some mechanism that you
86 // know nothing about.
87 //
88 // Please be very careful about the limits of the object contract here.
89 // We promise to invent a suitable, unique handle for each MappingHandle in
90 // existence within one address space. We promise that if you hand that
91 // handle to the various MappingHandle<>::find() variants, we will give you
92 // back the MappingHandle that created it. We promise to throw if you pass
93 // a bad handle to those MappingHandle<>::find() variants. This is the
94 // entire contract.
95 //
96 template <class _Handle>
97 class MappingHandle : public TypedHandle<_Handle>
98 {
99 protected:
100 class State;
101
102 public:
103 typedef typename TypedHandle<_Handle>::Handle Handle;
104 virtual ~MappingHandle()
105 {
106 State &st = state();
107 StLock<Mutex> _(st);
108 st.erase(this);
109 }
110
111 template <class SubType>
112 static SubType &find(_Handle handle, CSSM_RETURN error);
113
114 template <class Subtype>
115 static Subtype &findAndLock(_Handle handle, CSSM_RETURN error);
116
117 template <class Subtype>
118 static Subtype &findAndKill(_Handle handle, CSSM_RETURN error);
119
120 template <class Subtype>
121 static RefPointer<Subtype> findRef(_Handle handle, CSSM_RETURN error);
122
123 template <class Subtype>
124 static RefPointer<Subtype> findRefAndLock(_Handle handle, CSSM_RETURN error);
125
126 template <class Subtype>
127 static RefPointer<Subtype> findRefAndKill(_Handle handle, CSSM_RETURN error);
128
129 // @@@ Remove when 4003540 is fixed
130 template <class Subtype>
131 static void findAllRefs(std::vector<_Handle> &refs) {
132 state().findAllRefs<Subtype>(refs);
133 }
134
135 protected:
136 virtual void lock();
137 virtual bool tryLock();
138
139 typedef hash_map<_Handle, MappingHandle<_Handle> *> HandleMap;
140
141 MappingHandle();
142
143 class State : public Mutex, public HandleMap
144 {
145 public:
146 State();
147 uint32_t nextSeq() { return ++sequence; }
148
149 bool handleInUse(_Handle h);
150 MappingHandle<_Handle> *find(_Handle h, CSSM_RETURN error);
151 typename HandleMap::iterator locate(_Handle h, CSSM_RETURN error);
152 void add(_Handle h, MappingHandle<_Handle> *obj);
153 void erase(MappingHandle<_Handle> *obj);
154 void erase(typename HandleMap::iterator &it);
155 // @@@ Remove when 4003540 is fixed
156 template <class SubType> void findAllRefs(std::vector<_Handle> &refs);
157
158 private:
159 uint32_t sequence;
160 };
161
162 private:
163 //
164 // Create the handle to be used by the map
165 //
166 void make();
167
168 static ModuleNexus<typename MappingHandle<_Handle>::State> state;
169 };
170
171 //
172 // MappingHandle class methods
173 // Type-specific ways to access the map in various ways
174 //
175 template <class _Handle>
176 template <class Subclass>
177 inline Subclass &MappingHandle<_Handle>::find(_Handle handle, CSSM_RETURN error)
178 {
179 Subclass *sub;
180 if (!(sub = dynamic_cast<Subclass *>(state().find(handle, error))))
181 CssmError::throwMe(error);
182 return *sub;
183 }
184
185 template <class _Handle>
186 template <class Subclass>
187 inline Subclass &MappingHandle<_Handle>::findAndLock(_Handle handle,
188 CSSM_RETURN error)
189 {
190 for (;;) {
191 typename HandleMap::iterator it = state().locate(handle, error);
192 StLock<Mutex> _(state(), true); // locate() locked it
193 Subclass *sub;
194 if (!(sub = dynamic_cast<Subclass *>(it->second)))
195 CssmError::throwMe(error); // bad type
196 if (it->second->tryLock()) // try to lock it
197 return *sub; // okay, go
198 Thread::yield(); // object lock failed, backoff and retry
199 }
200 }
201
202 template <class _Handle>
203 template <class Subclass>
204 inline Subclass &MappingHandle<_Handle>::findAndKill(_Handle handle,
205 CSSM_RETURN error)
206 {
207 for (;;) {
208 typename HandleMap::iterator it = state().locate(handle, error);
209 StLock<Mutex> _(state(), true); // locate() locked it
210 Subclass *sub;
211 if (!(sub = dynamic_cast<Subclass *>(it->second)))
212 CssmError::throwMe(error); // bad type
213 if (it->second->tryLock()) { // try to lock it
214 state().erase(it); // kill the handle
215 return *sub; // okay, go
216 }
217 Thread::yield(); // object lock failed, backoff and retry
218 }
219 }
220
221 template <class _Handle>
222 template <class Subclass>
223 inline RefPointer<Subclass> MappingHandle<_Handle>::findRef(_Handle handle,
224 CSSM_RETURN error)
225 {
226 typename HandleMap::iterator it = state().locate(handle, error);
227 StLock<Mutex> _(state(), true); // locate() locked it
228 Subclass *sub;
229 if (!(sub = dynamic_cast<Subclass *>(it->second)))
230 CssmError::throwMe(error);
231 return sub;
232 }
233
234 template <class _Handle>
235 template <class Subclass>
236 inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndLock(_Handle handle,
237 CSSM_RETURN error)
238 {
239 for (;;) {
240 typename HandleMap::iterator it = state().locate(handle, error);
241 StLock<Mutex> _(state(), true); // locate() locked it
242 Subclass *sub;
243 if (!(sub = dynamic_cast<Subclass *>(it->second)))
244 CssmError::throwMe(error); // bad type
245 if (it->second->tryLock()) // try to lock it
246 return sub; // okay, go
247 Thread::yield(); // object lock failed, backoff and retry
248 }
249 }
250
251 template <class _Handle>
252 template <class Subclass>
253 inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndKill(_Handle handle,
254 CSSM_RETURN error)
255 {
256 for (;;) {
257 typename HandleMap::iterator it = state().locate(handle, error);
258 StLock<Mutex> _(state(), true); // locate() locked it
259 Subclass *sub;
260 if (!(sub = dynamic_cast<Subclass *>(it->second)))
261 CssmError::throwMe(error); // bad type
262 if (it->second->tryLock()) { // try to lock it
263 state().erase(it); // kill the handle
264 return sub; // okay, go
265 }
266 Thread::yield(); // object lock failed, backoff and retry
267 }
268 }
269
270 //
271 // @@@ Remove when 4003540 is fixed
272 //
273 // This is a hack to fix 3981388 and should NOT be used elsewhere.
274 // Also, do not follow this code's example: State methods should not
275 // implement type-specific behavior.
276 //
277 template <class _Handle>
278 template <class Subtype>
279 void MappingHandle<_Handle>::State::findAllRefs(std::vector<_Handle> &refs)
280 {
281 StLock<Mutex> _(*this);
282 typename HandleMap::iterator it = (*this).begin();
283 for (; it != (*this).end(); ++it)
284 {
285 Subtype *obj = dynamic_cast<Subtype *>(it->second);
286 if (obj)
287 refs.push_back(it->first);
288 }
289 }
290
291
292 } // end namespace Security
293
294 #endif //_H_HANDLETEMPLATES