home *** CD-ROM | disk | FTP | other *** search
- #ifndef __SEMAPHORES__
- #define __SEMAPHORES__
-
- #ifndef __THREADS__
- #include <Threads.h>
- #endif
-
-
- //========================================================================================
- // CLASS TThreadIDQueue
- //
- // Keep track of a queue of ThreadIDs
- //========================================================================================
-
- class TThreadIDQueue
- {
- public:
- TThreadIDQueue() : fThreadCount(0), fReservedSpace(0), fThreadQueue(nil) {};
- ~TThreadIDQueue();
-
- OSErr Enqueue(ThreadID threadToAdd);
- ThreadID Dequeue();
- long QueuedThreads() { return fThreadCount; }
-
- private:
- OSErr InsureThreadQueueHasFreeSpace();
-
- long fThreadCount;
- long fReservedSpace;
- ThreadID** fThreadQueue;
- };
-
- enum
- {
- kAnySemaphoreID = 0,
- kNeverTimeoutSemaphore = 0x7FFFFFFF
- };
-
- //========================================================================================
- // CLASS TSemaphore
- //
- // A semaphore consists of an owner thread and a list of blocked threads waiting to
- // become the owner. When the semaphore is created, its resource count is specified
- // to be either 0 or 1 (larger numbers could be supported if a list of owning threads
- // was kept).
- //
- // A thread requests to become the owner by calling Grab, and relinquishes
- // ownership by calling Release. Non-threads can get ownership of the semaphore by
- // calling SetAvailable(false); in this case even though fOwningThread will be nil, the
- // semaphore will still work correctly because fAvailable is false and thus other threads
- // that grab the semaphore will block as they should.
- //
- // Semaphores are linked into a global list of all semaphores upon creation and removed
- // upon deletion. Each semaphore has a unique ID (generated by a static method), and
- // the global list can be searched for a given ID (via another static method).
- //========================================================================================
-
- class TSemaphore
- {
-
- // --- Methods -------------------------------------------------------------------------------------
-
- public:
- TSemaphore(long resourceCount = 1, long semaphoreID = kAnySemaphoreID);
- protected:
- virtual ~TSemaphore();
-
- public:
- static void InitializeGlobals();
- static long NewUniqueSemaphoreID();
- static TSemaphore* FindSemaphore(long semaphoreID, Boolean createIfNotFound = false, long resourceCount = 1);
- static void Idle();
- static void ThreadDied(ThreadID threadID);
- static void SetDefaultTimeout(long newDefault);
- static void SetDefaultMaxWait(long newMaxWait);
-
- void ReleaseReference();
- void Dispose();
- long SemaphoreID() const;
-
- OSErr Grab(ThreadID threadID = kCurrentThreadID);
- void Release(ThreadID threadID = kCurrentThreadID);
- ThreadID ReleaseOneThread();
- void ReleaseAllThreads();
- Boolean Available() const;
- void SetAvailable(Boolean);
-
- void ResetTimeoutTimer();
- void AddGracePeriod(long gracePeriod);
- void SetSemaphoreTimoutValue(long timeoutValue);
- void SetSemaphoreMaxWaitTime(long timeoutValue);
- long SemaphoreTimoutValue() { return fSemaphoreTimeoutValue; }
- long SemaphoreMaxWaitTime() { return fSemaphoreMaxWaitTime; }
-
- unsigned long TimeoutTick();
- Boolean CheckIfTimerExpired(unsigned long currentTime);
- void SemaphoreTimedOut();
-
- protected:
- void RemoveFromGlobalSemaphoreList();
-
- // --- Fields -------------------------------------------------------------------------------------
-
- private:
- static TSemaphore* fgFirstSemaphore; // Pointer to the first semaphore in the global list of all semaphores
- static long fgSemaphoreIDSequence; // The next available semaphore ID (used for assigning unique IDs)
- static long fgSemaphoreDefaultTimeout; // Default time to wait before timing out
- static long fgSemaphoreDefaultMaxWait; // Default maximum time to wait (exclusive of timer resets)
- static unsigned long fgLastTimeoutTest; // The last tick that we looked for timed-out semaphores
- static unsigned long fgLastIdleTick; // The last tick we got some idle time
- static unsigned long fgNextTimeoutTest; // Next tick to look for semaphores that have timed out
-
- TSemaphore* fNextSemaphore; // Previous semaphore in the global list of all semaphores
- TSemaphore* fPreviousSemaphore; // Next semaphore in the global list of all semaphores
-
- ThreadID fOwnerThread; // The thread that currently owns this semaphore
- TThreadIDQueue fBlockedThreads; // Queue of threads blocked on this semaphore
-
- long fResourceCount; // The number of threads that may own this semaphore (0 or 1)
- long fSemaphoreID; // The ID (usually unique) for this semaphore
- long fOwnerCount; // The number of threads that currently own the semaphore (<= fResourceCount)
- Boolean fDisposed; // True if someone disposed this semaphore
- long fReferenceCount; // Count of blocked threads, to keep semaphore around after "deletion"
- OSErr fFailOnWakeup; // If set, all threads fail with this error when they wake up
-
- unsigned long fBlockStartTick; // TickCount at which first thread blocked on this semaphore
- unsigned long fTimeoutTick; // The tick at which the semaphore will time out if timer
- // is not recet
- long fSemaphoreTimeoutValue; // How long to wait after every timer reset
- long fSemaphoreMaxWaitTime; // The maximum number of ticks to wait before ignoring timer
- // resets and just time out
- };
-
- inline void TSemaphore::SetDefaultTimeout(long newDefault) { fgSemaphoreDefaultTimeout = newDefault; }
- inline void TSemaphore::SetDefaultMaxWait(long newMaxWait) { fgSemaphoreDefaultMaxWait = newMaxWait; }
- inline unsigned long TSemaphore::TimeoutTick() { return fTimeoutTick; }
-
- inline long TSemaphore::SemaphoreID() const { return fSemaphoreID; }
-
-
- #endif
-