]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/callback.cpp
Security-54.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / callback.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // Encapsulate the callback mechanism of CSSM.
21 //
22 #ifdef __MWERKS__
23 #define _CPP_CALLBACK
24 #endif
25 #include <Security/callback.h>
26
27
28 //
29 // Invoke a callback
30 //
31 void ModuleCallback::operator () (CSSM_MODULE_EVENT event,
32 const Guid &guid, uint32 subId,
33 CSSM_SERVICE_TYPE serviceType) const
34 {
35 if (mCallback)
36 if (CSSM_RETURN err = mCallback(&guid, mContext, subId, serviceType, event))
37 CssmError::throwMe(err);
38 }
39
40
41 //
42 // Manage Callback sets.
43 // THREADS: Caller is ensuring single-thread access on these calls.
44 //
45 void ModuleCallbackSet::insert(const ModuleCallback &newCallback)
46 {
47 callbacks.insert(CallbackMap::value_type(newCallback, new CountingMutex));
48 }
49
50 void ModuleCallbackSet::erase(const ModuleCallback &oldCallback)
51 {
52 CallbackMap::iterator it = callbacks.find(oldCallback);
53 if (it == callbacks.end()) // not registered; fail
54 CssmError::throwMe(CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
55 CountingMutex *counter = it->second;
56 {
57 StLock<Mutex> _(*counter);
58 if (!counter->isIdle()) // callbacks are scheduled against this
59 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_FAILED); // @#module is busy
60 }
61 // counter is zero (idle), and we hold the entry lock (via our caller)
62 delete counter;
63 callbacks.erase(it);
64 }
65
66
67 //
68 // Invoke an entire callback set.
69 // THREADS: Caller is ensuring single-thread access on these calls.
70 //
71 void ModuleCallbackSet::operator () (CSSM_MODULE_EVENT event,
72 const Guid &guid, uint32 subId,
73 CSSM_SERVICE_TYPE serviceType) const
74 {
75 if (callbacks.empty()) // nothing to do; quick exit
76 return;
77
78 #if _USE_THREADS == _USE_NO_THREADS || defined(SYNCHRONOUS_CALLBACKS)
79 // no threading model supported - we HAVE to do this right here
80 // note that the user better not re-enter CSSM too much,
81 // or we might deadlock...
82 for (CallbackMap::const_iterator it = callbacks.begin();
83 it != callbacks.end(); it++) {
84 it->first(event, guid, subId, serviceType);
85 }
86 #else // real threads available
87 // lock down all callback elements - still protected by global lock (via caller)
88 for (CallbackMap::iterator it = callbacks.begin();
89 it != callbacks.end(); it++)
90 it->second->enter();
91
92 // get out of this thread - now!
93 (new Runner(callbacks, event, guid, subId, serviceType))->run();
94 #endif
95 }
96
97 void ModuleCallbackSet::Runner::action()
98 {
99 //
100 // NOTE WELL: Our callbacks map shares (pointed-to) values with the ModuleCallbackSet
101 // we were created from. Some of these values may be dangling pointers since they have
102 // been destroyed by other threads, but only *after* we are done with them, since
103 // we must call exit() on them before they become eligible for destruction.
104 // In all cases, it is the responsibility of other threads to destroy those mutexi.
105 //
106 // @@@ Could also fan out to multiple callback threads in parallel.
107 for (CallbackMap::iterator it = callbacks.begin();
108 it != callbacks.end(); it++) {
109 //@@@ safety vs. convenience - recheck
110 it->first(event, guid, subserviceId, serviceType);
111 it->second->exit();
112 }
113 }