X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_utilities/lib/globalizer.h?ds=sidebyside diff --git a/Security/libsecurity_utilities/lib/globalizer.h b/Security/libsecurity_utilities/lib/globalizer.h new file mode 100644 index 00000000..66480469 --- /dev/null +++ b/Security/libsecurity_utilities/lib/globalizer.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2000-2004,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@ + */ + + +/* + * globalizer - multiscope globalization services + */ +#ifndef _H_GLOBALIZER +#define _H_GLOBALIZER + +#include +#include +#include +#include +#include + +namespace Security { + + +// +// GlobalNexus is the common superclass of all globality scopes. +// A Nexus is an *access point* to the *single* object of a given +// type in the Nexus's particular scope. +// +class GlobalNexus { +public: + class Error : public std::exception { + public: + virtual ~Error() throw(); + const char * const message; + Error(const char *m) : message(m) { } + const char *what() const throw() { return message; } + }; +}; + + +class ModuleNexusCommon : public GlobalNexus { +private: + void do_create(void *(*make)()); + +protected: + void *create(void *(*make)()); + void lock() {OSSpinLockLock(&access);} + void unlock() {OSSpinLockUnlock(&access);} + +protected: + // all of these will be statically initialized to zero + void *pointer; + dispatch_once_t once; + OSSpinLock access; +}; + +template +class ModuleNexus : public ModuleNexusCommon { +public: + Type &operator () () + { + lock(); + + try + { + if (pointer == NULL) + { + pointer = create(make); + } + + unlock(); + } + catch (...) + { + unlock(); + throw; + } + + return *reinterpret_cast(pointer); + } + + // does the object DEFINITELY exist already? + bool exists() const + { + bool result; + lock(); + result = pointer != NULL; + unlock(); + return result; + } + + // destroy the object (if any) and start over - not really thread-safe + void reset() + { + lock(); + if (pointer != NULL) + { + delete reinterpret_cast(pointer); + pointer = NULL; + once = 0; + } + unlock(); + } + +private: + static void *make() { return new Type; } +}; + +template +class CleanModuleNexus : public ModuleNexus { +public: + ~CleanModuleNexus() + { + secdebug("nexus", "ModuleNexus %p destroyed object 0x%x", + this, ModuleNexus::pointer); + delete reinterpret_cast(ModuleNexus::pointer); + } +}; + +typedef std::set RetentionSet; + +// +// A thread-scope nexus is tied to a particular native thread AND +// a particular nexus object. Its scope is all code in any one thread +// that access that particular Nexus object. Any number of Nexus objects +// can exist, and each implements a different scope for each thread. +// NOTE: ThreadNexus is dynamically constructed. If you want static, +// zero-initialization ThreadNexi, put them inside a ModuleNexus. +// +template +class ThreadNexus : public GlobalNexus { +public: + ThreadNexus() : mSlot(true) { } + + Type &operator () () + { + // no thread contention here! + if (Type *p = mSlot) + return *p; + mSlot = new Type; + return *mSlot; + } + +private: + PerThreadPointer mSlot; +}; + + +// +// A ProcessNexus is global within a single process, regardless of +// load module boundaries. You can have any number of ProcessNexus +// scopes, each identified by a C string (compared by value, not pointer). +// +class ProcessNexusBase : public GlobalNexus { +protected: + ProcessNexusBase(const char *identifier); + + struct Store { + void *mObject; + Mutex mLock; + }; + Store *mStore; +}; + +template +class ProcessNexus : public ProcessNexusBase { +public: + ProcessNexus(const char *identifier) : ProcessNexusBase(identifier) { } + Type &operator () (); + +private: + Type *mObject; +}; + +template +Type &ProcessNexus::operator () () +{ +#if !defined(PTHREAD_STRICT) + // not strictly kosher POSIX, but pointers are usually atomic types + if (mStore->mObject) + return *reinterpret_cast(mStore->mObject); +#endif + StLock _(mStore->mLock); + if (mStore->mObject == NULL) + mStore->mObject = new Type; + return *reinterpret_cast(mStore->mObject); +}; + + +} // end namespace Security + +#endif //_H_GLOBALIZER