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