csutil/threading/win32_mutex.h
00001 /* 00002 Copyright (C) 2006 by Marten Svanfeldt 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Lesser General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public 00015 License along with this library; if not, write to the Free 00016 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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 //Create a new semaphore and try to set it 00116 void* const newSem = Implementation::CreateSemaphoreA (0,0,1,0); 00117 void* const oldSem = AtomicOperations::CompareAndSet (&semaphore, 00118 newSem, 0); 00119 00120 //We already have one, use it 00121 if (oldSem != 0) 00122 { 00123 Implementation::CloseHandle (newSem); 00124 return oldSem; 00125 } 00126 else 00127 { 00128 //We didn't have any before, so use our new semaphore 00129 return newSem; 00130 } 00131 } 00132 return currentSem; 00133 } 00134 00135 int32 activeFlag; //Lock flag for mutex 00136 void* semaphore; //Semaphore for being able to wait for 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; //Non-recursive base-mutex 00214 int32 recursionCount; 00215 int32 lockingThreadID; 00216 }; 00217 00218 } // namespace Implementation 00219 } // namespace Threading 00220 } // namespace CS 00221 00222 #endif // !defined(CS_PLATFORM_WIN32) 00223 00224 #endif // __CS_CSUTIL_THREADING_WIN32_MUTEX_H__
Generated for Crystal Space 2.0 by doxygen 1.6.1