]> git.saurik.com Git - apple/security.git/blame - cdsa/cdsa_utilities/globalizer.cpp
Security-163.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / globalizer.cpp
CommitLineData
bac41a7b
A
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// This is a tentative, partial implementation.
23// Status:
24// module scope: constructs, optional cleanup
25// thread scope: constructs, optional cleanup
26// process scope: not implemented (obsolete implementation, unused)
27// system scope: not implemented (probably never will)
28//
29// @@@ Assumption: {bool,T*} atomic unless PTHREAD_STRICT
30//
bac41a7b 31#include <Security/globalizer.h>
29654253 32#include <Security/debugging.h>
bac41a7b
A
33#include <cstdlib>
34
35
36//
37// The Error class thrown if Nexus operations fail
38//
29654253 39GlobalNexus::Error::~Error() throw()
bac41a7b
A
40{
41}
42
43
44//
45// The long (and possibly contentious) path of ModuleNexus()
46//
47// Briefly, the trick here is to go through a three-stage sequence
48// to lazily construct a unique singleton object, no matter how many
49// threads all of a sudden decide they need it.
50// State sequence:
51// State 0: pointer == 0, not initialized, idle
52// State 1: pointer == mutexp | 0x1, where mutexp points to a Mutex
53// used to serialize construction of the singleton object
54// State 2: pointer == &singleton, and we're done
55//
56// TAKE NOTE:
57// This code is optimized with a particular issue in mind: when placed
58// into static storage (as ModuleNexi are wont to), it should not require
59// dynamic initialization. This is important because our code is, in effect,
60// linked into just about every program in the system. The price we pay
61// for this coolness is
62// (a) This won't work *except* in static storage (not on stack or heap)
63// (b) We slightly fracture portability (see below)
64// This has been considered Worth It, at least for now. Before you throw
65// up and throw this code out, please try to figure out whether you know
66// the Whole Story. Thank you.
67//
68// WARNING:
69// This code makes the following non-portable assumptions:
70// (a) NULL == 0 (binary representation of NULL pointer is zero value)
29654253
A
71// (b) Pointers acquired from new have at least their LSB zero (are at
72// least two-byte aligned).
bac41a7b
A
73// It seems like it's been a while since anyone made a machine/runtime that
74// violated either of those. But you have been warned.
75//
76#if defined(_HAVE_ATOMIC_OPERATIONS)
77
78AtomicWord ModuleNexusCommon::create(void *(*make)())
79{
80 sync++; // keep mutex alive if needed
81 retry:
82 AtomicWord initialPointer = pointer; // latch pointer
83 if (!initialPointer || (initialPointer & 0x1)) {
84 Mutex *mutex;
85 if (initialPointer == 0) {
86 mutex = new Mutex(false); // don't bother debugging this one
87 mutex->lock();
88 if (atomicStore(pointer, AtomicWord(mutex) | 0x1, 0) != 0) {
89 // somebody beat us to the lead - back off
90 mutex->unlock();
91 delete mutex;
92 goto retry;
93 }
94 // we have the ball
95 try {
96 void *singleton = make();
97 pointer = AtomicWord(singleton);
98 // we need a write barrier here, but the mutex->unlock below provides it for free
bac41a7b 99 } catch (...) {
df0e469f 100 secdebug("nexus", "ModuleNexus %p construction failed", this);
bac41a7b 101 mutex->unlock();
29654253
A
102 if (--sync == 0) {
103 delete mutex;
104 pointer = 0;
105 }
bac41a7b
A
106 throw;
107 }
108 } else {
29654253 109 mutex = reinterpret_cast<Mutex *>(initialPointer & ~0x1);
bac41a7b
A
110 mutex->lock(); // we'll wait here
111 }
112 mutex->unlock();
113 //@@@ retry if not resolved -- or fail here (with "object can't be built")
114 if (--sync == 0)
115 delete mutex;
116 }
117 return pointer;
118}
119
120#endif //_HAVE_ATOMIC_OPERATIONS
121
122
123//
124// Process nexus operation
125//
126ProcessNexusBase::ProcessNexusBase(const char *identifier)
127{
128 const char *env = getenv(identifier);
129 if (env == NULL) { // perhaps we're first...
130 auto_ptr<Store> store(new Store);
131 char form[2*sizeof(Store *) + 2];
132 sprintf(form, "*%p", &store);
133 setenv(identifier, form, 0); // do NOT overwrite...
134 env = getenv(identifier); // ... and refetch to resolve races
135 if (sscanf(env, "*%p", &mStore) != 1)
136 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR /*"environment communication failed" */);
137 if (mStore == store.get()) // we won the race...
138 store.release(); // ... so keep the store
139 } else
140 if (sscanf(env, "*%p", &mStore) != 1)
141 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR /*"environment communication failed"*/);
142}