(file) Return to SpinLock.h CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  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 */

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2