CrystalSpace

Public API Reference

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.7.6.1