]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_cdsa_utilities/lib/handletemplates.h
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_cdsa_utilities / lib / handletemplates.h
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>
39 using __gnu_cxx::hash_map;
40 #else
41 #include <hash_map>
42 #endif
43
44 namespace 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 //
52 template <class _Handle>
53 struct TypedHandle
54 {
55 public:
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
63 protected:
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
79 private:
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 //
97 template <class _Handle>
98 class MappingHandle : public TypedHandle<_Handle>
99 {
100 protected:
101 class State;
102
103 public:
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
136 protected:
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
163 private:
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 //
176 template <class _Handle>
177 template <class Subclass>
178 inline 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
186 template <class _Handle>
187 template <class Subclass>
188 inline 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
203 template <class _Handle>
204 template <class Subclass>
205 inline 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
222 template <class _Handle>
223 template <class Subclass>
224 inline 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
235 template <class _Handle>
236 template <class Subclass>
237 inline 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
252 template <class _Handle>
253 template <class Subclass>
254 inline 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 //
278 template <class _Handle>
279 template <class Subtype>
280 void 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