2 * Copyright (c) 2000-2001,2003-2004,2006,2011-2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // Encapsulate the callback mechanism of CSSM.
28 #include <security_cdsa_utilities/callback.h>
34 void ModuleCallback::operator () (CSSM_MODULE_EVENT event
,
35 const Guid
&guid
, uint32 subId
,
36 CSSM_SERVICE_TYPE serviceType
) const
41 if (CSSM_RETURN err
= mCallback(&guid
, mContext
, subId
, serviceType
, event
))
42 CssmError::throwMe(err
);
51 // Manage Callback sets.
52 // THREADS: Caller is ensuring single-thread access on these calls.
54 void ModuleCallbackSet::insert(const ModuleCallback
&newCallback
)
56 callbacks
.insert(CallbackMap::value_type(newCallback
, new CountingMutex
));
59 void ModuleCallbackSet::erase(const ModuleCallback
&oldCallback
)
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
;
66 StLock
<Mutex
> _(*counter
);
67 if (!counter
->isIdle()) // callbacks are scheduled against this
68 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_FAILED
); // @#module is busy
70 // counter is zero (idle), and we hold the entry lock (via our caller)
77 // Invoke an entire callback set.
78 // THREADS: Caller is ensuring single-thread access on these calls.
80 void ModuleCallbackSet::operator () (CSSM_MODULE_EVENT event
,
81 const Guid
&guid
, uint32 subId
,
82 CSSM_SERVICE_TYPE serviceType
) const
84 if (callbacks
.empty()) // nothing to do; quick exit
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
);
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
++)
101 // get out of this thread - now!
102 (new Runner(callbacks
, event
, guid
, subId
, serviceType
))->run();
106 void ModuleCallbackSet::Runner::action()
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.
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
);