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
);