summaryrefslogtreecommitdiff
path: root/depends/tthread/fast_mutex.h
diff options
context:
space:
mode:
Diffstat (limited to 'depends/tthread/fast_mutex.h')
-rw-r--r--depends/tthread/fast_mutex.h239
1 files changed, 239 insertions, 0 deletions
diff --git a/depends/tthread/fast_mutex.h b/depends/tthread/fast_mutex.h
new file mode 100644
index 00000000..b4e712f4
--- /dev/null
+++ b/depends/tthread/fast_mutex.h
@@ -0,0 +1,239 @@
+/*
+Copyright (c) 2010 Marcus Geelnard
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+*/
+
+#ifndef _FAST_MUTEX_H_
+#define _FAST_MUTEX_H_
+
+/// @file
+
+// Which platform are we on?
+#if !defined(_TTHREAD_PLATFORM_DEFINED_)
+ #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
+ #define _TTHREAD_WIN32_
+ #else
+ #define _TTHREAD_POSIX_
+ #endif
+ #define _TTHREAD_PLATFORM_DEFINED_
+#endif
+
+// Check if we can support the assembly language level implementation (otherwise
+// revert to the system API)
+#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \
+ (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || \
+ (defined(__GNUC__) && (defined(__ppc__)))
+ #define _FAST_MUTEX_ASM_
+#else
+ #define _FAST_MUTEX_SYS_
+#endif
+
+#if defined(_TTHREAD_WIN32_)
+ #include <windows.h>
+#else
+ #ifdef _FAST_MUTEX_ASM_
+ #include <sched.h>
+ #else
+ #include <pthread.h>
+ #endif
+#endif
+
+namespace tthread {
+
+/// Fast mutex class.
+/// This is a mutual exclusion object for synchronizing access to shared
+/// memory areas for several threads. It is similar to the tthread::mutex class,
+/// but instead of using system level functions, it is implemented as an atomic
+/// spin lock with very low CPU overhead.
+///
+/// The \c fast_mutex class is NOT compatible with the \c condition_variable
+/// class (however, it IS compatible with the \c lock_guard class). It should
+/// also be noted that the \c fast_mutex class typically does not provide
+/// as accurate thread scheduling as a the standard \c mutex class does.
+///
+/// Because of the limitations of the class, it should only be used in
+/// situations where the mutex needs to be locked/unlocked very frequently.
+///
+/// @note The "fast" version of this class relies on inline assembler language,
+/// which is currently only supported for 32/64-bit Intel x86/AMD64 and
+/// PowerPC architectures on a limited number of compilers (GNU g++ and MS
+/// Visual C++).
+/// For other architectures/compilers, system functions are used instead.
+class fast_mutex {
+ public:
+ /// Constructor.
+#if defined(_FAST_MUTEX_ASM_)
+ fast_mutex() : mLock(0) {}
+#else
+ fast_mutex()
+ {
+ #if defined(_TTHREAD_WIN32_)
+ InitializeCriticalSection(&mHandle);
+ #elif defined(_TTHREAD_POSIX_)
+ pthread_mutex_init(&mHandle, NULL);
+ #endif
+ }
+#endif
+
+#if !defined(_FAST_MUTEX_ASM_)
+ /// Destructor.
+ ~fast_mutex()
+ {
+ #if defined(_TTHREAD_WIN32_)
+ DeleteCriticalSection(&mHandle);
+ #elif defined(_TTHREAD_POSIX_)
+ pthread_mutex_destroy(&mHandle);
+ #endif
+ }
+#endif
+
+ /// Lock the mutex.
+ /// The method will block the calling thread until a lock on the mutex can
+ /// be obtained. The mutex remains locked until \c unlock() is called.
+ /// @see lock_guard
+ inline void lock()
+ {
+#if defined(_FAST_MUTEX_ASM_)
+ bool gotLock;
+ do {
+ gotLock = try_lock();
+ if(!gotLock)
+ {
+ #if defined(_TTHREAD_WIN32_)
+ Sleep(0);
+ #elif defined(_TTHREAD_POSIX_)
+ sched_yield();
+ #endif
+ }
+ } while(!gotLock);
+#else
+ #if defined(_TTHREAD_WIN32_)
+ EnterCriticalSection(&mHandle);
+ #elif defined(_TTHREAD_POSIX_)
+ pthread_mutex_lock(&mHandle);
+ #endif
+#endif
+ }
+
+ /// Try to lock the mutex.
+ /// The method will try to lock the mutex. If it fails, the function will
+ /// return immediately (non-blocking).
+ /// @return \c true if the lock was acquired, or \c false if the lock could
+ /// not be acquired.
+ inline bool try_lock()
+ {
+#if defined(_FAST_MUTEX_ASM_)
+ int oldLock;
+ #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ asm volatile (
+ "movl $1,%%eax\n\t"
+ "xchg %%eax,%0\n\t"
+ "movl %%eax,%1\n\t"
+ : "=m" (mLock), "=m" (oldLock)
+ :
+ : "%eax", "memory"
+ );
+ #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
+ int *ptrLock = &mLock;
+ __asm {
+ mov eax,1
+ mov ecx,ptrLock
+ xchg eax,[ecx]
+ mov oldLock,eax
+ }
+ #elif defined(__GNUC__) && (defined(__ppc__))
+ int newLock = 1;
+ asm volatile (
+ "\n1:\n\t"
+ "lwarx %0,0,%1\n\t"
+ "cmpwi 0,%0,0\n\t"
+ "bne- 2f\n\t"
+ "stwcx. %2,0,%1\n\t"
+ "bne- 1b\n\t"
+ "isync\n"
+ "2:\n\t"
+ : "=&r" (oldLock)
+ : "r" (&mLock), "r" (newLock)
+ : "cr0", "memory"
+ );
+ #endif
+ return (oldLock == 0);
+#else
+ #if defined(_TTHREAD_WIN32_)
+ return TryEnterCriticalSection(&mHandle) ? true : false;
+ #elif defined(_TTHREAD_POSIX_)
+ return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
+ #endif
+#endif
+ }
+
+ /// Unlock the mutex.
+ /// If any threads are waiting for the lock on this mutex, one of them will
+ /// be unblocked.
+ inline void unlock()
+ {
+#if defined(_FAST_MUTEX_ASM_)
+ #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ asm volatile (
+ "movl $0,%%eax\n\t"
+ "xchg %%eax,%0\n\t"
+ : "=m" (mLock)
+ :
+ : "%eax", "memory"
+ );
+ #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
+ int *ptrLock = &mLock;
+ __asm {
+ mov eax,0
+ mov ecx,ptrLock
+ xchg eax,[ecx]
+ }
+ #elif defined(__GNUC__) && (defined(__ppc__))
+ asm volatile (
+ "sync\n\t" // Replace with lwsync where possible?
+ : : : "memory"
+ );
+ mLock = 0;
+ #endif
+#else
+ #if defined(_TTHREAD_WIN32_)
+ LeaveCriticalSection(&mHandle);
+ #elif defined(_TTHREAD_POSIX_)
+ pthread_mutex_unlock(&mHandle);
+ #endif
+#endif
+ }
+
+ private:
+#if defined(_FAST_MUTEX_ASM_)
+ int mLock;
+#else
+ #if defined(_TTHREAD_WIN32_)
+ CRITICAL_SECTION mHandle;
+ #elif defined(_TTHREAD_POSIX_)
+ pthread_mutex_t mHandle;
+ #endif
+#endif
+};
+
+}
+
+#endif // _FAST_MUTEX_H_