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