X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cdsa_utilities/lib/callback.cpp?ds=inline diff --git a/Security/libsecurity_cdsa_utilities/lib/callback.cpp b/Security/libsecurity_cdsa_utilities/lib/callback.cpp new file mode 100644 index 00000000..72a16361 --- /dev/null +++ b/Security/libsecurity_cdsa_utilities/lib/callback.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2000-2001,2003-2004,2006,2011-2012,2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// Encapsulate the callback mechanism of CSSM. +// +#include + + +// +// Invoke a callback +// +void ModuleCallback::operator () (CSSM_MODULE_EVENT event, + const Guid &guid, uint32 subId, + CSSM_SERVICE_TYPE serviceType) const +{ + try + { + if (mCallback) + if (CSSM_RETURN err = mCallback(&guid, mContext, subId, serviceType, event)) + CssmError::throwMe(err); + } + catch (...) + { + } +} + + +// +// Manage Callback sets. +// THREADS: Caller is ensuring single-thread access on these calls. +// +void ModuleCallbackSet::insert(const ModuleCallback &newCallback) +{ + callbacks.insert(CallbackMap::value_type(newCallback, new CountingMutex)); +} + +void ModuleCallbackSet::erase(const ModuleCallback &oldCallback) +{ + CallbackMap::iterator it = callbacks.find(oldCallback); + if (it == callbacks.end()) // not registered; fail + CssmError::throwMe(CSSMERR_CSSM_INVALID_ADDIN_HANDLE); + CountingMutex *counter = it->second; + { + StLock _(*counter); + if (!counter->isIdle()) // callbacks are scheduled against this + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_FAILED); // @#module is busy + } + // counter is zero (idle), and we hold the entry lock (via our caller) + delete counter; + callbacks.erase(it); +} + + +// +// Invoke an entire callback set. +// THREADS: Caller is ensuring single-thread access on these calls. +// +void ModuleCallbackSet::operator () (CSSM_MODULE_EVENT event, + const Guid &guid, uint32 subId, + CSSM_SERVICE_TYPE serviceType) const +{ + if (callbacks.empty()) // nothing to do; quick exit + return; + +#if _USE_THREADS == _USE_NO_THREADS || defined(SYNCHRONOUS_CALLBACKS) + // no threading model supported - we HAVE to do this right here + // note that the user better not re-enter CSSM too much, + // or we might deadlock... + for (CallbackMap::const_iterator it = callbacks.begin(); + it != callbacks.end(); it++) { + it->first(event, guid, subId, serviceType); + } +#else // real threads available + // lock down all callback elements - still protected by global lock (via caller) + for (CallbackMap::iterator it = callbacks.begin(); + it != callbacks.end(); it++) + it->second->enter(); + + // get out of this thread - now! + (new Runner(callbacks, event, guid, subId, serviceType))->run(); +#endif +} + +void ModuleCallbackSet::Runner::action() +{ + // + // NOTE WELL: Our callbacks map shares (pointed-to) values with the ModuleCallbackSet + // we were created from. Some of these values may be dangling pointers since they have + // been destroyed by other threads, but only *after* we are done with them, since + // we must call exit() on them before they become eligible for destruction. + // In all cases, it is the responsibility of other threads to destroy those mutexi. + // + // @@@ Could also fan out to multiple callback threads in parallel. + for (CallbackMap::iterator it = callbacks.begin(); + it != callbacks.end(); it++) { + //@@@ safety vs. convenience - recheck + it->first(event, guid, subserviceId, serviceType); + it->second->exit(); + } +}