Crystal Space: csutil/spinlock.h Source File (Crystal Space Public API Reference)

| ## Public API Reference

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# csutil/spinlock.h

Go to the documentation of this file.

    00001 /*
    00002     Copyright (C) 2006 by Frank Richter
    00003
    00004     This library is free software; you can redistribute it and/or
    00005     modify it under the terms of the GNU Library 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_SPINLOCK_H__
    00020 #define __CS_CSUTIL_SPINLOCK_H__
    00021
    00025 #ifndef CS_PLATFORM_WIN32
    00026 #include <pthread.h>
    00027 #include <sched.h>
    00028 #endif
    00029
    00033 namespace CS
    00034 {
    00035   class SpinLock
    00036   {
    00037   #ifdef CS_PLATFORM_WIN32
    00038     typedef DWORD ThreadID;
    00039   #else
    00040     typedef pthread_t ThreadID;
    00041   #endif
    00042   #if defined (CS_PROCESSOR_X86) && defined (CS_COMPILER_GCC)
    00043     volatile ThreadID threadid;
    00044     volatile uint l;
    00045   #elif defined(CS_PLATFORM_WIN32)
    00046     volatile ThreadID threadid;
    00047     volatile LONG l;
    00048   #else
    00049     pthread_mutex_t l;
    00050   #endif
    00051
    00052     volatile uint c;
    00053
    00054     static const int spinsPerYield = 63;
    00055
    00056   #if defined(CS_PLATFORM_WIN32)
    00057     CS_FORCEINLINE ThreadID CurrentThreadID()
    00058     { return GetCurrentThreadId(); }
    00059   #else
    00060     CS_FORCEINLINE ThreadID CurrentThreadID()
    00061     { return pthread_self(); }
    00062   #endif
    00063
    00064     // Spinlock implementation from ptmalloc3's malloc.c
    00065   #if defined (CS_PROCESSOR_X86) && defined (CS_COMPILER_GCC)
    00066     CS_FORCEINLINE bool DoLockWait()
    00067     {
    00068       ThreadID mythreadid = CurrentThreadID();
    00069       if(mythreadid == threadid)
    00070         ++c;
    00071       else
    00072       {
    00073         int spins = 0;
    00074         for (;;) {
    00075           int ret;
    00076           __asm__ __volatile__ ("lock; cmpxchgl %2,(%1)" : "=a" (ret) : "r" (&l), "r" (1), "a" (0));
    00077           if(!ret)
    00078           {
    00079             CS_ASSERT(!threadid);
    00080             threadid = mythreadid;
    00081             c = 1;
    00082             break;
    00083           }
    00084           if ((++spins & spinsPerYield) == 0) {
    00085     #if defined (__SVR4) && defined (__sun) /* solaris */
    00086             thr_yield();
    00087     #elif defined(linux) || defined(CS_PLATFORM_MACOSX)
    00088             sched_yield();
    00089     #elif defined(CS_PLATFORM_WIN32)
    00090             SleepEx (0, FALSE);
    00091     #else  /* no-op yield on unknown systems */
    00092             ;
    00093     #endif /* solaris, linux, CS_PLATFORM_MACOSX, CS_PLATFORM_WIN32 */
    00094           }
    00095         }
    00096       }
    00097       return true;
    00098     }
    00099     CS_FORCEINLINE bool DoLockTry()
    00100     {
    00101       int ret;
    00102       __asm__ __volatile__ ("lock; cmpxchgl %2,(%1)" : "=a" (ret) : "r" (&l), "r" (1), "a" (0));
    00103       if(!ret){
    00104         CS_ASSERT(!threadid);
    00105         threadid = CurrentThreadID();
    00106         c=1;
    00107         return true;
    00108       }
    00109       return false;
    00110     }
    00111     CS_FORCEINLINE void DoRelease()
    00112     {
    00113       int ret;
    00114       CS_ASSERT(CurrentThreadID() == threadid);
    00115       if (!--c) {
    00116         threadid=0;
    00117         __asm__ __volatile__ ("xchgl %2,(%1)" : "=r" (ret) : "r" (&l), "0" (0));
    00118       }
    00119     }
    00120     CS_FORCEINLINE void Init() { threadid = 0; c = 0; l = 0; }
    00121     CS_FORCEINLINE void Destroy() {}
    00122     //------------------------------------------------------------------------
    00123   #elif defined(CS_PLATFORM_WIN32)
    00124     CS_FORCEINLINE bool DoLockWait()
    00125     {
    00126       ThreadID mythreadid = CurrentThreadID();
    00127       if(mythreadid == threadid)
    00128         ++c;
    00129       else {
    00130         int spins = 0;
    00131         for (;;) {
    00132           if (!_InterlockedExchange(&l, 1)) {
    00133             CS_ASSERT(!threadid);
    00134             threadid = mythreadid;
    00135             c = 1;
    00136             break;
    00137           }
    00138           if ((++spins & spinsPerYield) == 0)
    00139             SleepEx (0, FALSE);
    00140         }
    00141       }
    00142       return true;
    00143     }
    00144     CS_FORCEINLINE bool DoLockTry()
    00145     {
    00146       if (!_InterlockedExchange (&l, 1)) {
    00147         CS_ASSERT (!threadid);
    00148         threadid = CurrentThreadID();
    00149         c = 1;
    00150         return true;
    00151       }
    00152       return false;
    00153     }
    00154     CS_FORCEINLINE void DoRelease()
    00155     {
    00156       CS_ASSERT (CurrentThreadID() == threadid);
    00157       if (!--c) {
    00158         threadid = 0;
    00159         _InterlockedExchange (&l, 0);
    00160       }
    00161     }
    00162     CS_FORCEINLINE void Init() { threadid = 0; c = 0; l = 0; }
    00163     CS_FORCEINLINE void Destroy() {}
    00164     //------------------------------------------------------------------------
    00165   #else
    00166     CS_FORCEINLINE bool DoLockWait()
    00167     {
    00168       if(!pthread_mutex_lock(&l)){
    00169         c++;
    00170         return true;
    00171       }
    00172       return false;
    00173     }
    00174     CS_FORCEINLINE bool DoLockTry()
    00175     {
    00176       if(!pthread_mutex_trylock(&l)){
    00177         c++;
    00178         return true;
    00179       }
    00180       return false;
    00181     }
    00182     CS_FORCEINLINE void DoRelease()
    00183     {
    00184        --c;
    00185       pthread_mutex_unlock(&l);
    00186     }
    00187     CS_FORCEINLINE void Init()
    00188     {
    00189       pthread_mutexattr_t attr;
    00190       c=0;
    00191       if(pthread_mutexattr_init (&attr)) return;
    00192       if(pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE)) return;
    00193       if(pthread_mutex_init (&l, &attr)) return;
    00194       pthread_mutexattr_destroy (&attr);
    00195     }
    00196     CS_FORCEINLINE void Destroy() {}
    00197 #endif
    00198   public:
    00199     SpinLock()
    00200     { Init(); }
    00201     ~SpinLock() { Destroy(); }
    00202
    00203     CS_FORCEINLINE bool LockWait()
    00204     { return DoLockWait(); }
    00205     CS_FORCEINLINE bool LockTry()
    00206     { return DoLockTry(); }
    00207     CS_FORCEINLINE void Release()
    00208     { DoRelease(); }
    00209   };
    00210 } // namespace CS
    00211
    00214 #endif // __CS_CSUTIL_SPINLOCK_H__