int_QMutexImpl.h

Go to the documentation of this file.
00001 /********************************************************************************
00002 *                                                                               *
00003 *                  FXAtomicInt and QMutex implementations                      *
00004 *                                                                               *
00005 *********************************************************************************
00006 *        Copyright (C) 2002-2005 by Niall Douglas.   All Rights Reserved.       *
00007 *       NOTE THAT I DO NOT PERMIT ANY OF MY CODE TO BE PROMOTED TO THE GPL      *
00008 *********************************************************************************
00009 * This code is free software; you can redistribute it and/or modify it under    *
00010 * the terms of the GNU Library General Public License v2.1 as published by the  *
00011 * Free Software Foundation EXCEPT that clause 3 does not apply ie; you may not  *
00012 * "upgrade" this code to the GPL without my prior written permission.           *
00013 * Please consult the file "License_Addendum2.txt" accompanying this file.       *
00014 *                                                                               *
00015 * This code is distributed in the hope that it will be useful,                  *
00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                          *
00018 *********************************************************************************
00019 * $Id:                                                                          *
00020 ********************************************************************************/
00021 
00022 #ifndef FXBEING_INCLUDED_BY_QTHREAD
00023 #error This file is not supposed to be included by public code
00024 #endif
00025 
00026 //#undef FX_SMPBUILD
00027 
00028 #include "FXErrCodes.h"
00029 #include "FXRollback.h"
00030 
00031 #ifdef FXDISABLE_THREADS
00032  #undef USE_WINAPI
00033  #undef USE_OURMUTEX
00034  #undef USE_X86
00035 #else
00036 // Decide which thread API to use
00037  #ifndef USE_POSIX
00038   #define USE_WINAPI
00039   #define USE_OURMUTEX
00040   #include "WindowsGubbins.h"
00041   #include <intrin.h>
00042  #endif
00043  #ifdef USE_POSIX
00044   // POSIX threads for the Unices
00045   #define __CLEANUP_C           // for pthreads_win32
00046   //#define USE_OURTHREADID // Define when pthread_self() is not unique across processes
00047   #include <semaphore.h>
00048   #include <pthread.h>
00049  #endif
00050 #endif
00051 
00052 #include <assert.h>
00053 
00054 // On Windows, always use our mutex implementation
00055 #ifdef USE_WINAPI
00056  #define USE_OURMUTEX
00057  #ifdef _MSC_VER
00058   // Use MSVC7.1 Intrinsics
00059   #pragma intrinsic (_InterlockedCompareExchange)
00060   #pragma intrinsic (_InterlockedExchange)
00061   #pragma intrinsic (_InterlockedExchangeAdd)
00062   #pragma intrinsic (_InterlockedIncrement)
00063   #pragma intrinsic (_InterlockedDecrement)
00064  #endif
00065 #else
00066  // On GCC, always use our mutex implementation
00067  #if defined(__GNUC__)
00068   #define USE_OURMUTEX
00069   #if (defined(__i386__) || defined(__x86_64__))
00070    #define USE_X86 FX_X86PROCESSOR                  // On x86 or x64, use inline assembler
00071   #else
00072    #include <bits/atomicity.h>
00073   #endif
00074  #endif
00075 #endif
00076 
00077 #ifndef USE_OURMUTEX
00078  #error Unsupported compiler, please add atomic int support to QThread.cxx
00079 #endif
00080 
00081 namespace FX {
00082 
00083 QMUTEX_INLINEI int FXAtomicInt::get() const throw()
00084 {
00085     return value;
00086 }
00087 QMUTEX_INLINEP FXAtomicInt::operator int() const throw() { return get(); }
00088 QMUTEX_INLINEI int FXAtomicInt::set(int i) throw()
00089 {   // value=i; is write-buffered out and we need it immediate
00090 #ifdef __GNUC__
00091     int d;
00092 #ifdef USE_X86
00093     __asm__ __volatile__ ("xchgl %2,(%1)" : "=r" (d) : "r" (&value), "0" (i));
00094 #else
00095     while(__gnu_cxx::__exchange_and_add((_Atomic_word *) &lock, 1)) __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00096     value=i;
00097     __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00098 #endif
00099 #elif defined(USE_WINAPI)
00100     _InterlockedExchange((PLONG) &value, i);
00101 #endif
00102     return i;
00103 }
00104 QMUTEX_INLINEP int FXAtomicInt::operator=(int i) throw() { return set(i); }
00105 QMUTEX_INLINEI int FXAtomicInt::incp() throw()
00106 {
00107 #ifdef __GNUC__
00108     int myret;
00109 #ifdef USE_X86
00110     __asm__ __volatile__ (
00111 #ifdef FX_SMPBUILD
00112         "lock/xaddl %2,(%1)"
00113 #else
00114         "xaddl %2,(%1)"
00115 #endif
00116         : "=a" (myret) : "r" (&value), "a" (1));
00117 #else
00118     while(__gnu_cxx::__exchange_and_add((_Atomic_word *) &lock, 1)) __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00119     myret=value++;
00120     __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00121 #endif
00122     return myret;
00123 #elif defined(USE_WINAPI)
00124     return _InterlockedExchangeAdd((PLONG) &value, 1);
00125 #endif
00126 }
00127 QMUTEX_INLINEP int FXAtomicInt::operator++(int) throw() { return incp(); }
00128 QMUTEX_INLINEI int FXAtomicInt::pinc() throw()
00129 {
00130 #ifdef __GNUC__
00131     int myret;
00132 #ifdef USE_X86
00133     __asm__ __volatile__ (
00134 #ifdef FX_SMPBUILD
00135         "lock/xaddl %2,(%1)\n\tinc %%eax"
00136 #else
00137         "xaddl %2,(%1)\n\tinc %%eax"
00138 #endif
00139         : "=a" (myret) : "r" (&value), "a" (1));
00140 #else
00141     while(__gnu_cxx::__exchange_and_add((_Atomic_word *) &lock, 1)) __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00142     myret=++value;
00143     __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00144 #endif
00145     return myret;
00146 #elif defined(USE_WINAPI)
00147     return _InterlockedIncrement((PLONG) &value);
00148 #endif
00149 }
00150 QMUTEX_INLINEP int FXAtomicInt::operator++() throw() { return pinc(); }
00151 QMUTEX_INLINEI int FXAtomicInt::finc() throw()
00152 {   // Returns -1, 0, +1 on value AFTER inc
00153 #ifdef __GNUC__
00154     int myret;
00155 #if defined(USE_X86)
00156     __asm__ __volatile__ (
00157 #ifdef FX_SMPBUILD
00158         "lock/incl (%1)\n"
00159 #else
00160         "incl (%1)\n"
00161 #endif
00162         "\tjl 1f\n\tjg 2f\n"
00163         "\tmov $0, %%eax\n\tjmp 3f\n"
00164         "1:\tmov $-1, %%eax\n\tjmp 3f\n"
00165         "2:\tmov $1, %%eax\n"
00166         "3:\n"
00167         : "=a" (myret) : "r" (&value));
00168 #else
00169     return pinc();
00170 #endif
00171     return myret;
00172 #else
00173     return pinc();
00174 #endif
00175 }
00176 QMUTEX_INLINEP int FXAtomicInt::fastinc() throw() { return finc(); }
00177 QMUTEX_INLINEI int FXAtomicInt::inc(int i) throw()
00178 {
00179 #ifdef __GNUC__
00180     int myret;
00181 #ifdef USE_X86
00182     __asm__ __volatile__ (
00183 #ifdef FX_SMPBUILD
00184         "lock/xaddl %2,(%1)"
00185 #else
00186         "xaddl %2,(%1)"
00187 #endif
00188         : "=a" (myret) : "r" (&value), "a" (i));
00189 #else
00190     while(__gnu_cxx::__exchange_and_add((_Atomic_word *) &lock, 1)) __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00191     myret=(value+=i);
00192     __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00193 #endif
00194     return myret+i;
00195 #elif defined(USE_WINAPI)
00196     return _InterlockedExchangeAdd((PLONG) &value, i)+i;
00197 #endif
00198 }
00199 QMUTEX_INLINEP int FXAtomicInt::operator+=(int i) throw() { return inc(i); }
00200 QMUTEX_INLINEI int FXAtomicInt::decp() throw()
00201 {
00202 #ifdef __GNUC__
00203     int myret;
00204 #ifdef USE_X86
00205     __asm__ __volatile__ (
00206 #ifdef FX_SMPBUILD
00207         "lock/xaddl %2,(%1)"
00208 #else
00209         "xaddl %2,(%1)"
00210 #endif
00211         : "=a" (myret) : "r" (&value), "a" (-1));
00212 #else
00213     while(__gnu_cxx::__exchange_and_add((_Atomic_word *) &lock, 1)) __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00214     myret=value--;
00215     __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00216 #endif
00217     return myret;
00218 #elif defined(USE_WINAPI)
00219     return _InterlockedExchangeAdd((PLONG) &value, -1);
00220 #endif
00221 }
00222 QMUTEX_INLINEP int FXAtomicInt::operator--(int) throw() { return decp(); }
00223 QMUTEX_INLINEI int FXAtomicInt::pdec() throw()
00224 {
00225 #ifdef __GNUC__
00226     int myret;
00227 #ifdef USE_X86
00228     __asm__ __volatile__ (
00229 #ifdef FX_SMPBUILD
00230         "lock/xaddl %2,(%1)\n\tdec %%eax"
00231 #else
00232         "xaddl %2,(%1)\n\tdec %%eax"
00233 #endif
00234         : "=a" (myret) : "r" (&value), "a" (-1));
00235 #else
00236     while(__gnu_cxx::__exchange_and_add((_Atomic_word *) &lock, 1)) __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00237     myret=--value;
00238     __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00239 #endif
00240     return myret;
00241 #elif defined(USE_WINAPI)
00242     return _InterlockedDecrement((PLONG) &value);
00243 #endif
00244 }
00245 QMUTEX_INLINEP int FXAtomicInt::operator--() throw() { return pdec(); }
00246 QMUTEX_INLINEI int FXAtomicInt::fdec() throw()
00247 {   // Returns -1, 0, +1 on value AFTER inc
00248 #ifdef __GNUC__
00249     int myret;
00250 #if defined(USE_X86)
00251     __asm__ __volatile__ (
00252 #ifdef FX_SMPBUILD
00253         "lock/decl (%1)\n"
00254 #else
00255         "decl (%1)\n"
00256 #endif
00257         "\tjl 1f\n\tjg 2f\n"
00258         "\tmov $0, %%eax\n\tjmp 3f\n"
00259         "1:\tmov $-1, %%eax\n\tjmp 3f\n"
00260         "2:\tmov $1, %%eax\n"
00261         "3:\n"
00262         : "=a" (myret) : "r" (&value));
00263 #else
00264     return pdec();
00265 #endif
00266     return myret;
00267 #else
00268     return pdec();
00269 #endif
00270 }
00271 QMUTEX_INLINEP int FXAtomicInt::fastdec() throw() { return fdec(); }
00272 QMUTEX_INLINEI int FXAtomicInt::dec(int i) throw()
00273 {
00274 #ifdef __GNUC__
00275     int myret;
00276     i=-i;
00277 #ifdef USE_X86
00278     __asm__ __volatile__ (
00279 #ifdef FX_SMPBUILD
00280         "lock/xaddl %2,(%1)"
00281 #else
00282         "xaddl %2,(%1)"
00283 #endif
00284         : "=a" (myret) : "r" (&value), "a" (i));
00285 #else
00286     while(__gnu_cxx::__exchange_and_add((_Atomic_word *) &lock, 1)) __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00287     myret=(value-=i);
00288     __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00289 #endif
00290     return myret+i;
00291 #elif defined(USE_WINAPI)
00292     return _InterlockedExchangeAdd((PLONG) &value, -i)-i;
00293 #endif
00294 }
00295 QMUTEX_INLINEP int FXAtomicInt::operator-=(int i) throw() { return dec(i); }
00296 QMUTEX_INLINEI int FXAtomicInt::swapI(int i) throw()
00297 {
00298 #ifdef __GNUC__
00299     int myret;
00300 #ifdef USE_X86
00301     __asm__ __volatile__ ("xchgl %2,(%1)" : "=r" (myret) : "r" (&value), "0" (i));
00302 #else
00303     while(__gnu_cxx::__exchange_and_add((_Atomic_word *) &lock, 1)) __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00304     myret=value;
00305     value=i;
00306     __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00307 #endif
00308     return myret;
00309 #elif defined(USE_WINAPI)
00310     return _InterlockedExchange((PLONG) &value, i);
00311 #endif
00312 }
00313 QMUTEX_INLINEP int FXAtomicInt::swap(int i) throw() { return swapI(i); }
00314 QMUTEX_INLINEI int FXAtomicInt::cmpXI(int compare, int newval) throw()
00315 {
00316 #ifdef __GNUC__
00317     int myret;
00318 #ifdef USE_X86
00319     __asm__ __volatile__ (
00320 #ifdef FX_SMPBUILD
00321         "pause\n\tlock/cmpxchgl %2,(%1)"
00322 #else
00323         "pause\n\tcmpxchgl %2,(%1)"
00324 #endif
00325         : "=a" (myret) : "r" (&value), "r" (newval), "a" (compare));
00326 #else
00327     while(__gnu_cxx::__exchange_and_add((_Atomic_word *) &lock, 1)) __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00328     myret=value;
00329     if(value==compare)
00330         value=newval;
00331     __gnu_cxx::__atomic_add((_Atomic_word *) &lock, -1);
00332 #endif
00333     return myret;
00334 #elif defined(USE_WINAPI)
00335     return _InterlockedCompareExchange((PLONG) &value, newval, compare);
00336 #endif
00337 }
00338 QMUTEX_INLINEP int FXAtomicInt::cmpX(int compare, int newval) throw() { return cmpXI(compare, newval); }
00339 #if 0
00340 /* Optimised spin just for QMutex. This implementation avoids
00341 costly xchg instructions which are very expensive on the x86 memory
00342 bus as they effectively hang multiprocessing */
00343 QMUTEX_INLINEI int FXAtomicInt::spinI(int count) throw()
00344 {
00345     int myret;
00346 #ifdef USE_X86
00347 #ifdef __GNUC__
00348 #error todo
00349     __asm__ __volatile__ (
00350 #ifdef FX_SMPBUILD
00351         "pause\n\tlock/cmpxchgl %2,(%1)"
00352 #else
00353         "pause\n\tcmpxchgl %2,(%1)"
00354 #endif
00355         : "=a" (myret) : "r" (&value), "r" (newval), "a" (compare));
00356 #endif
00357     return myret;
00358 #elif defined(USE_WINAPI)
00359     for(int n=0; n<count && (myret=_InterlockedExchange((PLONG) &value, 1)); n++)
00360     return myret;
00361 #endif
00362 }
00363 #endif
00364 
00365 /**************************************************************************************************************/
00366 
00367 QMUTEX_INLINEP void QShrdMemMutex::lock()
00368 {
00369     FXuint start=!timeout ? 0 : FXProcess::getMsCount();
00370     while(lockvar.swapI(1) && (!timeout || FXProcess::getMsCount()-start<timeout-1))
00371 #ifndef FX_SMPBUILD
00372         QThread::yield()
00373 #endif
00374         ;
00375 }
00376 
00377 QMUTEX_INLINEP bool QShrdMemMutex::tryLock() throw()
00378 {
00379     return !lockvar.swapI(1);
00380 }
00381 
00382 /**************************************************************************************************************/
00383 
00384 #ifndef FXDISABLE_THREADS
00385 namespace QMutexImpl {
00386 
00387 /* On POSIX, a more efficient mutex is one which avoids calling the kernel.
00388 If MUTEX_USESEMA is defined, it uses a POSIX semaphore like an OS/2 event to
00389 signal waiting threads when the holder is done - unfortunately, only sem_post()
00390 is legal from a cleanup/signal handler, not sem_wait(). Linux is happy with
00391 this, FreeBSD is not and must use a real POSIX mutex - nevertheless, we still
00392 save on recursion overheads and get spin counts.
00393 */
00394 #if !defined(__FreeBSD__) && !defined(__APPLE__)
00395 #define MUTEX_USESEMA
00396 #endif
00397 
00398 /* 23rd June 2004 ned: Testing shows that a lot of the cost of using QMutex is
00399 creating and deleting the kernel wait object. Therefore cache instances here.
00400 */
00401 class FXDLLLOCAL KernelWaitObjectCache
00402 {
00403     QShrdMemMutex lockvar;
00404 public:
00405 #ifdef USE_WINAPI
00406     typedef HANDLE WaitObjectType;
00407 #endif
00408 #ifdef USE_POSIX
00409 #ifdef MUTEX_USESEMA
00410     typedef sem_t WaitObjectType;
00411 #else
00412     typedef pthread_mutex_t WaitObjectType;
00413 #endif
00414 #endif
00415     struct Entry
00416     {
00417         WaitObjectType wo;
00418         Entry *next;
00419     };
00420 private:
00421     Entry *entries;
00422     QMUTEX_INLINEI void lock() throw() { lockvar.lock(); }
00423     QMUTEX_INLINEI void unlock() throw() { lockvar.unlock(); }
00424 public:
00425     bool dead;
00426     KernelWaitObjectCache() : lockvar(FXINFINITE) { }
00427     ~KernelWaitObjectCache()
00428     {
00429         lock();
00430         FXRBOp undolock=FXRBObj(*this, &KernelWaitObjectCache::unlock);
00431         while(entries)
00432         {
00433 #ifdef USE_WINAPI
00434             FXERRHWIN(CloseHandle(entries->wo));
00435 #endif
00436 #ifdef USE_POSIX
00437 #ifdef MUTEX_USESEMA
00438             FXERRHOS(sem_destroy(&entries->wo));
00439 #else
00440             FXERRHOS(pthread_mutex_destroy(&entries->wo));
00441 #endif
00442 #endif
00443             Entry *e=entries;
00444             entries=e->next;
00445             FXDELETE(e);
00446         }
00447         dead=true;
00448     }
00449     Entry *fetch() throw()
00450     {
00451         if(!entries) return 0;
00452         lock();
00453         if(!entries)
00454         {
00455             unlock();
00456             return 0;
00457         }
00458         Entry *ret=entries;
00459         entries=entries->next;
00460         unlock();
00461         return ret;
00462     }
00463     void addFreed(Entry *e) throw()
00464     {
00465         if(dead)
00466             delete e;
00467         else
00468         {
00469             lock();
00470             e->next=entries;
00471             entries=e;
00472             unlock();
00473         }
00474     }
00475 };
00476 extern QMUTEX_GLOBALS_FXAPI KernelWaitObjectCache waitObjectCache;
00477 extern QMUTEX_GLOBALS_FXAPI bool yieldAfterLock;
00478 extern QMUTEX_GLOBALS_FXAPI FXuint systemProcessors;
00479 
00480 } // namespace QMutexImpl
00481 #endif
00482 
00483 struct FXDLLLOCAL QMutexPrivate
00484 {
00485 #ifndef FXDISABLE_THREADS
00486 #ifdef USE_OURMUTEX
00487     FXAtomicInt lockCount, wakeSema;
00488     FXulong threadId;
00489     FXuint recurseCount, spinCount;
00490 #ifdef USE_WINAPI
00491     QMutexImpl::KernelWaitObjectCache::Entry *wc;
00492 #endif
00493 #ifdef USE_POSIX
00494     QMutexImpl::KernelWaitObjectCache::Entry *sema;
00495 #endif
00496 #elif defined(USE_POSIX)
00497     QMutexImpl::KernelWaitObjectCache::Entry *m;
00498 #endif
00499 #endif
00500 };
00501 
00502 QMUTEX_INLINEP QMutex::QMutex(FXuint spinc) : p(0)
00503 {
00504     FXRBOp unconstr=FXRBConstruct(this);
00505     FXERRHM(p=new QMutexPrivate);
00506 #ifndef FXDISABLE_THREADS
00507 #ifdef USE_OURMUTEX
00508     p->lockCount.set(-1);
00509     p->wakeSema.set(0);
00510     p->threadId=p->recurseCount=0;
00511     if(!QMutexImpl::systemProcessors)
00512         QMutexImpl::systemProcessors=FXProcess::noOfProcessors();
00513     p->spinCount=spinc; //(systemProcessors>1) ? spinc : 0;
00514 #ifdef USE_WINAPI
00515     if(!(p->wc=QMutexImpl::waitObjectCache.fetch()))
00516     {
00517         FXERRHM(p->wc=new QMutexImpl::KernelWaitObjectCache::Entry);
00518         FXRBOp unwc=FXRBNew(p->wc);
00519         FXERRHWIN(p->wc->wo=CreateEvent(NULL, FALSE, FALSE, NULL));
00520         unwc.dismiss();
00521     }
00522 #endif
00523 #ifdef USE_POSIX
00524 #ifdef MUTEX_USESEMA
00525     if(!(p->sema=QMutexImpl::waitObjectCache.fetch()))
00526     {
00527         FXERRHM(p->sema=new QMutexImpl::KernelWaitObjectCache::Entry);
00528         FXRBOp unsema=FXRBNew(p->sema);
00529         FXERRHOS(sem_init(&p->sema->wo, 0, 0));
00530         unsema.dismiss();
00531     }
00532 #else
00533     if(!(p->sema=QMutexImpl::waitObjectCache.fetch()))
00534     {
00535         FXERRHM(p->sema=new QMutexImpl::KernelWaitObjectCache::Entry);
00536         FXRBOp unsema=FXRBNew(p->sema);
00537         FXERRHOS(pthread_mutex_init(&p->sema->wo, NULL));
00538         unsema.dismiss();
00539     }
00540 #endif
00541 #endif
00542 #elif defined(USE_POSIX)
00543     pthread_mutexattr_t mattr;
00544     FXERRHOS(pthread_mutexattr_init(&mattr));
00545     FXERRHOS(pthread_mutexattr_setkind_np(&mattr, PTHREAD_MUTEX_RECURSIVE_NP));
00546     if(!(p->m=waitObjectCache.fetch()))
00547     {
00548         FXERRHM(p->m=new KernelWaitObjectCache::Entry);
00549         FXRBOp unm=FXRBNew(p->m);
00550         FXERRHOS(pthread_mutex_init(&p->m->wo, &mattr));
00551         unm.dismiss();
00552     }
00553     FXERRHOS(pthread_mutexattr_destroy(&mattr));
00554 #endif
00555 #endif
00556     unconstr.dismiss();
00557 }
00558 
00559 QMUTEX_INLINEP QMutex::~QMutex()
00560 { FXEXCEPTIONDESTRUCT1 {
00561     if(p)
00562     {   // Force exception if something else uses us after now
00563         QMutexPrivate *_p=p;
00564         p=0;
00565 #ifndef FXDISABLE_THREADS
00566 #ifdef USE_OURMUTEX
00567 #ifdef USE_WINAPI
00568         if(_p->wc && _p->wc->wo)
00569         {
00570             FXERRHWIN(ResetEvent(_p->wc->wo));
00571             QMutexImpl::waitObjectCache.addFreed(_p->wc);
00572             _p->wc=0;
00573         }
00574 #endif
00575 #ifdef USE_POSIX
00576         if(_p->sema)
00577         {
00578             QMutexImpl::waitObjectCache.addFreed(_p->sema);
00579             _p->sema=0;
00580         }
00581 #endif
00582 #elif defined(USE_POSIX)
00583         if(_p->m)
00584         {
00585             QMutexImpl::waitObjectCache.addFreed(_p->m);
00586             p->m=0;
00587         }
00588 #endif
00589 #endif
00590         FXDELETE(_p);
00591     }
00592 } FXEXCEPTIONDESTRUCT2; }
00593 
00594 QMUTEX_INLINEP bool QMutex::isLocked() const
00595 {
00596 #ifndef FXDISABLE_THREADS
00597     return p->lockCount>=0;
00598 #else
00599     return false;
00600 #endif
00601 }
00602 
00603 QMUTEX_INLINEP FXuint QMutex::spinCount() const
00604 {
00605 #ifndef FXDISABLE_THREADS
00606 #ifdef USE_OURMUTEX
00607     return p->spinCount;
00608 #else
00609     return 0;
00610 #endif
00611 #else
00612     return 0;
00613 #endif
00614 }
00615 
00616 QMUTEX_INLINEP void QMutex::setSpinCount(FXuint c)
00617 {
00618 #ifndef FXDISABLE_THREADS
00619 #ifdef USE_OURMUTEX
00620     p->spinCount=c;
00621 #endif
00622 #endif
00623 }
00624 
00625 QMUTEX_INLINEI void QMutex::int_lock()
00626 {
00627     assert(this);
00628     assert(p);
00629     if(!p) return;
00630 #ifndef FXDISABLE_THREADS
00631 #ifdef USE_OURMUTEX
00632     FXulong myid=QThread::id();
00633     if(!p->lockCount.finc())
00634     {   // Nothing owns me
00635         assert(p->threadId==0);
00636         assert(p->recurseCount==0);
00637         p->threadId=myid;
00638         p->recurseCount=1;
00639     }
00640     else
00641     {
00642         if(p->threadId==myid)
00643         {   // Recurse
00644             p->recurseCount++;
00645         }
00646         else
00647         {   // Spin & Wait
00648 #if 0
00649             // In theory this implementation is meant to be faster, but it wasn't on my
00650             // dual Athlon :(
00651             int gotit;
00652             while(!(gotit=p->wakeSema.swapI(0)))
00653             {
00654                 gotit=p->wakeSema.spinI(p->spinCount*3);
00655 #else
00656             int gotit;
00657             while(!(gotit=p->wakeSema.swapI(0)))
00658             {
00659                 for(FXuint n=0; n<p->spinCount; n++)
00660                 {
00661                     if(1==QMutexImpl::systemProcessors)
00662                     {   // Always give up remaining time slice on uniprocessor machines
00663 #ifdef USE_WINAPI
00664                         Sleep(0);
00665 #endif
00666 #ifdef USE_POSIX
00667                         sched_yield();
00668 #endif
00669                     }
00670                     if((gotit=p->wakeSema.swapI(0)))
00671                     {
00672                         break;
00673                     }
00674                 }
00675 #endif
00676                 if(gotit)
00677                     break;
00678                 else
00679                 {   // Ok, then wait on kernel
00680 #ifdef USE_WINAPI
00681                     WaitForSingleObject(p->wc->wo, INFINITE);
00682 #endif
00683 #if defined(USE_POSIX) && defined(MUTEX_USESEMA)
00684                     QThread *c=QThread::current();
00685                     if(c) c->disableTermination();
00686                     sem_wait(&p->sema->wo);
00687                     if(c) c->enableTermination();
00688 #endif
00689                 }
00690             }
00691 #if defined(USE_POSIX) && !defined(MUTEX_USESEMA)
00692             pthread_mutex_lock(&p->sema->wo);
00693 #endif
00694             //fxmessage(FXString("%1 %6 lock lc=%2, rc=%3, kc=%4, ti=%5\n").arg(QThread::id(),0, 16).arg(p->lockCount).arg(p->recurseCount).arg(p->kernelCount).arg(p->threadId, 0, 16).arg((FXuint)this,0,16).text());
00695             {   // Nothing owns me
00696                 assert(p->threadId==0);
00697                 p->threadId=myid;
00698                 assert(p->recurseCount==0);
00699                 p->recurseCount=1;
00700             }
00701         }
00702     }
00703 #elif defined(USE_POSIX)
00704     FXERRHOS(pthread_mutex_lock(&p->m->wo));
00705 #endif
00706     if(QMutexImpl::yieldAfterLock) QThread::yield();
00707 #endif
00708 }
00709 QMUTEX_INLINEP void QMutex::lock() { int_lock(); }
00710 
00711 QMUTEX_INLINEI void QMutex::int_unlock()
00712 {
00713     assert(this);
00714     assert(p);
00715     if(!p) return;
00716 #ifndef FXDISABLE_THREADS
00717 #ifdef USE_OURMUTEX
00718     if(--p->recurseCount>0)
00719     {
00720         assert(p->recurseCount<0x80000000);     // Someone unlocked when not already locked
00721         p->lockCount.fdec();
00722     }
00723     else
00724     {
00725 #ifdef DEBUG
00726         FXulong myid=QThread::id(); // For debug knowledge only
00727         if(myid && p->threadId)
00728             FXERRH(QThread::id()==p->threadId, "QMutex::unlock() performed by thread which did not own mutex", QMUTEX_BADUNLOCK, FXERRH_ISDEBUG);
00729 #endif
00730         p->threadId=0;
00731         //fxmessage(FXString("%1 %6 unlock lc=%2, rc=%3, kc=%4, ti=%5\n").arg(QThread::id(),0, 16).arg(p->lockCount).arg(p->recurseCount).arg(p->kernelCount).arg(p->threadId, 0, 16).arg((FXuint)this,0,16).text());
00732         if(p->lockCount.fdec()>=0)
00733         {   // Others waiting
00734             p->wakeSema.set(1); // Wake either a spinner or sleeper
00735 #ifdef USE_WINAPI
00736             SetEvent(p->wc->wo);// Wake one sleeper
00737 #endif
00738 #if defined(USE_POSIX) && defined(MUTEX_USESEMA)
00739             sem_post(&p->sema->wo);
00740 #endif
00741         }
00742 #if defined(USE_POSIX) && !defined(MUTEX_USESEMA)
00743         pthread_mutex_unlock(&p->sema->wo);
00744 #endif
00745     }
00746 #elif defined(USE_POSIX)
00747     FXERRHOS(pthread_mutex_unlock(&p->m->wo));
00748 #endif
00749 #endif
00750 }
00751 QMUTEX_INLINEP void QMutex::unlock() { int_unlock(); }
00752 
00753 QMUTEX_INLINEP bool QMutex::tryLock()
00754 {
00755 #ifndef FXDISABLE_THREADS
00756 #ifdef USE_OURMUTEX
00757     FXulong myid=QThread::id();
00758     if(!p->lockCount.finc())
00759     {   // Nothing owns me
00760         assert(p->threadId==0);
00761         p->threadId=myid;
00762         p->recurseCount=1;
00763         return true;
00764     }
00765     else
00766     {   // Restore
00767         if(p->threadId==myid)
00768         {   // Recurse
00769             p->recurseCount++;
00770             return true;
00771         }
00772         // Restore
00773         p->lockCount.fdec();
00774         return false;
00775     }
00776 #elif defined(USE_POSIX)
00777 
00778     if(0==pthread_mutex_trylock(&p->m->wo))
00779         return true;
00780     else
00781         return false;
00782 #endif
00783 #endif
00784 }
00785 
00786 QMUTEX_INLINEP bool QMutex::setMutexDebugYield(bool v)
00787 {
00788 #ifndef FXDISABLE_THREADS
00789     bool old=QMutexImpl::yieldAfterLock;
00790     QMutexImpl::yieldAfterLock=v;
00791     return old;
00792 #endif
00793 }
00794 
00795 }

(C) 2002-2009 Niall Douglas. Some parts (C) to assorted authors.
Generated on Fri Nov 20 18:31:25 2009 for TnFOX by doxygen v1.4.7