00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef __CS_CSUTIL_THREADING_WIN32_MUTEX_H__
00020 #define __CS_CSUTIL_THREADING_WIN32_MUTEX_H__
00021
00022 #include "csutil/threading/atomicops.h"
00023 #include "csutil/threading/win32_apifuncs.h"
00024
00025 #if !defined(CS_PLATFORM_WIN32)
00026 #error "This file is only for Windows and requires you to include csysdefs.h before"
00027 #else
00028
00029 #ifdef CS_THREAD_CHECKER
00030 #include <libittnotify.h>
00031 #endif
00032
00033 namespace CS
00034 {
00035 namespace Threading
00036 {
00037 namespace Implementation
00038 {
00039
00043 class MutexBase
00044 {
00045 public:
00046 void Initialize ()
00047 {
00048 activeFlag = 0;
00049 semaphore = 0;
00050 }
00051
00052 void Destroy ()
00053 {
00054 void* oldSemaphore = AtomicOperations::Set (&semaphore, (void*)0);
00055 if (oldSemaphore)
00056 {
00057 Implementation::CloseHandle (semaphore);
00058 }
00059 }
00060
00061
00062 bool Lock ()
00063 {
00064 #ifdef CS_THREAD_CHECKER
00065 __itt_notify_sync_prepare((void *)this);
00066 #endif
00067 if (AtomicOperations::Increment (&activeFlag) != 1)
00068 {
00069 Implementation::WaitForSingleObject (GetSemaphore (), INFINITE);
00070 }
00071 #ifdef CS_THREAD_CHECKER
00072 __itt_notify_sync_acquired((void *)this);
00073 #endif
00074 return IsLocked ();
00075 }
00076
00077 bool TryLock ()
00078 {
00079 #ifdef CS_THREAD_CHECKER
00080 __itt_notify_sync_prepare((void *)this);
00081 bool locked = !AtomicOperations::CompareAndSet (&activeFlag, 1, 0);
00082 if(locked)
00083 __itt_notify_sync_acquired((void *)this);
00084 else
00085 __itt_notify_sync_cancel((void *)this);
00086 return locked;
00087 #else
00088 return !AtomicOperations::CompareAndSet (&activeFlag, 1, 0);
00089 #endif
00090 }
00091
00092 void Unlock ()
00093 {
00094 #ifdef CS_THREAD_CHECKER
00095 __itt_notify_sync_releasing((void *)this);
00096 #endif
00097 if (AtomicOperations::Decrement (&activeFlag) > 0)
00098 {
00099 Implementation::ReleaseSemaphore (GetSemaphore (), 1, 0);
00100 }
00101 }
00102
00103 protected:
00104 friend class RecursiveMutexBase;
00105 bool IsLocked ()
00106 {
00107 return AtomicOperations::Read (&activeFlag) > 0;
00108 }
00109
00110 void* GetSemaphore ()
00111 {
00112 void* currentSem = AtomicOperations::Read (&semaphore);
00113 if (!currentSem)
00114 {
00115
00116 void* const newSem = Implementation::CreateSemaphoreA (0,0,1,0);
00117 void* const oldSem = AtomicOperations::CompareAndSet (&semaphore,
00118 newSem, 0);
00119
00120
00121 if (oldSem != 0)
00122 {
00123 Implementation::CloseHandle (newSem);
00124 return oldSem;
00125 }
00126 else
00127 {
00128
00129 return newSem;
00130 }
00131 }
00132 return currentSem;
00133 }
00134
00135 int32 activeFlag;
00136 void* semaphore;
00137 };
00138
00139
00143 class RecursiveMutexBase
00144 {
00145 public:
00146 void Initialize ()
00147 {
00148 recursionCount = 0;
00149 lockingThreadID = 0;
00150 mutex.Initialize ();
00151 }
00152
00153 void Destroy ()
00154 {
00155 mutex.Destroy ();
00156 }
00157
00158 bool IsLocked ()
00159 {
00160 return mutex.IsLocked ();
00161 }
00162
00163 bool Lock ()
00164 {
00165 int32 currentThreadID = (int32)Implementation::GetCurrentThreadId ();
00166 if (!TryRecursiveLock (currentThreadID))
00167 {
00168 mutex.Lock ();
00169 AtomicOperations::Set (&lockingThreadID, currentThreadID);
00170 recursionCount = 1;
00171 }
00172 return IsLocked ();
00173 }
00174
00175 bool TryLock ()
00176 {
00177 int32 currentThreadID = (int32)Implementation::GetCurrentThreadId ();
00178 return TryRecursiveLock (currentThreadID) ||
00179 TryNormalLock (currentThreadID);
00180 }
00181
00182 void Unlock ()
00183 {
00184 if(!--recursionCount)
00185 {
00186 AtomicOperations::Set (&lockingThreadID, 0);
00187 mutex.Unlock ();
00188 }
00189 }
00190
00191 private:
00192 bool TryRecursiveLock (int32 currentThreadID)
00193 {
00194 if (AtomicOperations::Read (&lockingThreadID) == currentThreadID)
00195 {
00196 ++recursionCount;
00197 return true;
00198 }
00199 return false;
00200 }
00201
00202 bool TryNormalLock (int32 currentThreadID)
00203 {
00204 if (mutex.TryLock ())
00205 {
00206 AtomicOperations::Set (&lockingThreadID, currentThreadID);
00207 recursionCount = 1;
00208 return true;
00209 }
00210 return false;
00211 }
00212
00213 MutexBase mutex;
00214 int32 recursionCount;
00215 int32 lockingThreadID;
00216 };
00217
00218 }
00219 }
00220 }
00221
00222 #endif // !defined(CS_PLATFORM_WIN32)
00223
00224 #endif // __CS_CSUTIL_THREADING_WIN32_MUTEX_H__