TinyThread++ 1.1
fast_mutex.h
Go to the documentation of this file.
00001 /* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
00002 Copyright (c) 2010-2012 Marcus Geelnard
00003 
00004 This software is provided 'as-is', without any express or implied
00005 warranty. In no event will the authors be held liable for any damages
00006 arising from the use of this software.
00007 
00008 Permission is granted to anyone to use this software for any purpose,
00009 including commercial applications, and to alter it and redistribute it
00010 freely, subject to the following restrictions:
00011 
00012     1. The origin of this software must not be misrepresented; you must not
00013     claim that you wrote the original software. If you use this software
00014     in a product, an acknowledgment in the product documentation would be
00015     appreciated but is not required.
00016 
00017     2. Altered source versions must be plainly marked as such, and must not be
00018     misrepresented as being the original software.
00019 
00020     3. This notice may not be removed or altered from any source
00021     distribution.
00022 */
00023 
00024 #ifndef _FAST_MUTEX_H_
00025 #define _FAST_MUTEX_H_
00026 
00028 
00029 // Which platform are we on?
00030 #if !defined(_TTHREAD_PLATFORM_DEFINED_)
00031   #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
00032     #define _TTHREAD_WIN32_
00033   #else
00034     #define _TTHREAD_POSIX_
00035   #endif
00036   #define _TTHREAD_PLATFORM_DEFINED_
00037 #endif
00038 
00039 // Check if we can support the assembly language level implementation (otherwise
00040 // revert to the system API)
00041 #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \
00042     (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || \
00043     (defined(__GNUC__) && (defined(__ppc__)))
00044   #define _FAST_MUTEX_ASM_
00045 #else
00046   #define _FAST_MUTEX_SYS_
00047 #endif
00048 
00049 #if defined(_TTHREAD_WIN32_)
00050   #ifndef WIN32_LEAN_AND_MEAN
00051     #define WIN32_LEAN_AND_MEAN
00052     #define __UNDEF_LEAN_AND_MEAN
00053   #endif
00054   #include <windows.h>
00055   #ifdef __UNDEF_LEAN_AND_MEAN
00056     #undef WIN32_LEAN_AND_MEAN
00057     #undef __UNDEF_LEAN_AND_MEAN
00058   #endif
00059 #else
00060   #ifdef _FAST_MUTEX_ASM_
00061     #include <sched.h>
00062   #else
00063     #include <pthread.h>
00064   #endif
00065 #endif
00066 
00067 namespace tthread {
00068 
00088 class fast_mutex {
00089   public:
00091 #if defined(_FAST_MUTEX_ASM_)
00092     fast_mutex() : mLock(0) {}
00093 #else
00094     fast_mutex()
00095     {
00096   #if defined(_TTHREAD_WIN32_)
00097       InitializeCriticalSection(&mHandle);
00098   #elif defined(_TTHREAD_POSIX_)
00099       pthread_mutex_init(&mHandle, NULL);
00100   #endif
00101     }
00102 #endif
00103 
00104 #if !defined(_FAST_MUTEX_ASM_)
00105 
00106     ~fast_mutex()
00107     {
00108   #if defined(_TTHREAD_WIN32_)
00109       DeleteCriticalSection(&mHandle);
00110   #elif defined(_TTHREAD_POSIX_)
00111       pthread_mutex_destroy(&mHandle);
00112   #endif
00113     }
00114 #endif
00115 
00120     inline void lock()
00121     {
00122 #if defined(_FAST_MUTEX_ASM_)
00123       bool gotLock;
00124       do {
00125         gotLock = try_lock();
00126         if(!gotLock)
00127         {
00128   #if defined(_TTHREAD_WIN32_)
00129           Sleep(0);
00130   #elif defined(_TTHREAD_POSIX_)
00131           sched_yield();
00132   #endif
00133         }
00134       } while(!gotLock);
00135 #else
00136   #if defined(_TTHREAD_WIN32_)
00137       EnterCriticalSection(&mHandle);
00138   #elif defined(_TTHREAD_POSIX_)
00139       pthread_mutex_lock(&mHandle);
00140   #endif
00141 #endif
00142     }
00143 
00149     inline bool try_lock()
00150     {
00151 #if defined(_FAST_MUTEX_ASM_)
00152       int oldLock;
00153   #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
00154       asm volatile (
00155         "movl $1,%%eax\n\t"
00156         "xchg %%eax,%0\n\t"
00157         "movl %%eax,%1\n\t"
00158         : "=m" (mLock), "=m" (oldLock)
00159         :
00160         : "%eax", "memory"
00161       );
00162   #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
00163       int *ptrLock = &mLock;
00164       __asm {
00165         mov eax,1
00166         mov ecx,ptrLock
00167         xchg eax,[ecx]
00168         mov oldLock,eax
00169       }
00170   #elif defined(__GNUC__) && (defined(__ppc__))
00171       int newLock = 1;
00172       asm volatile (
00173         "\n1:\n\t"
00174         "lwarx  %0,0,%1\n\t"
00175         "cmpwi  0,%0,0\n\t"
00176         "bne-   2f\n\t"
00177         "stwcx. %2,0,%1\n\t"
00178         "bne-   1b\n\t"
00179         "isync\n"
00180         "2:\n\t"
00181         : "=&r" (oldLock)
00182         : "r" (&mLock), "r" (newLock)
00183         : "cr0", "memory"
00184       );
00185   #endif
00186       return (oldLock == 0);
00187 #else
00188   #if defined(_TTHREAD_WIN32_)
00189       return TryEnterCriticalSection(&mHandle) ? true : false;
00190   #elif defined(_TTHREAD_POSIX_)
00191       return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
00192   #endif
00193 #endif
00194     }
00195 
00199     inline void unlock()
00200     {
00201 #if defined(_FAST_MUTEX_ASM_)
00202   #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
00203       asm volatile (
00204         "movl $0,%%eax\n\t"
00205         "xchg %%eax,%0\n\t"
00206         : "=m" (mLock)
00207         :
00208         : "%eax", "memory"
00209       );
00210   #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
00211       int *ptrLock = &mLock;
00212       __asm {
00213         mov eax,0
00214         mov ecx,ptrLock
00215         xchg eax,[ecx]
00216       }
00217   #elif defined(__GNUC__) && (defined(__ppc__))
00218       asm volatile (
00219         "sync\n\t"  // Replace with lwsync where possible?
00220         : : : "memory"
00221       );
00222       mLock = 0;
00223   #endif
00224 #else
00225   #if defined(_TTHREAD_WIN32_)
00226       LeaveCriticalSection(&mHandle);
00227   #elif defined(_TTHREAD_POSIX_)
00228       pthread_mutex_unlock(&mHandle);
00229   #endif
00230 #endif
00231     }
00232 
00233   private:
00234 #if defined(_FAST_MUTEX_ASM_)
00235     int mLock;
00236 #else
00237   #if defined(_TTHREAD_WIN32_)
00238     CRITICAL_SECTION mHandle;
00239   #elif defined(_TTHREAD_POSIX_)
00240     pthread_mutex_t mHandle;
00241   #endif
00242 #endif
00243 };
00244 
00245 }
00246 
00247 #endif // _FAST_MUTEX_H_
00248