]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_utilities/lib/globalizer.h
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_utilities / lib / globalizer.h
1 /*
2 * Copyright (c) 2000-2004,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 * globalizer - multiscope globalization services
27 */
28 #ifndef _H_GLOBALIZER
29 #define _H_GLOBALIZER
30
31 #include <security_utilities/threading.h>
32 #include <memory>
33 #include <set>
34 #include <dispatch/dispatch.h>
35 #include <libkern/OSAtomic.h>
36
37 namespace Security {
38
39
40 //
41 // GlobalNexus is the common superclass of all globality scopes.
42 // A Nexus is an *access point* to the *single* object of a given
43 // type in the Nexus's particular scope.
44 //
45 class GlobalNexus {
46 public:
47 class Error : public std::exception {
48 public:
49 virtual ~Error() throw();
50 const char * const message;
51 Error(const char *m) : message(m) { }
52 const char *what() const throw() { return message; }
53 };
54 };
55
56
57 class ModuleNexusCommon : public GlobalNexus {
58 private:
59 void do_create(void *(*make)());
60
61 protected:
62 void *create(void *(*make)());
63 void lock() {OSSpinLockLock(&access);}
64 void unlock() {OSSpinLockUnlock(&access);}
65
66 protected:
67 // all of these will be statically initialized to zero
68 void *pointer;
69 dispatch_once_t once;
70 OSSpinLock access;
71 };
72
73 template <class Type>
74 class ModuleNexus : public ModuleNexusCommon {
75 public:
76 Type &operator () ()
77 {
78 lock();
79
80 try
81 {
82 if (pointer == NULL)
83 {
84 pointer = create(make);
85 }
86
87 unlock();
88 }
89 catch (...)
90 {
91 unlock();
92 throw;
93 }
94
95 return *reinterpret_cast<Type *>(pointer);
96 }
97
98 // does the object DEFINITELY exist already?
99 bool exists() const
100 {
101 bool result;
102 lock();
103 result = pointer != NULL;
104 unlock();
105 return result;
106 }
107
108 // destroy the object (if any) and start over - not really thread-safe
109 void reset()
110 {
111 lock();
112 if (pointer != NULL)
113 {
114 delete reinterpret_cast<Type *>(pointer);
115 pointer = NULL;
116 once = 0;
117 }
118 unlock();
119 }
120
121 private:
122 static void *make() { return new Type; }
123 };
124
125 template <class Type>
126 class CleanModuleNexus : public ModuleNexus<Type> {
127 public:
128 ~CleanModuleNexus()
129 {
130 secdebug("nexus", "ModuleNexus %p destroyed object 0x%x",
131 this, ModuleNexus<Type>::pointer);
132 delete reinterpret_cast<Type *>(ModuleNexus<Type>::pointer);
133 }
134 };
135
136 typedef std::set<void*> RetentionSet;
137
138 //
139 // A thread-scope nexus is tied to a particular native thread AND
140 // a particular nexus object. Its scope is all code in any one thread
141 // that access that particular Nexus object. Any number of Nexus objects
142 // can exist, and each implements a different scope for each thread.
143 // NOTE: ThreadNexus is dynamically constructed. If you want static,
144 // zero-initialization ThreadNexi, put them inside a ModuleNexus.
145 //
146 template <class Type>
147 class ThreadNexus : public GlobalNexus {
148 public:
149 ThreadNexus() : mSlot(true) { }
150
151 Type &operator () ()
152 {
153 // no thread contention here!
154 if (Type *p = mSlot)
155 return *p;
156 mSlot = new Type;
157 return *mSlot;
158 }
159
160 private:
161 PerThreadPointer<Type> mSlot;
162 };
163
164
165 //
166 // A ProcessNexus is global within a single process, regardless of
167 // load module boundaries. You can have any number of ProcessNexus
168 // scopes, each identified by a C string (compared by value, not pointer).
169 //
170 class ProcessNexusBase : public GlobalNexus {
171 protected:
172 ProcessNexusBase(const char *identifier);
173
174 struct Store {
175 void *mObject;
176 Mutex mLock;
177 };
178 Store *mStore;
179 };
180
181 template <class Type>
182 class ProcessNexus : public ProcessNexusBase {
183 public:
184 ProcessNexus(const char *identifier) : ProcessNexusBase(identifier) { }
185 Type &operator () ();
186
187 private:
188 Type *mObject;
189 };
190
191 template <class Type>
192 Type &ProcessNexus<Type>::operator () ()
193 {
194 #if !defined(PTHREAD_STRICT)
195 // not strictly kosher POSIX, but pointers are usually atomic types
196 if (mStore->mObject)
197 return *reinterpret_cast<Type *>(mStore->mObject);
198 #endif
199 StLock<Mutex> _(mStore->mLock);
200 if (mStore->mObject == NULL)
201 mStore->mObject = new Type;
202 return *reinterpret_cast<Type *>(mStore->mObject);
203 };
204
205
206 } // end namespace Security
207
208 #endif //_H_GLOBALIZER