00001 #include <stdio.h>
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifndef _SPINLOCK_H_
00029 #define _SPINLOCK_H_
00030
00031 #if defined(unix)
00032 #include <sched.h>
00033 #endif
00034
00035 #if defined(__SVR4)
00036 #include <thread.h>
00037 #endif
00038
00039 #if defined(__sgi)
00040 #include <mutex.h>
00041 #endif
00042
00043 #if defined(__APPLE__)
00044 #include <libkern/OSAtomic.h>
00045 #endif
00046
00047 #include "hldefines.h"
00048 #include "cpuinfo.h"
00049
00050 #if defined(_MSC_VER)
00051
00052 #if !defined(NO_INLINE)
00053 #pragma inline_depth(255)
00054 #define NO_INLINE __declspec(noinline)
00055 #define INLINE __forceinline
00056 #define inline __forceinline
00057 #endif // !defined(NO_INLINE)
00058
00059 #else
00060
00061 #endif // defined(_MSC_VER)
00062
00063
00064 #if defined(__SUNPRO_CC)
00065
00066 extern "C" unsigned long MyInterlockedExchange (unsigned long * oldval,
00067 unsigned long newval);
00068 #endif
00069
00070 #if defined(_WIN32) && !defined(_WIN64)
00071 #define _WIN32_WINNT 0x0500
00072
00073
00074
00075
00076
00077
00078
00079 #define _MM_PAUSE {__asm{_emit 0xf3};__asm {_emit 0x90}}
00080 #include <windows.h>
00081 #else
00082 #define _MM_PAUSE
00083 #endif // defined(_WIN32) && !defined(_WIN64)
00084
00085 extern volatile int anyThreadCreated;
00086
00087 namespace HL {
00088
00089 class SpinLockType {
00090 private:
00091
00092 enum { UNLOCKED = 0, LOCKED = 1 };
00093
00094 public:
00095
00096 SpinLockType (void)
00097 #if defined(__APPLE__)
00098 : mutex (OS_SPINLOCK_INIT)
00099 #else
00100 : mutex (UNLOCKED)
00101 #endif
00102 {}
00103
00104 ~SpinLockType (void)
00105 {}
00106
00107 inline void lock (void) {
00108 if (anyThreadCreated) {
00109 if (MyInterlockedExchange (const_cast<unsigned long *>(&mutex), LOCKED)
00110 != UNLOCKED) {
00111 contendedLock();
00112 }
00113 } else {
00114 mutex = LOCKED;
00115 }
00116 }
00117
00118
00119
00120 inline void unlock (void) {
00121 if (anyThreadCreated) {
00122 #if defined(_WIN32) && !defined(_WIN64)
00123 __asm {}
00124 #elif defined(__GNUC__)
00125 asm volatile ("" : : : "memory");
00126 #endif
00127 }
00128 mutex = UNLOCKED;
00129 }
00130
00131
00132 #if !defined(__SUNPRO_CC)
00133 inline static unsigned long MyInterlockedExchange (unsigned long *,unsigned long);
00134 #endif
00135
00136 private:
00137
00138 #if 0 // defined(__APPLE__)
00139 OSSpinLock mutex;
00140
00141 #else
00142
00143 NO_INLINE
00144 void contendedLock (void) {
00145 while (1) {
00146 if (MyInterlockedExchange (const_cast<unsigned long *>(&mutex), LOCKED)
00147 == UNLOCKED) {
00148 return;
00149 }
00150 while (mutex == LOCKED) {
00151 _MM_PAUSE;
00152 yieldProcessor();
00153 }
00154 }
00155 }
00156
00157
00158 inline bool onMultiprocessor (void) {
00159 static CPUInfo cpuInfo;
00160 return (cpuInfo.getNumProcessors() > 1);
00161 }
00162
00163 inline void yieldProcessor (void) {
00164 #if defined(_WIN32)
00165 Sleep(0);
00166 #elif defined(__SVR4)
00167 thr_yield();
00168 #else
00169 sched_yield();
00170 #endif
00171 }
00172
00173 enum { MAX_SPIN_LIMIT = 1024 };
00174
00175 union {
00176 volatile unsigned long mutex;
00177 };
00178 #endif
00179
00180 };
00181
00182 }
00183
00184
00185
00186
00187
00188
00189 #if !defined(__SUNPRO_CC) // && !defined(__APPLE__)
00190 inline unsigned long
00191 HL::SpinLockType::MyInterlockedExchange (unsigned long * oldval,
00192 unsigned long newval)
00193 {
00194 #if defined(_WIN32) && defined(_MSC_VER)
00195 return InterlockedExchange ((volatile LONG *) oldval, newval);
00196
00197
00198
00199
00200 #elif defined(__sparc)
00201 asm volatile ("swap [%1],%0"
00202 :"=r" (newval)
00203 :"r" (oldval), "0" (newval)
00204 : "memory");
00205
00206 #elif defined(__i386__)
00207 asm volatile ("lock; xchgl %0, %1"
00208 : "=r" (newval)
00209 : "m" (*oldval), "0" (newval)
00210 : "memory");
00211
00212 #elif defined(__sgi)
00213 newval = test_and_set (oldval, newval);
00214
00215 #elif defined(__x86_64__)
00216
00217 asm volatile ("lock; xchgq %0, %1"
00218 : "=r" (newval)
00219 : "m" (*oldval), "0" (newval)
00220 : "memory");
00221
00222 #elif defined(__ppc) || defined(__powerpc__) || defined(PPC)
00223
00224 int ret;
00225 asm volatile (
00226 "La..%=0: lwarx %0,0,%1 ;"
00227 " cmpw %0,%2;"
00228 " beq La..%=1;"
00229 " stwcx. %2,0,%1;"
00230 " bne- La..%=0;"
00231 "La..%=1: isync;"
00232 : "=&r"(ret)
00233 : "r"(oldval), "r"(newval)
00234 : "cr0", "memory");
00235 return ret;
00236
00237 #elif defined(__arm__)
00238
00239 long result;
00240 asm volatile (
00241 "\n\t"
00242 "swp %0,%2,[%1] \n\t"
00243 ""
00244 : "=&r"(result)
00245 : "r"(oldval), "r"(newval)
00246 : "memory");
00247 return (result);
00248 #elif defined(__APPLE__)
00249 unsigned long oldValue = *oldval;
00250 bool swapped = OSAtomicCompareAndSwapLongBarrier (oldValue, newval, oldval);
00251 if (swapped) {
00252 return newval;
00253 } else {
00254 return oldValue;
00255 }
00256 #else
00257 #error "No spin lock implementation is available for this platform."
00258 #endif
00259 return newval;
00260 }
00261
00262
00263 #endif
00264
00265 #endif // _SPINLOCK_H_