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 namespace CS 00030 { 00031 namespace Threading 00032 { 00033 namespace Implementation 00034 { 00035 00039 class MutexBase 00040 { 00041 public: 00042 void Initialize () 00043 { 00044 activeFlag = 0; 00045 semaphore = 0; 00046 } 00047 00048 void Destroy () 00049 { 00050 void* oldSemaphore = AtomicOperations::Set (&semaphore, (void*)0); 00051 if (oldSemaphore) 00052 { 00053 Implementation::CloseHandle (semaphore); 00054 } 00055 } 00056 00057 00058 bool Lock () 00059 { 00060 if (AtomicOperations::Increment (&activeFlag) != 1) 00061 { 00062 Implementation::WaitForSingleObject (GetSemaphore (), INFINITE); 00063 } 00064 return IsLocked (); 00065 } 00066 00067 bool TryLock () 00068 { 00069 return !AtomicOperations::CompareAndSet (&activeFlag, 1, 0); 00070 } 00071 00072 void Unlock () 00073 { 00074 if (AtomicOperations::Decrement (&activeFlag) > 0) 00075 { 00076 Implementation::ReleaseSemaphore (GetSemaphore (), 1, 0); 00077 } 00078 } 00079 00080 protected: 00081 friend class RecursiveMutexBase; 00082 bool IsLocked () 00083 { 00084 return AtomicOperations::Read (&activeFlag) > 0; 00085 } 00086 00087 void* GetSemaphore () 00088 { 00089 void* currentSem = AtomicOperations::Read (&semaphore); 00090 if (!currentSem) 00091 { 00092 //Create a new semaphore and try to set it 00093 void* const newSem = Implementation::CreateSemaphoreA (0,0,1,0); 00094 void* const oldSem = AtomicOperations::CompareAndSet (&semaphore, 00095 newSem, 0); 00096 00097 //We already have one, use it 00098 if (oldSem != 0) 00099 { 00100 Implementation::CloseHandle (newSem); 00101 return oldSem; 00102 } 00103 else 00104 { 00105 //We didn't have any before, so use our new semaphore 00106 return newSem; 00107 } 00108 } 00109 return currentSem; 00110 } 00111 00112 int32 activeFlag; //Lock flag for mutex 00113 void* semaphore; //Semaphore for being able to wait for 00114 }; 00115 00116 00120 class RecursiveMutexBase 00121 { 00122 public: 00123 void Initialize () 00124 { 00125 recursionCount = 0; 00126 lockingThreadID = 0; 00127 mutex.Initialize (); 00128 } 00129 00130 void Destroy () 00131 { 00132 mutex.Destroy (); 00133 } 00134 00135 bool IsLocked () 00136 { 00137 return mutex.IsLocked (); 00138 } 00139 00140 bool Lock () 00141 { 00142 int32 currentThreadID = (int32)Implementation::GetCurrentThreadId (); 00143 if (!TryRecursiveLock (currentThreadID)) 00144 { 00145 mutex.Lock (); 00146 AtomicOperations::Set (&lockingThreadID, currentThreadID); 00147 recursionCount = 1; 00148 } 00149 return IsLocked (); 00150 } 00151 00152 bool TryLock () 00153 { 00154 int32 currentThreadID = (int32)Implementation::GetCurrentThreadId (); 00155 return TryRecursiveLock (currentThreadID) || 00156 TryNormalLock (currentThreadID); 00157 } 00158 00159 void Unlock () 00160 { 00161 if(!--recursionCount) 00162 { 00163 AtomicOperations::Set (&lockingThreadID, 0); 00164 mutex.Unlock (); 00165 } 00166 } 00167 00168 private: 00169 bool TryRecursiveLock (int32 currentThreadID) 00170 { 00171 if (AtomicOperations::Read (&lockingThreadID) == currentThreadID) 00172 { 00173 ++recursionCount; 00174 return true; 00175 } 00176 return false; 00177 } 00178 00179 bool TryNormalLock (int32 currentThreadID) 00180 { 00181 if (mutex.TryLock ()) 00182 { 00183 AtomicOperations::Set (&lockingThreadID, currentThreadID); 00184 recursionCount = 1; 00185 return true; 00186 } 00187 return false; 00188 } 00189 00190 MutexBase mutex; //Non-recursive base-mutex 00191 int32 recursionCount; 00192 int32 lockingThreadID; 00193 }; 00194 00195 } // namespace Implementation 00196 } // namespace Threading 00197 } // namespace CS 00198 00199 #endif // !defined(CS_PLATFORM_WIN32) 00200 00201 #endif // __CS_CSUTIL_THREADING_WIN32_MUTEX_H__
Generated for Crystal Space 1.4.0 by doxygen 1.5.8