00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef QTHREAD_H
00023 #define QTHREAD_H
00024
00025 #include "FXProcess.h"
00026
00027 namespace FX {
00028
00045 #ifdef FXINLINE_MUTEX_IMPLEMENTATION
00046 #define QMUTEX_FXAPI
00047 #define QMUTEX_GLOBALS_FXAPI FXAPI
00048
00049
00050 #define QMUTEX_INLINEI inline FXFORCEINLINE
00051 #define QMUTEX_INLINEP inline
00052 #else
00053 #define QMUTEX_FXAPI FXAPI
00054 #define QMUTEX_GLOBALS_FXAPI
00055 #define QMUTEX_INLINEI FXFORCEINLINE // internally inlined inside QThread.cxx
00056 #define QMUTEX_INLINEP // publicly inlined
00057 #endif
00058
00100 class QMUTEX_FXAPI FXAtomicInt
00101 {
00102 volatile long lock;
00103 volatile int value;
00104 volatile int value2;
00105 friend class QMutex;
00106 friend class QShrdMemMutex;
00107 QMUTEX_INLINEI FXDLLLOCAL int get() const throw();
00108 QMUTEX_INLINEI FXDLLLOCAL int set(int i) throw();
00109 QMUTEX_INLINEI FXDLLLOCAL int incp() throw();
00110 QMUTEX_INLINEI FXDLLLOCAL int pinc() throw();
00111 QMUTEX_INLINEI FXDLLLOCAL int finc() throw();
00112 QMUTEX_INLINEI FXDLLLOCAL int inc(int i) throw();
00113 QMUTEX_INLINEI FXDLLLOCAL int decp() throw();
00114 QMUTEX_INLINEI FXDLLLOCAL int pdec() throw();
00115 QMUTEX_INLINEI FXDLLLOCAL int fdec() throw();
00116 QMUTEX_INLINEI FXDLLLOCAL int dec(int i) throw();
00117 QMUTEX_INLINEI FXDLLLOCAL int swapI(int newval) throw();
00118 QMUTEX_INLINEI FXDLLLOCAL int cmpXI(int compare, int newval) throw();
00119 QMUTEX_INLINEI FXDLLLOCAL int spinI(int count) throw();
00120 public:
00122 QMUTEX_INLINEP FXAtomicInt(int i=0) throw() : lock(0), value(i), value2(0) { }
00123 QMUTEX_INLINEP FXAtomicInt(const FXAtomicInt &o) throw() : lock(0), value(o.value), value2(0) { }
00124 QMUTEX_INLINEP FXAtomicInt &operator=(const FXAtomicInt &o) throw() { lock=0; value=o.value; return *this; }
00126 QMUTEX_INLINEP operator int() const throw();
00128 QMUTEX_INLINEP int operator=(int i) throw();
00130 QMUTEX_INLINEP int operator++(int) throw();
00132 QMUTEX_INLINEP int operator++() throw();
00136 QMUTEX_INLINEP int fastinc() throw();
00138 QMUTEX_INLINEP int operator+=(int i) throw();
00140 QMUTEX_INLINEP int operator--(int) throw();
00142 QMUTEX_INLINEP int operator--() throw();
00146 QMUTEX_INLINEP int fastdec() throw();
00148 QMUTEX_INLINEP int operator-=(int i) throw();
00150 QMUTEX_INLINEP int swap(int newval) throw();
00152 QMUTEX_INLINEP int cmpX(int compare, int newval) throw();
00153 };
00154
00188 class QMUTEX_FXAPI QShrdMemMutex
00189 {
00190 FXAtomicInt lockvar;
00191 FXuint timeout;
00192 public:
00194 QMUTEX_INLINEP QShrdMemMutex(FXuint _timeout=1000) : timeout(_timeout+1) { }
00196 QMUTEX_INLINEP FXuint timeOut() const throw() { return timeout-1; }
00198 QMUTEX_INLINEP void setTimeOut(FXuint to) throw() { timeout=to+1; }
00200 QMUTEX_INLINEP void lock();
00202 QMUTEX_INLINEP void unlock() throw() { lockvar=0; }
00204 QMUTEX_INLINEP bool tryLock() throw();
00205 };
00206
00313 struct QMutexPrivate;
00314 class QMUTEX_FXAPI QMutex
00315 {
00316 QMutexPrivate *p;
00317 QMutex(const QMutex &);
00318 QMutex &operator=(const QMutex &);
00319 friend class QRWMutex;
00320 QMUTEX_INLINEI FXDLLLOCAL void int_lock();
00321 QMUTEX_INLINEI FXDLLLOCAL void int_unlock();
00322 public:
00324 QMUTEX_INLINEP QMutex(FXuint spinCount=4000);
00325 QMUTEX_INLINEP ~QMutex();
00327 QMUTEX_INLINEP bool isLocked() const;
00331 QMUTEX_INLINEP FXbool locked() const { return (FXbool) isLocked(); }
00333 QMUTEX_INLINEP FXuint spinCount() const;
00335 QMUTEX_INLINEP void setSpinCount(FXuint c);
00340 QMUTEX_INLINEP void lock();
00345 QMUTEX_INLINEP void unlock();
00349 QMUTEX_INLINEP bool tryLock();
00353 QMUTEX_INLINEP FXbool trylock() { return (FXbool) tryLock(); }
00356 QMUTEX_INLINEP static bool setMutexDebugYield(bool v);
00357 };
00358
00359
00384 class QWaitConditionPrivate;
00385 class FXAPI QWaitCondition
00386 {
00387 QWaitConditionPrivate *p;
00388 bool isSignalled, isAutoReset;
00389 QWaitCondition(const QWaitCondition &);
00390 QWaitCondition &operator=(const QWaitCondition &);
00391 public:
00395 QWaitCondition(bool autoreset=false, bool initialstate=false);
00396 ~QWaitCondition();
00400 bool wait(FXuint time=FXINFINITE) ;
00402 void wakeOne () ;
00409 void wakeAll () ;
00411 void reset();
00413 bool signalled() const { return isSignalled; }
00414 };
00415
00451 class QRWMutexPrivate;
00452 class QMtxHold;
00453 class FXAPI QRWMutex
00454 {
00455 QRWMutexPrivate *p;
00456 QRWMutex(const QRWMutex &);
00457 QRWMutex &operator=(const QRWMutex &);
00458 public:
00459 enum LockedState
00460 {
00461 Unlocked=0,
00462 ReadOnly,
00463 ReadWrite
00464 };
00465 private:
00466 LockedState lockedstate;
00467 public:
00468 QRWMutex();
00469 ~QRWMutex();
00471 FXuint spinCount() const;
00473 void setSpinCount(FXuint c);
00492 bool lock(bool write=true);
00497 void unlock(bool write=true);
00499 LockedState isLocked() const { return lockedstate; }
00503 bool trylock(bool write);
00504 private:
00506 bool prefersReaders() const;
00508 void setReaderPreference(bool);
00509 inline FXDLLLOCAL bool _lock(QMtxHold &h, bool write);
00510 };
00511
00522 class QMtxHold
00523 {
00524 FXuint flags;
00525 bool locklost;
00526 union {
00527 QMutex *mutex;
00528 QRWMutex *rwmutex;
00529 QShrdMemMutex *shrdmutex;
00530 };
00531
00532 QMtxHold(const QMtxHold &);
00533 QMtxHold &operator=(const QMtxHold &);
00534 public:
00536 enum Flags
00537 {
00538 LockAndUnlock=0,
00539 UnlockAndRelock=1,
00540 AcceptNullMutex=2,
00541
00542 IsShrdMutex=(1<<26),
00543 IsRWMutex=(1<<27),
00544 IsLocked=(1<<28),
00545 IsRWMutexWrite=(1<<29)
00546 };
00548 FXFORCEINLINE QMtxHold(const QMutex *m, FXuint _flags=LockAndUnlock)
00549 : flags(_flags), locklost(false)
00550 {
00551 mutex=const_cast<QMutex *>(m);
00552 if((flags & AcceptNullMutex) && !mutex) return;
00553 if(flags & UnlockAndRelock) mutex->unlock(); else mutex->lock();
00554 flags|=IsLocked;
00555 }
00557 FXFORCEINLINE QMtxHold(const QMutex &m, FXuint _flags=LockAndUnlock)
00558 : flags(_flags), locklost(false)
00559 {
00560 mutex=const_cast<QMutex *>(&m);
00561 if(flags & UnlockAndRelock) mutex->unlock(); else mutex->lock();
00562 flags|=IsLocked;
00563 }
00565 FXFORCEINLINE QMtxHold(const QRWMutex *m, bool write=true, FXuint _flags=LockAndUnlock)
00566 : flags(_flags|IsRWMutex|(write ? IsRWMutexWrite : 0)), locklost(false)
00567 {
00568 rwmutex=const_cast<QRWMutex *>(m);
00569 if((flags & AcceptNullMutex) && !rwmutex) return;
00570 locklost=rwmutex->lock(!!(flags & IsRWMutexWrite));
00571 flags|=IsLocked;
00572 }
00574 FXFORCEINLINE QMtxHold(const QRWMutex &m, bool write=true, FXuint _flags=LockAndUnlock)
00575 : flags(_flags|IsRWMutex|(write ? IsRWMutexWrite : 0)), locklost(false)
00576 {
00577 rwmutex=const_cast<QRWMutex *>(&m);
00578 locklost=rwmutex->lock(!!(flags & IsRWMutexWrite));
00579 flags|=IsLocked;
00580 }
00582 FXFORCEINLINE QMtxHold(const QShrdMemMutex *m, FXuint _flags=LockAndUnlock)
00583 : flags(_flags|IsShrdMutex), locklost(false)
00584 {
00585 shrdmutex=const_cast<QShrdMemMutex *>(m);
00586 if((flags & AcceptNullMutex) && !shrdmutex) return;
00587 if(flags & UnlockAndRelock) shrdmutex->unlock(); else shrdmutex->lock();
00588 flags|=IsLocked;
00589 }
00591 FXFORCEINLINE QMtxHold(const QShrdMemMutex &m, FXuint _flags=LockAndUnlock)
00592 : flags(_flags|IsShrdMutex), locklost(false)
00593 {
00594 shrdmutex=const_cast<QShrdMemMutex *>(&m);
00595 if(flags & UnlockAndRelock) shrdmutex->unlock(); else shrdmutex->lock();
00596 flags|=IsLocked;
00597 }
00599 FXFORCEINLINE void unlock()
00600 {
00601 if((flags & AcceptNullMutex) && !mutex) return;
00602 if(flags & IsLocked)
00603 {
00604 if(flags & IsRWMutex)
00605 rwmutex->unlock(!!(flags & IsRWMutexWrite));
00606 else if(flags & IsShrdMutex)
00607 {
00608 if(flags & UnlockAndRelock) shrdmutex->lock(); else shrdmutex->unlock();
00609 }
00610 else
00611 {
00612 if(flags & UnlockAndRelock) mutex->lock(); else mutex->unlock();
00613 }
00614 flags&=~IsLocked;
00615 }
00616 }
00618 FXFORCEINLINE void relock()
00619 {
00620 if((flags & AcceptNullMutex) && !mutex && !rwmutex) return;
00621 if(!(flags & IsLocked))
00622 {
00623 if(flags & IsRWMutex)
00624 locklost=rwmutex->lock(!!(flags & IsRWMutexWrite));
00625 else if(flags & IsShrdMutex)
00626 {
00627 if(flags & UnlockAndRelock) shrdmutex->unlock(); else shrdmutex->lock();
00628 }
00629 else
00630 {
00631 if(flags & UnlockAndRelock) mutex->unlock(); else mutex->lock();
00632 }
00633 flags|=IsLocked;
00634 }
00635 }
00637 FXFORCEINLINE bool lockLost() const { return locklost; }
00638 FXFORCEINLINE ~QMtxHold() { unlock(); }
00639 };
00640
00641
00642 namespace Generic {
00643
00675 template<class type> struct lockedAccessor
00676 {
00677 private:
00678 QMtxHold *h;
00679 type &val;
00680 public:
00682 lockedAccessor(type &_val, const QMutex *m) : val(_val), h(0) { if(m) { FXERRHM(h=new QMtxHold(m)); } }
00684 lockedAccessor(type &_val, const QMutex &m) : val(_val), h(0) { FXERRHM(h=new QMtxHold(m)); }
00686 lockedAccessor(type &_val, const QRWMutex *m) : val(_val), h(0) { if(m) { FXERRHM(h=new QMtxHold(m)); } }
00688 lockedAccessor(type &_val, const QRWMutex &m) : val(_val), h(0) { FXERRHM(h=new QMtxHold(m)); }
00689 #ifndef HAVE_CPP0XRVALUEREFS
00690 #ifdef HAVE_CONSTTEMPORARIES
00691 lockedAccessor(const lockedAccessor &_o) : h(_o.h), val(_o.val)
00692 {
00693 lockedAccessor &o=const_cast<lockedAccessor &>(_o);
00694 o.h=0;
00695 }
00696 lockedAccessor &operator=(const lockedAccessor &_o)
00697 {
00698 lockedAccessor &o=const_cast<lockedAccessor &>(_o);
00699 this->~lockedAccessor();
00700 return *new(this) lockedAccessor(o);
00701 }
00702 #else
00703 lockedAccessor(lockedAccessor &o) : h(o.h), val(o.val)
00704 {
00705 o.h=0;
00706 }
00707 lockedAccessor &operator=(lockedAccessor &o)
00708 {
00709 this->~lockedAccessor();
00710 return *new(this) lockedAccessor(o);
00711 }
00712 #endif
00713 #else
00714 private:
00715 lockedAccessor(const lockedAccessor &);
00716 lockedAccessor &operator=(const lockedAccessor &_o);
00717 public:
00718 lockedAccessor(lockedAccessor &&o) : h(o.h), val(o.val)
00719 {
00720 o.h=0;
00721 }
00722 lockedAccessor &&operator=(lockedAccessor &&o)
00723 {
00724 this->~lockedAccessor();
00725 return *new(this) lockedAccessor(o);
00726 }
00727 #endif
00728 ~lockedAccessor()
00729 {
00730 FXDELETE(h);
00731 }
00732
00734 type &operator*() const { return const_cast<type &>(val); }
00736 type *operator->() const { return const_cast<type *>(&val); }
00737 };
00738 }
00739
00752 class FXZeroedWait
00753 {
00754 FXAtomicInt count;
00755 bool doChecks;
00756 QWaitCondition wc;
00757 void handleCount(int nc)
00758 {
00759 if(doChecks)
00760 {
00761 if(nc<0) FXERRG("Count should not be below zero", 0, FXERRH_ISDEBUG);
00762 }
00763 if(nc>0) wc.reset();
00764 else if(!nc) wc.wakeAll();
00765 }
00766 public:
00768 FXZeroedWait(int initcount=0) : count(initcount), doChecks(false), wc(false, !initcount) { }
00770 operator int() const { return count; }
00772 int operator=(int i) { int c=(count=i); handleCount(c); return c; }
00774 int operator++(int) { int c=count++; handleCount(c+1); return c; }
00776 int operator++() { int c=++count; handleCount(c); return c; }
00778 int operator+=(int i) { int c=(count+=i); handleCount(c); return c; }
00780 int operator--(int) { int c=count--; handleCount(c-1); return c; }
00782 int operator--() { int c=--count; handleCount(c); return c; }
00784 int operator-=(int i) { int c=(count-=i); handleCount(c); return c; }
00785
00787 bool wait(FXuint time=FXINFINITE) { return wc.wait(time); }
00789 void setChecks(bool d) { doChecks=d; }
00790 };
00791
00822 class QThreadLocalStorageBasePrivate;
00823 class FXAPI QThreadLocalStorageBase
00824 {
00825 QThreadLocalStorageBasePrivate *p;
00826 QThreadLocalStorageBase(const QThreadLocalStorageBase &);
00827 QThreadLocalStorageBase &operator=(const QThreadLocalStorageBase &);
00828 public:
00829 QThreadLocalStorageBase(void *initval=0);
00830 ~QThreadLocalStorageBase();
00832 void setPtr(void *val);
00834 void *getPtr() const;
00835 };
00836 template<class type> class QThreadLocalStorage : private QThreadLocalStorageBase
00837 {
00838 public:
00840 QThreadLocalStorage(type *initval=0) : QThreadLocalStorageBase(static_cast<void *>(initval)) { }
00844 type *operator=(type *a) { setPtr(static_cast<void *>(a)); return a; }
00848 operator type *() const { return static_cast<type *>(getPtr()); }
00849 type *operator ->() const { return static_cast<type *>(getPtr()); }
00850 };
00851
00852
00970 class QThreadPrivate;
00971 class FXAPI QThread
00972 {
00973 friend class QThreadPrivate;
00974 friend class FXPrimaryThread;
00975 const char *myname;
00976 FXuint magic;
00977 QThreadPrivate *p;
00978 bool isRunning, isFinished, isInCleanup;
00979 int termdisablecnt;
00980 QThread(const QThread &);
00981 QThread &operator=(const QThread &);
00982 public:
00984 enum ThreadScheduler
00985 {
00986 Auto=0,
00987 InProcess,
00988 InKernel
00989 };
00993 QThread(const char *name=0, bool autodelete=false, FXuval stacksize=524288, ThreadScheduler schedloc=Auto);
00995 virtual ~QThread();
00997 const char *name() const throw() { return myname; }
00999 FXuval stackSize() const;
01008 void setStackSize(FXuval newsize);
01010 ThreadScheduler threadLocation() const;
01012 void setThreadLocation(ThreadScheduler threadloc);
01013
01021 bool wait(FXuint time=FXINFINITE);
01029 void start(bool waitTillStarted=false) ;
01031 bool finished () const throw(){ return isFinished; }
01033 bool running () const throw(){ return isRunning; }
01035 bool inCleanup() const throw(){ return isInCleanup; }
01037 bool isValid() const throw();
01041 bool setAutoDelete(bool doso) throw();
01049 void requestTermination();
01051 static FXulong id() throw();
01053 FXulong myId() const;
01059 static QThread *current();
01061 static QThread *primaryThread() throw();
01067 QThread *creator() const;
01072 signed char priority() const;
01077 void setPriority(signed char pri);
01079 FXulong processorAffinity() const;
01083 void setProcessorAffinity(FXulong mask=(FXulong)-1, bool recursive=false);
01085 static void sleep(FXuint secs);
01087 static void msleep(FXuint millisecs);
01089 static void yield();
01093 virtual void selfDestruct() { delete this; }
01095 static void exit (void *retcode);
01097 void *result() const throw();
01102 void disableTermination();
01107 bool checkForTerminate();
01112 void enableTermination();
01114 typedef Generic::Functor<Generic::TL::create<void, QThread *>::value> CreationUpcallSpec;
01125 static void addCreationUpcall(CreationUpcallSpec upcallv, bool inThread=false);
01127 static bool removeCreationUpcall(CreationUpcallSpec upcallv);
01135 Generic::BoundFunctorV *addCleanupCall(FXAutoPtr<Generic::BoundFunctorV> handler, bool inThread=false);
01138 bool removeCleanupCall(Generic::BoundFunctorV *handler);
01139
01140 protected:
01142 virtual void run()=0;
01147 virtual void *cleanup()=0;
01148 public:
01149 static FXDLLLOCAL void *int_cancelWaiterHandle();
01150 private:
01151 friend class QThread_DisableSignals;
01152 static void *int_disableSignals();
01153 static void int_enableSignals(void *oldmask);
01154 };
01155
01164 class QThread_DTHold : public Generic::DoUndo<QThread, void (QThread::*)(), void (QThread::*)()>
01165 {
01166 public:
01168 QThread_DTHold(QThread *t=QThread::current())
01169 : Generic::DoUndo<QThread, void (QThread::*)(), void (QThread::*)()>(t, &QThread::disableTermination, &QThread::enableTermination) { }
01170 };
01171
01179 class QThread_DisableSignals
01180 {
01181 void *old_mask;
01182 public:
01184 QThread_DisableSignals() : old_mask(QThread::int_disableSignals()) { }
01185 ~QThread_DisableSignals() { QThread::int_enableSignals(old_mask); }
01186 };
01187
01227 struct QThreadPoolPrivate;
01228 class FXAPI QThreadPool
01229 {
01230 QThreadPoolPrivate *p;
01231 QThreadPool(const QThreadPool &);
01232 QThreadPool &operator=(const QThreadPool &);
01233 void startThreads(FXuint newno);
01234 public:
01236 typedef void *handle;
01241 QThreadPool(FXuint total=FXProcess::noOfProcessors(), bool dynamic=false);
01242 ~QThreadPool();
01244 FXuint total() const throw();
01246 FXuint maximum() const throw();
01248 FXuint free() const throw();
01253 void setTotal(FXuint newno);
01255 bool dynamic() const throw();
01257 void setDynamic(bool v);
01259 enum DispatchUpcallType
01260 {
01261 PreDispatch=0,
01262 PostDispatch=1,
01263 CancelledPreDispatch=2
01264 };
01266 typedef Generic::Functor<Generic::TL::create<bool, QThreadPool *, handle, DispatchUpcallType>::value> DispatchUpcallSpec;
01269 handle dispatch(FXAutoPtr<Generic::BoundFunctorV> code, FXuint delay=0, DispatchUpcallSpec *upcallv=0);
01271 enum CancelledState
01272 {
01273 NotFound=0,
01274 Cancelled,
01275 WasRunning
01276 };
01279 CancelledState cancel(handle code, bool wait=true);
01282 bool reset(handle code, FXuint delay);
01284 bool wait(handle code, FXuint period=FXINFINITE);
01285 };
01286
01287 }
01288
01289 #ifndef FXBEING_INCLUDED_BY_QTHREAD
01290 #ifdef FXINLINE_MUTEX_IMPLEMENTATION
01291 #define FXBEING_INCLUDED_BY_QTHREAD
01292 #include "int_QMutexImpl.h"
01293 #undef FXBEING_INCLUDED_BY_QTHREAD
01294
01295
01296 #undef USE_WINAPI
01297 #undef USE_OURMUTEX
01298 #undef USE_X86
01299 #undef __CLEANUP_C
01300 #undef MUTEX_USESEMA
01301 #endif
01302 #undef QMUTEX_FXAPI
01303 #undef QMUTEX_INLINE
01304 #undef QMUTEX_GLOBALS_FXAPI
01305 #endif
01306
01307 #endif
01308