]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_utilities/lib/handletemplates.h
Security-59754.41.1.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 // <rdar://problem/28898053> security_filedb build error: instantiation of variable 'Security::MappingHandle<long>::state' required here, but no definition is available
103 #pragma clang diagnostic push
104 #pragma clang diagnostic ignored "-Wundefined-var-template"
105 State &st = state();
106 #pragma clang diagnostic pop
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().template findAllRefs<Subtype>(refs);
133 }
134
135 protected:
136 virtual void lock();
137 virtual bool tryLock();
138
139 typedef std::unordered_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 // <rdar://problem/28898053> security_filedb build error: instantiation of variable 'Security::MappingHandle<long>::state' required here, but no definition is available
181 #pragma clang diagnostic push
182 #pragma clang diagnostic ignored "-Wundefined-var-template"
183 if (!(sub = dynamic_cast<Subclass *>(state().find(handle, error))))
184 CssmError::throwMe(error);
185 #pragma clang diagnostic pop
186 return *sub;
187 }
188
189 template <class _Handle>
190 template <class Subclass>
191 inline Subclass &MappingHandle<_Handle>::findAndLock(_Handle handle,
192 CSSM_RETURN error)
193 {
194 for (;;) {
195 typename HandleMap::iterator it = state().locate(handle, error);
196 StLock<Mutex> _(state(), true); // locate() locked it
197 Subclass *sub;
198 if (!(sub = dynamic_cast<Subclass *>(it->second)))
199 CssmError::throwMe(error); // bad type
200 if (it->second->tryLock()) // try to lock it
201 return *sub; // okay, go
202 Thread::yield(); // object lock failed, backoff and retry
203 }
204 }
205
206 template <class _Handle>
207 template <class Subclass>
208 inline Subclass &MappingHandle<_Handle>::findAndKill(_Handle handle,
209 CSSM_RETURN error)
210 {
211 for (;;) {
212 // <rdar://problem/28898053> security_filedb build error: instantiation of variable 'Security::MappingHandle<long>::state' required here, but no definition is available
213 #pragma clang diagnostic push
214 #pragma clang diagnostic ignored "-Wundefined-var-template"
215 typename HandleMap::iterator it = state().locate(handle, error);
216 #pragma clang diagnostic pop
217 StLock<Mutex> _(state(), true); // locate() locked it
218 Subclass *sub;
219 if (!(sub = dynamic_cast<Subclass *>(it->second)))
220 CssmError::throwMe(error); // bad type
221 if (it->second->tryLock()) { // try to lock it
222 state().erase(it); // kill the handle
223 return *sub; // okay, go
224 }
225 Thread::yield(); // object lock failed, backoff and retry
226 }
227 }
228
229 template <class _Handle>
230 template <class Subclass>
231 inline RefPointer<Subclass> MappingHandle<_Handle>::findRef(_Handle handle,
232 CSSM_RETURN error)
233 {
234 typename HandleMap::iterator it = state().locate(handle, error);
235 StLock<Mutex> _(state(), true); // locate() locked it
236 Subclass *sub;
237 if (!(sub = dynamic_cast<Subclass *>(it->second)))
238 CssmError::throwMe(error);
239 return sub;
240 }
241
242 template <class _Handle>
243 template <class Subclass>
244 inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndLock(_Handle handle,
245 CSSM_RETURN error)
246 {
247 for (;;) {
248 typename HandleMap::iterator it = state().locate(handle, error);
249 StLock<Mutex> _(state(), true); // locate() locked it
250 Subclass *sub;
251 if (!(sub = dynamic_cast<Subclass *>(it->second)))
252 CssmError::throwMe(error); // bad type
253 if (it->second->tryLock()) // try to lock it
254 return sub; // okay, go
255 Thread::yield(); // object lock failed, backoff and retry
256 }
257 }
258
259 template <class _Handle>
260 template <class Subclass>
261 inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndKill(_Handle handle,
262 CSSM_RETURN error)
263 {
264 for (;;) {
265 typename HandleMap::iterator it = state().locate(handle, error);
266 StLock<Mutex> _(state(), true); // locate() locked it
267 Subclass *sub;
268 if (!(sub = dynamic_cast<Subclass *>(it->second)))
269 CssmError::throwMe(error); // bad type
270 if (it->second->tryLock()) { // try to lock it
271 state().erase(it); // kill the handle
272 return sub; // okay, go
273 }
274 Thread::yield(); // object lock failed, backoff and retry
275 }
276 }
277
278 //
279 // @@@ Remove when 4003540 is fixed
280 //
281 // This is a hack to fix 3981388 and should NOT be used elsewhere.
282 // Also, do not follow this code's example: State methods should not
283 // implement type-specific behavior.
284 //
285 template <class _Handle>
286 template <class Subtype>
287 void MappingHandle<_Handle>::State::findAllRefs(std::vector<_Handle> &refs)
288 {
289 StLock<Mutex> _(*this);
290 typename HandleMap::iterator it = (*this).begin();
291 for (; it != (*this).end(); ++it)
292 {
293 Subtype *obj = dynamic_cast<Subtype *>(it->second);
294 if (obj)
295 refs.push_back(it->first);
296 }
297 }
298
299
300 } // end namespace Security
301
302 #endif //_H_HANDLETEMPLATES