Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef __CS_CSUTIL_SPINLOCK_H__
00020 #define __CS_CSUTIL_SPINLOCK_H__
00021
00025 #ifndef CS_PLATFORM_WIN32
00026 #include <pthread.h>
00027 #include <sched.h>
00028 #endif
00029
00033 namespace CS
00034 {
00035 class SpinLock
00036 {
00037 #ifdef CS_PLATFORM_WIN32
00038 typedef DWORD ThreadID;
00039 #else
00040 typedef pthread_t ThreadID;
00041 #endif
00042 #if defined (CS_PROCESSOR_X86) && defined (CS_COMPILER_GCC)
00043 volatile ThreadID threadid;
00044 volatile uint l;
00045 #elif defined(CS_PLATFORM_WIN32)
00046 volatile ThreadID threadid;
00047 volatile LONG l;
00048 #else
00049 pthread_mutex_t l;
00050 #endif
00051
00052 volatile uint c;
00053
00054 static const int spinsPerYield = 63;
00055
00056 #if defined(CS_PLATFORM_WIN32)
00057 CS_FORCEINLINE ThreadID CurrentThreadID()
00058 { return GetCurrentThreadId(); }
00059 #else
00060 CS_FORCEINLINE ThreadID CurrentThreadID()
00061 { return pthread_self(); }
00062 #endif
00063
00064
00065 #if defined (CS_PROCESSOR_X86) && defined (CS_COMPILER_GCC)
00066 CS_FORCEINLINE bool DoLockWait()
00067 {
00068 ThreadID mythreadid = CurrentThreadID();
00069 if(mythreadid == threadid)
00070 ++c;
00071 else
00072 {
00073 int spins = 0;
00074 for (;;) {
00075 int ret;
00076 __asm__ __volatile__ ("lock; cmpxchgl %2,(%1)" : "=a" (ret) : "r" (&l), "r" (1), "a" (0));
00077 if(!ret)
00078 {
00079 CS_ASSERT(!threadid);
00080 threadid = mythreadid;
00081 c = 1;
00082 break;
00083 }
00084 if ((++spins & spinsPerYield) == 0) {
00085 #if defined(CS_PLATFORM_UNIX)
00086 sched_yield();
00087 #elif defined(CS_PLATFORM_WIN32)
00088 SleepEx (0, FALSE);
00089 #else
00090 ;
00091 #endif
00092 }
00093 }
00094 }
00095 return true;
00096 }
00097 CS_FORCEINLINE bool DoLockTry()
00098 {
00099 int ret;
00100 __asm__ __volatile__ ("lock; cmpxchgl %2,(%1)" : "=a" (ret) : "r" (&l), "r" (1), "a" (0));
00101 if(!ret){
00102 CS_ASSERT(!threadid);
00103 threadid = CurrentThreadID();
00104 c=1;
00105 return true;
00106 }
00107 return false;
00108 }
00109 CS_FORCEINLINE void DoRelease()
00110 {
00111 int ret;
00112 CS_ASSERT(CurrentThreadID() == threadid);
00113 if (!--c) {
00114 threadid=0;
00115 __asm__ __volatile__ ("xchgl %2,(%1)" : "=r" (ret) : "r" (&l), "0" (0));
00116 }
00117 }
00118 CS_FORCEINLINE void Init() { threadid = 0; c = 0; l = 0; }
00119 CS_FORCEINLINE void Destroy() {}
00120
00121 #elif defined(CS_PLATFORM_WIN32)
00122 CS_FORCEINLINE bool DoLockWait()
00123 {
00124 ThreadID mythreadid = CurrentThreadID();
00125 if(mythreadid == threadid)
00126 ++c;
00127 else {
00128 int spins = 0;
00129 for (;;) {
00130 if (!_InterlockedExchange(&l, 1)) {
00131 CS_ASSERT(!threadid);
00132 threadid = mythreadid;
00133 c = 1;
00134 break;
00135 }
00136 if ((++spins & spinsPerYield) == 0)
00137 SleepEx (0, FALSE);
00138 }
00139 }
00140 return true;
00141 }
00142 CS_FORCEINLINE bool DoLockTry()
00143 {
00144 if (!_InterlockedExchange (&l, 1)) {
00145 CS_ASSERT (!threadid);
00146 threadid = CurrentThreadID();
00147 c = 1;
00148 return true;
00149 }
00150 return false;
00151 }
00152 CS_FORCEINLINE void DoRelease()
00153 {
00154 CS_ASSERT (CurrentThreadID() == threadid);
00155 if (!--c) {
00156 threadid = 0;
00157 _InterlockedExchange (&l, 0);
00158 }
00159 }
00160 CS_FORCEINLINE void Init() { threadid = 0; c = 0; l = 0; }
00161 CS_FORCEINLINE void Destroy() {}
00162
00163 #else
00164 CS_FORCEINLINE bool DoLockWait()
00165 {
00166 if(!pthread_mutex_lock(&l)){
00167 c++;
00168 return true;
00169 }
00170 return false;
00171 }
00172 CS_FORCEINLINE bool DoLockTry()
00173 {
00174 if(!pthread_mutex_trylock(&l)){
00175 c++;
00176 return true;
00177 }
00178 return false;
00179 }
00180 CS_FORCEINLINE void DoRelease()
00181 {
00182 --c;
00183 pthread_mutex_unlock(&l);
00184 }
00185 CS_FORCEINLINE void Init()
00186 {
00187 pthread_mutexattr_t attr;
00188 c=0;
00189 if(pthread_mutexattr_init (&attr)) return;
00190 if(pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE)) return;
00191 if(pthread_mutex_init (&l, &attr)) return;
00192 pthread_mutexattr_destroy (&attr);
00193 }
00194 CS_FORCEINLINE void Destroy() {}
00195 #endif
00196 public:
00197 SpinLock()
00198 { Init(); }
00199 ~SpinLock() { Destroy(); }
00200
00201 CS_FORCEINLINE bool LockWait()
00202 { return DoLockWait(); }
00203 CS_FORCEINLINE bool LockTry()
00204 { return DoLockTry(); }
00205 CS_FORCEINLINE void Release()
00206 { DoRelease(); }
00207 };
00208 }
00209
00212 #endif // __CS_CSUTIL_SPINLOCK_H__