1/* 2 * Copyright (c) 2000-2001,2003-2004,2006,2011-2012,2014 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// Encapsulate the callback mechanism of CSSM. 27// 28#include <security_cdsa_utilities/callback.h> 29 30 31// 32// Invoke a callback 33// 34void 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// 54void ModuleCallbackSet::insert(const ModuleCallback &newCallback) 55{ 56 callbacks.insert(CallbackMap::value_type(newCallback, new CountingMutex)); 57} 58 59void 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// 80void 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 106void 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} 123