1 karl 1.4 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.1 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.4 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.1 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
|
20 karl 1.4 //
|
21 mike 1.1 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 #ifndef Pegasus_SpinLock_h
35 #define Pegasus_SpinLock_h
36
37 #include <Pegasus/Common/Config.h>
|
38 dave.sudlik 1.7 #include <Pegasus/Common/Linkage.h>
|
39 mike 1.1
|
40 mike 1.5 //==============================================================================
41 //
42 // PEGASUS_PLATFORM_HPUX_PARISC_ACC
43 //
44 // NOTE: This spinlock implementation is based on the paper "Implementing
45 // Spinlocks on the Intel(R) Itanium(R) Architecture an PA-RISC" by Tor
46 // Ekqvist and David Graves.
47 //
48 // WARNING: This implementation has subtle complexities. Seemingly
49 // innocuous changes could have unexpected side effects. Please use
50 // diligence when modifying the implementation.
51 //
52 //==============================================================================
53
54 #if defined(PEGASUS_PLATFORM_HPUX_PARISC_ACC)
55 # define PEGASUS_SPIN_LOCK_DEFINED
56
57 # include <sys/time.h> // For select()
58
59 #define PEGASUS_SPINLOCK_USE_PTHREADS
60
61 mike 1.5 extern "C" int LoadAndClearWord(volatile int* addr);
62 extern "C" void _flush_globals();
63
64 PEGASUS_NAMESPACE_BEGIN
65
|
66 kumpf 1.6 // This type implements a spinlock. It is deliberately not a class since we
|
67 mike 1.5 // wish to avoid automatic construction/destruction.
68 struct SpinLock
69 {
70 unsigned int initialized;
71
72 /**
73 Points to a 16-byte aligned lock word (which lies somewhere within
74 the region). The lock word is zero when locked and 1 when unlocked.
75 */
76 volatile int* lock;
77
78 /**
79 Points to a lock region (which contains the lock). The LDCWS
80 instruction requires that the lock word be aligned on a 16-byte
81 boundary. So we allocate 32 bytes and adjust lock so that it falls
82 on the first such boundary within this region. We make the region
83 large to keep the spin locks from getting too close together, which
84 would put them on the same cache line, creating contention.
85 */
86 char region[32];
87
88 mike 1.5 /**
89 Extends the size of the struct to match the 64-byte cache line size.
90 NOTE: This does not ensure that the struct will align with a cache
91 line. Doing so could benefit performance.
92 */
93 char unused[24];
94 };
95
96 inline void SpinLockCreate(SpinLock& x)
97 {
98 // Set x.lock to first 16-byte boundary within region.
99 #ifdef __LP64__
100 x.lock = (volatile int*)(((long)x.region + 15) & ~0xF);
|
101 mike 1.1 #else
|
102 mike 1.5 x.lock = (volatile int*)(((int)x.region + 15) & ~0xF);
|
103 mike 1.1 #endif
104
|
105 mike 1.5 // Set to unlocked
106 *x.lock = 1;
107
108 x.initialized = 1;
109 }
110
111 inline void SpinLockDestroy(SpinLock& x)
112 {
113 }
114
115 inline void SpinLockLock(SpinLock& x)
116 {
117 // Spin until we obtain the lock.
118 while (1)
119 {
120 for (Uint32 spins = 0; spins < 200; spins++)
121 {
122 if (*x.lock == 1) // pre-check
123 {
124 if (LoadAndClearWord(x.lock) == 1)
125 {
126 mike 1.5 return;
127 }
128 }
129 }
130
131 // Didn't get the lock after 200 spins, so sleep for 5 ms
132 struct timeval sleeptime = { 0, 5000 };
133 select(0, 0, 0, 0, &sleeptime);
134 }
135 }
136
137 inline void SpinLockUnlock(SpinLock& x)
138 {
139 // Ensure that the compiler doesn't hold any externally-visible values in
140 // registers across the lock release.
141 _flush_globals();
142
143 // Set to unlocked
144 *x.lock = 1;
145 }
146
147 mike 1.5 PEGASUS_NAMESPACE_END
148
149 #endif /* PEGASUS_PLATFORM_HPUX_PARISC_ACC */
150
151 //==============================================================================
152 //
153 // PEGASUS_PLATFORM_SOLARIS_SPARC_GNU
154 //
155 //==============================================================================
156
157 #if defined(PEGASUS_PLATFORM_SOLARIS_SPARC_GNU)
158 # define PEGASUS_SPIN_LOCK_DEFINED
159
160 # include <new>
161
162 #define PEGASUS_SPINLOCK_USE_PTHREADS
163
164 PEGASUS_NAMESPACE_BEGIN
165
|
166 kumpf 1.6 // This type implements a spinlock. It is deliberately not a class since we
|
167 mike 1.5 // wish to avoid automatic construction/destruction.
168 struct SpinLock
169 {
170 volatile unsigned char lock;
171 };
172
173 inline void SpinLockCreate(SpinLock& x)
174 {
175 x.lock = 0;
176 }
177
178 inline void SpinLockDestroy(SpinLock& x)
179 {
180 }
181
182 inline void SpinLockLock(SpinLock& x)
183 {
184 Uint32 value;
185
186 // Loop until lock becomes zero.
187 do
188 mike 1.5 {
|
189 kumpf 1.6 // Load and store unsigned byte (LDSTUB). Load the lock argument
190 // into value and set lock to 0xFF (atomically).
191 asm("ldstub %1, %0"
192 : "=r" (value),
193 "=m" (x.lock)
194 : "m" (x.lock));
|
195 mike 1.5 }
196 while (value);
197 }
198
199 inline void SpinLockUnlock(SpinLock& x)
200 {
201 x.lock = 0;
202 }
203
204 PEGASUS_NAMESPACE_END
205
206 #endif /* PEGASUS_PLATFORM_SOLARIS_SPARC_GNU */
207
208 //==============================================================================
209 //
210 // Generic SpinLock Implementation (for other platforms).
211 //
212 //==============================================================================
213
214 #if !defined(PEGASUS_SPIN_LOCK_DEFINED)
215 # define PEGASUS_SPIN_LOCK_DEFINED
216 mike 1.5
217 # include <new>
218 # include <Pegasus/Common/Mutex.h>
219
220 PEGASUS_NAMESPACE_BEGIN
221
|
222 kumpf 1.6 // This type implements a spinlock. It is deliberately not a class since we
|
223 mike 1.5 // wish to avoid automatic construction/destruction.
224 struct SpinLock
225 {
226 union
227 {
|
228 kumpf 1.6 char mutex[sizeof(Mutex)];
229 Uint64 alignment8;
|
230 mike 1.5 };
231 };
232
233 inline void SpinLockCreate(SpinLock& x)
234 {
235 new(&x.mutex) Mutex;
236 }
237
238 inline void SpinLockDestroy(SpinLock& x)
239 {
240 ((Mutex*)&x.mutex)->~Mutex();
241 }
242
243 inline void SpinLockLock(SpinLock& x)
244 {
245 ((Mutex*)&x.mutex)->lock();
246 }
247
248 inline void SpinLockUnlock(SpinLock& x)
249 {
250 ((Mutex*)&x.mutex)->unlock();
251 mike 1.5 }
252
253 PEGASUS_NAMESPACE_END
254
255 #endif /* !PEGASUS_SPIN_LOCK_DEFINED */
256
257 //==============================================================================
258 //
259 // SpinLock Pool Definitions
260 //
261 //==============================================================================
262
|
263 mike 1.1 #define PEGASUS_NUM_SHARED_SPIN_LOCKS 64
264
265 PEGASUS_NAMESPACE_BEGIN
266
|
267 kumpf 1.6 // This array defines spin locks shared across the system. These are
|
268 kumpf 1.3 // initialized by calling SpinLockCreatePool().
|
269 dave.sudlik 1.7 PEGASUS_COMMON_LINKAGE
270 extern SpinLock spinLockPool[PEGASUS_NUM_SHARED_SPIN_LOCKS];
|
271 mike 1.1
|
272 kumpf 1.3 // This flag is 0 until SpinLockCreatePool() is called, which sets it
273 // to 1.
|
274 dave.sudlik 1.7 PEGASUS_COMMON_LINKAGE extern int spinLockPoolInitialized;
|
275 kumpf 1.3
276 // Initializes the global pool of mutexes.
|
277 dave.sudlik 1.7 PEGASUS_COMMON_LINKAGE void SpinLockCreatePool();
|
278 kumpf 1.3
279 // Maps an address into the spinLockPool[] array defined above. This is used
|
280 kumpf 1.6 // to assign objects (by their addresses) to a shared lock. Collisions are
|
281 mike 1.1 // okay.
282 inline size_t SpinLockIndex(const void* x)
283 {
284 // Throw away the lower two bits since they are almost always zero
285 // anyway due to alignment properties.
|
286 a.dunfey 1.8 return ((size_t)x >> 2) % PEGASUS_NUM_SHARED_SPIN_LOCKS;
|
287 mike 1.1 }
288
|
289 kumpf 1.3 // Call this function before forking to unlock the spinlocks in the global
290 // spinlock pool (spinLockPool).
291 void SpinLockInit();
292
|
293 mike 1.1 PEGASUS_NAMESPACE_END
294
295 #endif /* Pegasus_SpinLock_h */
|