]> git.saurik.com Git - apple/security.git/blame - libsecurity_utilities/lib/globalizer.h
Security-55471.14.18.tar.gz
[apple/security.git] / libsecurity_utilities / lib / globalizer.h
CommitLineData
b1ab9ed8
A
1/*
2 * Copyright (c) 2000-2004 Apple Computer, 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>
427c49bc
A
34#include <dispatch/dispatch.h>
35#include <libkern/OSAtomic.h>
b1ab9ed8
A
36
37namespace 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//
45class GlobalNexus {
46public:
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
b1ab9ed8 57class ModuleNexusCommon : public GlobalNexus {
427c49bc
A
58private:
59 void do_create(void *(*make)());
60
b1ab9ed8
A
61protected:
62 void *create(void *(*make)());
427c49bc
A
63 void lock() {OSSpinLockLock(&access);}
64 void unlock() {OSSpinLockUnlock(&access);}
65
b1ab9ed8 66protected:
427c49bc 67 // all of these will be statically initialized to zero
b1ab9ed8 68 void *pointer;
427c49bc
A
69 dispatch_once_t once;
70 OSSpinLock access;
b1ab9ed8
A
71};
72
73template <class Type>
74class ModuleNexus : public ModuleNexusCommon {
75public:
427c49bc 76 Type &operator () ()
b1ab9ed8 77 {
427c49bc
A
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);
b1ab9ed8
A
96 }
97
98 // does the object DEFINITELY exist already?
99 bool exists() const
100 {
427c49bc
A
101 bool result;
102 lock();
103 result = pointer != NULL;
104 unlock();
105 return result;
b1ab9ed8
A
106 }
107
108 // destroy the object (if any) and start over - not really thread-safe
109 void reset()
110 {
427c49bc
A
111 lock();
112 if (pointer != NULL)
113 {
b1ab9ed8 114 delete reinterpret_cast<Type *>(pointer);
427c49bc
A
115 pointer = NULL;
116 once = 0;
b1ab9ed8 117 }
427c49bc 118 unlock();
b1ab9ed8
A
119 }
120
121private:
122 static void *make() { return new Type; }
123};
124
125template <class Type>
126class CleanModuleNexus : public ModuleNexus<Type> {
127public:
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
136typedef std::set<void*> RetentionSet;
137
b1ab9ed8
A
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//
146template <class Type>
427c49bc 147class ThreadNexus : public GlobalNexus {
b1ab9ed8
A
148public:
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;
b1ab9ed8
A
157 return *mSlot;
158 }
159
160private:
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//
170class ProcessNexusBase : public GlobalNexus {
171protected:
172 ProcessNexusBase(const char *identifier);
173
174 struct Store {
175 void *mObject;
176 Mutex mLock;
177 };
178 Store *mStore;
179};
180
181template <class Type>
182class ProcessNexus : public ProcessNexusBase {
183public:
184 ProcessNexus(const char *identifier) : ProcessNexusBase(identifier) { }
185 Type &operator () ();
186
187private:
188 Type *mObject;
189};
190
191template <class Type>
192Type &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