]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/globalizer.h
Security-164.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / globalizer.h
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 * globalizer - multiscope globalization services
21 */
22 #ifndef _H_GLOBALIZER
23 #define _H_GLOBALIZER
24
25 #include <Security/threading.h>
26 #include <memory>
27
28 namespace Security {
29
30
31 //
32 // GlobalNexus is the common superclass of all globality scopes.
33 // A Nexus is an *access point* to the *single* object of a given
34 // type in the Nexus's particular scope.
35 //
36 class GlobalNexus {
37 public:
38 class Error : public std::exception {
39 public:
40 virtual ~Error() throw();
41 const char * const message;
42 Error(const char *m) : message(m) { }
43 const char *what() const throw() { return message; }
44 };
45 };
46
47
48 //
49 // A module-scope nexus is tied to the linker Nexus object itself.
50 // Its scope is all code accessing that particular Nexus object
51 // from within a process. Any number of ModuleNexus objects can
52 // exist, and each implements a different scope.
53 //
54 // IMPORTANT notes on this class can be found in globalizer.cpp.
55 // DO NOT change anything here before carefully reading them.
56 //
57 #if defined(_HAVE_ATOMIC_OPERATIONS)
58
59 class ModuleNexusCommon : public GlobalNexus {
60 protected:
61 AtomicWord create(void *(*make)());
62
63 protected:
64 // both of these will be statically initialized to zero
65 AtomicWord pointer;
66 StaticAtomicCounter<uint32> sync;
67 };
68
69 template <class Type>
70 class ModuleNexus : public ModuleNexusCommon {
71 public:
72 Type &operator () ()
73 {
74 AtomicWord p = pointer; // latch pointer
75 if (!p || (p & 0x1)) {
76 p = create(make);
77 secdebug("nexus", "module %s 0x%x", Debug::typeName<Type>().c_str(), pointer);
78 }
79 return *reinterpret_cast<Type *>(p);
80 }
81
82 void reset()
83 {
84 if (pointer && !(pointer & 0x1)) {
85 delete reinterpret_cast<Type *>(pointer);
86 pointer = 0;
87 }
88 }
89
90 private:
91 static void *make() { return new Type; }
92 };
93
94 template <class Type>
95 class CleanModuleNexus : public ModuleNexus<Type> {
96 public:
97 ~CleanModuleNexus()
98 {
99 secdebug("nexus", "ModuleNexus %p destroyed object 0x%x", this, pointer);
100 delete reinterpret_cast<Type *>(pointer);
101 }
102 };
103
104 #else // !_HAVE_ATOMIC_OPERATIONS
105
106 template <class Type>
107 class ModuleNexus : public GlobalNexus {
108 public:
109 Type &operator () ()
110 {
111 #if !defined(PTHREAD_STRICT)
112 // not strictly kosher POSIX, but pointers are usually atomic types
113 if (mSingleton)
114 return *mSingleton;
115 #endif
116 StLock<Mutex> _(mLock);
117 if (mSingleton == NULL)
118 mSingleton = new Type;
119 return *mSingleton;
120 }
121
122 void reset() { delete mSingleton; mSingleton = NULL; }
123
124 protected:
125 Type *mSingleton; // pointer to singleton static initialized to NULL
126 Mutex mLock; // construction lock
127 };
128
129 template <class Type>
130 class CleanModuleNexus : public ModuleNexus<Type> {
131 public:
132 ~CleanModuleNexus()
133 {
134 secdebug("nexus", "ModuleNexus %p destroyed object 0x%x", this, mSingleton);
135 delete mSingleton;
136 }
137 };
138
139 #endif // _HAVE_ATOMIC_OPERATIONS
140
141
142 //
143 // A thread-scope nexus is tied to a particular native thread AND
144 // a particular nexus object. Its scope is all code in any one thread
145 // that access that particular Nexus object. Any number of Nexus objects
146 // can exist, and each implements a different scope for each thread.
147 // NOTE: ThreadNexus is dynamically constructed. If you want static,
148 // zero-initialization ThreadNexi, put them inside a ModuleNexus.
149 //
150 #if _USE_THREADS == _USE_PTHREADS
151
152 template <class Type>
153 class ThreadNexus : public GlobalNexus {
154 public:
155 ThreadNexus() : mSlot(true) { }
156 Type &operator () ()
157 {
158 // no thread contention here!
159 if (Type *p = mSlot)
160 return *p;
161 mSlot = new Type;
162 return *mSlot;
163 }
164
165 private:
166 PerThreadPointer<Type> mSlot;
167 };
168
169 #endif //_USE_PTHREADS
170
171
172 //
173 // A ProcessNexus is global within a single process, regardless of
174 // load module boundaries. You can have any number of ProcessNexus
175 // scopes, each identified by a C string (compared by value, not pointer).
176 //
177 class ProcessNexusBase : public GlobalNexus {
178 protected:
179 ProcessNexusBase(const char *identifier);
180
181 struct Store {
182 void *mObject;
183 Mutex mLock;
184 };
185 Store *mStore;
186 };
187
188 template <class Type>
189 class ProcessNexus : public ProcessNexusBase {
190 public:
191 ProcessNexus(const char *identifier) : ProcessNexusBase(identifier) { }
192 Type &operator () ();
193
194 private:
195 Type *mObject;
196 };
197
198 template <class Type>
199 Type &ProcessNexus<Type>::operator () ()
200 {
201 #if !defined(PTHREAD_STRICT)
202 // not strictly kosher POSIX, but pointers are usually atomic types
203 if (mStore->mObject)
204 return *reinterpret_cast<Type *>(mStore->mObject);
205 #endif
206 StLock<Mutex> _(mStore->mLock);
207 if (mStore->mObject == NULL)
208 mStore->mObject = new Type;
209 return *reinterpret_cast<Type *>(mStore->mObject);
210 };
211
212
213 } // end namespace Security
214
215 #endif //_H_GLOBALIZER