#ifndef __AUTOCRIT_H__ #define __AUTOCRIT_H__ #ifdef RV_USE_CRITICALSECTION // This class eliminates the need to figure out where to call InitializeCriticalSection // and DeleteCriticalSection. It makes critical sections into a meaningful class. More // importantly, now when they are created as statics, they are already initialized, so // the AutoCrit doesn't have to worry about checking to see if they've been initialized yet class CriticalSection { public: ID_INLINE CriticalSection() { InitializeCriticalSection(&mCrit); } ID_INLINE ~CriticalSection() { DeleteCriticalSection(&mCrit); } ID_INLINE void Enter() { while(!Try()) { Sleep(0); // give another thread a chance to run to try to eliminate deadlock } } ID_INLINE void Leave() { LeaveCriticalSection(&mCrit); } ID_INLINE bool Try() { return TryEnterCriticalSection(&mCrit) != 0; } private: CRITICAL_SECTION mCrit; }; #endif #ifdef RV_USE_AUTOCRIT // Enters a critical section unique to the type of object t on construction // Exits that critical section on destruction. Effectively synchronizes calls // to ANY instance of type t template class AutoCrit { public: ID_INLINE AutoCrit() { sCrit.Enter(); } ID_INLINE ~AutoCrit() { sCrit.Leave(); } private: static CriticalSection sCrit; }; template CriticalSection AutoCrit::sCrit; template class ConditionalAutoCrit { public: ID_INLINE ConditionalAutoCrit() { if(sThreading) { sCrit.Enter(); mMustLeave = true; } else { mMustLeave = false; } } ID_INLINE ~ConditionalAutoCrit() { if(mMustLeave) { sCrit.Leave(); } } static ID_INLINE SetThreading(bool threading) { // not threadsafe...must be called BEFORE entering and AFTER leaving a threaded section, not during sThreading = threading; } static ID_INLINE bool IsThreading() { return sThreading; } private: static bool sThreading; static CriticalSection sCrit; bool mMustLeave; }; template CriticalSection ConditionalAutoCrit::sCrit; template bool ConditionalAutoCrit::sThreading=false; #else // these compile out completely in release and removes the need // for ifdefs all over the code template class AutoCrit { public: AutoCrit() { } ~AutoCrit() { } }; template class ConditionalAutoCrit { public: ConditionalAutoCrit() { } ~ConditionalAutoCrit() { } }; #endif #ifdef RV_USE_AUTOINSTANCECRIT class CritInfo { public: ID_INLINE CritInfo() { refCount = 0; } int refCount; CriticalSection crit; }; // Enters a critical section unique to the specific instance of an object of type t on construction // Exits that critical section on destruction. This is templated instead of using void * in order // to reduce search time when entering and leaving. Effectively synchronizes on a single instance // of an object. This would allow containers for example to not be synchronized to other containers // of the same type. template class AutoInstanceCrit { public: ID_INLINE AutoInstanceCrit(t *ptr) { CritInfo *critPtr = NULL; //AutoCrit > crit; // protect access to the map critSect.Enter(); mPtr = ptr; int i = sPtrs.FindIndex(mPtr); if(i == -1) // not found { i = sPtrs.Num(); sPtrs.Append(mPtr); sInfos.Append(CritInfo()); } critPtr = &(sInfos[i]); critPtr->refCount++; critSect.Leave(); critPtr->crit.Enter(); } ID_INLINE ~AutoInstanceCrit() { CritInfo *critPtr = NULL; { //AutoCrit > crit; // protect access to the map critSect.Enter(); int i = sPtrs.FindIndex(mPtr); assert(i != -1); critPtr = &(sInfos[i]); critPtr->refCount--; // decrement refcount critSect.Leave(); } critPtr->crit.Leave(); /* if(critPtr->refCount == 0) { sPtrs.RemoveIndex(i); sInfos.RemoveIndex(i); }*/ } private: t *mPtr; // the pointer we're protecting static CriticalSection critSect; static idList sPtrs; static idList sInfos; }; template idList AutoInstanceCrit::sPtrs; template idList AutoInstanceCrit::sInfos; template CriticalSection AutoInstanceCrit::critSect; #else // this compiles out completely in release and removes the need // for ifdefs all over the code template class AutoInstanceCrit { public: ID_INLINE AutoInstanceCrit(t *ptr) { } }; #endif #endif