]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2001,2003-2004,2006,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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 | // Encapsulate the callback mechanism of CSSM. | |
27 | // | |
28 | #include <security_cdsa_utilities/callback.h> | |
29 | ||
30 | ||
31 | // | |
32 | // Invoke a callback | |
33 | // | |
34 | void ModuleCallback::operator () (CSSM_MODULE_EVENT event, | |
35 | const Guid &guid, uint32 subId, | |
36 | CSSM_SERVICE_TYPE serviceType) const | |
37 | { | |
38 | try | |
39 | { | |
40 | if (mCallback) | |
41 | if (CSSM_RETURN err = mCallback(&guid, mContext, subId, serviceType, event)) | |
42 | CssmError::throwMe(err); | |
43 | } | |
44 | catch (...) | |
45 | { | |
46 | } | |
47 | } | |
48 | ||
49 | ||
50 | // | |
51 | // Manage Callback sets. | |
52 | // THREADS: Caller is ensuring single-thread access on these calls. | |
53 | // | |
54 | void ModuleCallbackSet::insert(const ModuleCallback &newCallback) | |
55 | { | |
56 | callbacks.insert(CallbackMap::value_type(newCallback, new CountingMutex)); | |
57 | } | |
58 | ||
59 | void ModuleCallbackSet::erase(const ModuleCallback &oldCallback) | |
60 | { | |
61 | CallbackMap::iterator it = callbacks.find(oldCallback); | |
62 | if (it == callbacks.end()) // not registered; fail | |
63 | CssmError::throwMe(CSSMERR_CSSM_INVALID_ADDIN_HANDLE); | |
64 | CountingMutex *counter = it->second; | |
65 | { | |
66 | StLock<Mutex> _(*counter); | |
67 | if (!counter->isIdle()) // callbacks are scheduled against this | |
68 | CssmError::throwMe(CSSM_ERRCODE_FUNCTION_FAILED); // @#module is busy | |
69 | } | |
70 | // counter is zero (idle), and we hold the entry lock (via our caller) | |
71 | delete counter; | |
72 | callbacks.erase(it); | |
73 | } | |
74 | ||
75 | ||
76 | // | |
77 | // Invoke an entire callback set. | |
78 | // THREADS: Caller is ensuring single-thread access on these calls. | |
79 | // | |
80 | void ModuleCallbackSet::operator () (CSSM_MODULE_EVENT event, | |
81 | const Guid &guid, uint32 subId, | |
82 | CSSM_SERVICE_TYPE serviceType) const | |
83 | { | |
84 | if (callbacks.empty()) // nothing to do; quick exit | |
85 | return; | |
86 | ||
87 | #if _USE_THREADS == _USE_NO_THREADS || defined(SYNCHRONOUS_CALLBACKS) | |
88 | // no threading model supported - we HAVE to do this right here | |
89 | // note that the user better not re-enter CSSM too much, | |
90 | // or we might deadlock... | |
91 | for (CallbackMap::const_iterator it = callbacks.begin(); | |
92 | it != callbacks.end(); it++) { | |
93 | it->first(event, guid, subId, serviceType); | |
94 | } | |
95 | #else // real threads available | |
96 | // lock down all callback elements - still protected by global lock (via caller) | |
97 | for (CallbackMap::iterator it = callbacks.begin(); | |
98 | it != callbacks.end(); it++) | |
99 | it->second->enter(); | |
100 | ||
101 | // get out of this thread - now! | |
102 | (new Runner(callbacks, event, guid, subId, serviceType))->run(); | |
103 | #endif | |
104 | } | |
105 | ||
106 | void ModuleCallbackSet::Runner::action() | |
107 | { | |
108 | // | |
109 | // NOTE WELL: Our callbacks map shares (pointed-to) values with the ModuleCallbackSet | |
110 | // we were created from. Some of these values may be dangling pointers since they have | |
111 | // been destroyed by other threads, but only *after* we are done with them, since | |
112 | // we must call exit() on them before they become eligible for destruction. | |
113 | // In all cases, it is the responsibility of other threads to destroy those mutexi. | |
114 | // | |
115 | // @@@ Could also fan out to multiple callback threads in parallel. | |
116 | for (CallbackMap::iterator it = callbacks.begin(); | |
117 | it != callbacks.end(); it++) { | |
118 | //@@@ safety vs. convenience - recheck | |
119 | it->first(event, guid, subserviceId, serviceType); | |
120 | it->second->exit(); | |
121 | } | |
122 | } |