Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
859 lines
24 KiB
C++
859 lines
24 KiB
C++
/* ----------------------------------------------------------------------------
|
|
Microsoft D.T.C (Distributed Transaction Coordinator)
|
|
|
|
(c) 1995 Microsoft Corporation. All Rights Reserved
|
|
|
|
@doc
|
|
|
|
@module UTSem.H |
|
|
|
|
SYNCHRO - C++ class to provide synchronization object encapsulation
|
|
|
|
This implementation of the SYNCHRO class provides multi-read XOR single-write
|
|
(a.k.a. shared vs. exclusive) lock capabilities, with protection against
|
|
writer starvation. Code origianly borrowed from
|
|
(c) 1994 by Daniel S. Glasser and then modified for our needs.
|
|
|
|
@devnote None
|
|
|
|
@rev 3 | 1st-Aug-1996 | GaganC | Added the spin lock code and class
|
|
@rev 2 | 31-May-1996 | GaganC | Removed the special code for x86
|
|
@rev 1 | 18th Jan, 96 | GaganC | Special cased UTGuard for X86
|
|
@rev 0 | 4th Feb,95 | GaganC | Created
|
|
---------------------------------------------------------------------------- */
|
|
#ifndef __UTSEM_H__
|
|
#define __UTSEM_H__
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
// INCLUDES
|
|
// -------------------------------------------------------------
|
|
#include "UTAssert.H"
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
// CONSTANTS AND TYPES
|
|
// -------------------------------------------------------------
|
|
typedef enum {SLC_WRITE, SLC_READWRITE, SLC_READWRITEPROMOTE}
|
|
SYNCH_LOCK_CAPS;
|
|
|
|
typedef enum {SLT_READ, SLT_READPROMOTE, SLT_WRITE}
|
|
SYNCH_LOCK_TYPE;
|
|
|
|
const int NUM_SYNCH_LOCK_TYPES = SLT_WRITE + 1;
|
|
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
// FORWARDS
|
|
// -------------------------------------------------------------
|
|
class CSemExclusive;
|
|
class CSemExclusiveSL;
|
|
class UTGuard;
|
|
class UTSemReadWrite;
|
|
class UTSemCheapReadWrite;
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
// GLOBAL HELPER FUNCTIONS
|
|
// -------------------------------------------------------------
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@func Description:<nl>
|
|
|
|
Guarantees isolated increments of *pl.<nl><nl>
|
|
|
|
Usage:<nl>
|
|
Use instead of InterlockedIncrement for Win16/Win32 portability.<nl><nl>
|
|
|
|
@rev 0 | 3/21/95 | Rcraig | Created.
|
|
---------------------------------------------------------------------------- */
|
|
inline LONG SafeIncrement ( LPLONG pl )
|
|
{
|
|
return (InterlockedIncrement (pl));
|
|
} // SafeIncrement
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@func Description:<nl>
|
|
Win16/Win32 abstraction wrapper:
|
|
Guarantees isolated decrements of *pl.<nl><nl>
|
|
|
|
Usage:<nl>
|
|
Use instead of InterlockedDecrement for Win16/Win32 portability.<nl><nl>
|
|
|
|
@rev 0 | 3/21/95 | Rcraig | Created.
|
|
---------------------------------------------------------------------------- */
|
|
inline LONG SafeDecrement ( LPLONG pl )
|
|
{
|
|
return (InterlockedDecrement (pl));
|
|
} // SafeDecrement
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@class UTGuard
|
|
This object represents a guard that can be acquired or released. The
|
|
advantage with useing this instead of a critical section is that this
|
|
is non blocking. If AcquireGuard fails, it will return false and will not
|
|
block.
|
|
|
|
@rev 0 | 4th Feb,95 | GaganC | Created
|
|
---------------------------------------------------------------------------- */
|
|
class UTGuard
|
|
{
|
|
private:
|
|
long m_lVal;
|
|
|
|
public:
|
|
//@cmember Constructor
|
|
UTGuard (void);
|
|
//@cmember Destructor
|
|
~UTGuard (void);
|
|
|
|
//@cmember Acquires the guard
|
|
BOOL AcquireGuard (void);
|
|
//@cmember Releases the guard
|
|
void ReleaseGuard (void);
|
|
|
|
//@cmember Initializes the Guard
|
|
void Init (void);
|
|
} ; //End class UTGuard
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// IMPLEMENTATION of class UTGuard
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
---------------------------------------------------------------------------- */
|
|
inline UTGuard::UTGuard ( void )
|
|
{
|
|
m_lVal = 0;
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
---------------------------------------------------------------------------- */
|
|
inline UTGuard::~UTGuard ( void )
|
|
{
|
|
//Do nothing
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
---------------------------------------------------------------------------- */
|
|
inline BOOL UTGuard::AcquireGuard (void)
|
|
{
|
|
long lVal;
|
|
|
|
lVal = InterlockedExchange (&m_lVal, 1);
|
|
|
|
return (lVal == 0);
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
---------------------------------------------------------------------------- */
|
|
inline void UTGuard::ReleaseGuard (void)
|
|
{
|
|
m_lVal = 0;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
---------------------------------------------------------------------------- */
|
|
void inline UTGuard::Init ( void )
|
|
{
|
|
m_lVal = 0;
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@class UTSemReadWrite
|
|
|
|
@rev 0 | 4th Feb,95 | GaganC | Created
|
|
---------------------------------------------------------------------------- */
|
|
class UTSemReadWrite
|
|
{
|
|
private:
|
|
CRITICAL_SECTION csExclusive; // Critical section object to synchronize writers
|
|
CRITICAL_SECTION csReader; // Critical section object to synchronize readers
|
|
HANDLE hevReadDone; // Manual-reset event to notify writers of
|
|
//reader completion
|
|
int cReaders; // Count of current readers
|
|
|
|
BOOL fInitSucceeded; // TRUE if the constructor function succeeded
|
|
|
|
public:
|
|
UTSemReadWrite(void); // Constructor
|
|
~UTSemReadWrite(void); // Destructor
|
|
|
|
// This implementation supports Read and Write locks
|
|
SYNCH_LOCK_CAPS GetCaps(void) { return SLC_READWRITE; };
|
|
|
|
// This object is valid if it was initialized
|
|
BOOL IsValid(void) { return fInitSucceeded; }
|
|
|
|
BOOL Lock(SYNCH_LOCK_TYPE); // Lock the object
|
|
BOOL UnLock(SYNCH_LOCK_TYPE); // Unlock the object
|
|
};
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// IMPLEMENTATION of class UTSemReadWrite
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
SYNCHRO class - Constructor
|
|
|
|
Create the event, initialize the critical section objects and reader count,
|
|
and return.
|
|
---------------------------------------------------------------------------- */
|
|
inline UTSemReadWrite::UTSemReadWrite(void)
|
|
{
|
|
// Create the manual-reset event (the only init that can fail)
|
|
hevReadDone = CreateEvent(NULL, TRUE, TRUE, NULL);
|
|
|
|
fInitSucceeded = hevReadDone != NULL;
|
|
|
|
// If we created the event, proceed with the risk-free initialization
|
|
if (fInitSucceeded)
|
|
{
|
|
cReaders = 0;
|
|
InitializeCriticalSection(&csExclusive);
|
|
InitializeCriticalSection(&csReader);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
SYNCHRO class - Destructor
|
|
|
|
Free the event, delete the critical section objects, and return.
|
|
---------------------------------------------------------------------------- */
|
|
inline UTSemReadWrite::~UTSemReadWrite(void)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
CloseHandle(hevReadDone);
|
|
DeleteCriticalSection(&csExclusive);
|
|
DeleteCriticalSection(&csReader);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
SYNCHRO class - Lock member function
|
|
---------------------------------------------------------------------------- */
|
|
inline BOOL UTSemReadWrite::Lock(SYNCH_LOCK_TYPE lt)
|
|
{
|
|
// Verify that the object is valid
|
|
if (! IsValid())
|
|
return FALSE;
|
|
|
|
// Verify that the specified lock type is supported by this implementation
|
|
if (lt == SLT_READPROMOTE)
|
|
return FALSE;
|
|
|
|
// Claim the read lock or write lock as specified
|
|
if (lt == SLT_READ)
|
|
{
|
|
// Claim the <csExclusive> critical section. This call blocks if there's
|
|
// an active writer or if there's a writer waiting for active readers to
|
|
// complete.
|
|
EnterCriticalSection(&csExclusive);
|
|
|
|
// Claim access to the reader count. If this blocks, it's only for the
|
|
// briefest moment, while other threads go through to increment or
|
|
// decrement the reader count.
|
|
EnterCriticalSection(&csReader);
|
|
|
|
// Increment the reader count. If this is the first reader, we reset the
|
|
// hevReadDone event so that the next writer blocks.
|
|
if (cReaders++ == 0)
|
|
ResetEvent(hevReadDone);
|
|
|
|
// Release access to the reader count
|
|
LeaveCriticalSection(&csReader);
|
|
|
|
// Release access to the <csExclusive> critical section. This enables
|
|
// other readers to come through and the next writer to wait for active
|
|
// readers to complete (which in turn prevents new readers from entering).
|
|
LeaveCriticalSection(&csExclusive);
|
|
}
|
|
else
|
|
{
|
|
// Verify that since this isn't the read lock, that it's the write lock
|
|
Assert(lt == SLT_WRITE);
|
|
|
|
// Claim the <csExclusive> critical section. This not only prevents other
|
|
// threads from claiming the write lock, but also prevents any new threads
|
|
// from claiming the read lock.
|
|
EnterCriticalSection(&csExclusive);
|
|
|
|
// Wait for the active readers to release their read locks.
|
|
return WaitForSingleObject(hevReadDone, INFINITE) == WAIT_OBJECT_0;
|
|
}
|
|
|
|
return TRUE;
|
|
} //End Lock
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
SYNCHRO class - Unlock member function
|
|
---------------------------------------------------------------------------- */
|
|
inline BOOL UTSemReadWrite::UnLock(SYNCH_LOCK_TYPE lt)
|
|
{
|
|
// Verify that the object is valid
|
|
if (! IsValid())
|
|
return FALSE;
|
|
|
|
// Verify that the specified lock type is supported by this implementation
|
|
if (lt == SLT_READPROMOTE)
|
|
return FALSE;
|
|
|
|
// Release the read lock or write lock as specified
|
|
if (lt == SLT_READ)
|
|
{
|
|
// Claim access to the reader count. If this blocks, it's only for the
|
|
// briefest moment, while other threads go through to increment or
|
|
// decrement the reader count.
|
|
EnterCriticalSection(&csReader);
|
|
|
|
// Decrement the reader count. If this is the last reader, set
|
|
// <hevReadDone>, which allows the first waiting writer to proceed.
|
|
if (--cReaders == 0)
|
|
SetEvent(hevReadDone);
|
|
|
|
// Release access to the reader count
|
|
LeaveCriticalSection(&csReader);
|
|
}
|
|
else
|
|
{
|
|
// Verify that since this isn't the read lock, that it's the write lock
|
|
Assert(lt == SLT_WRITE);
|
|
|
|
// Make <csExclusive> available to one other writer or to the first reader
|
|
LeaveCriticalSection(&csExclusive);
|
|
}
|
|
|
|
return TRUE;
|
|
} //End Unlock
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@class UTSemCheapReadWrite
|
|
|
|
@rev 0 | 5/1/97 | Shaiwals | Created using UTSemReadWrite, reader
|
|
| | | access to the lock is cheaper if
|
|
| | | there is already a reader present
|
|
---------------------------------------------------------------------------- */
|
|
class UTSemCheapReadWrite
|
|
{
|
|
private:
|
|
CRITICAL_SECTION csExclusive; // Critical section object to provide core locking
|
|
CRITICAL_SECTION csReader; // Critical section object to synchronize readers
|
|
CRITICAL_SECTION csWriter; // Critical section object to synchronize writers
|
|
HANDLE hevReadDone; // Manual-reset event to notify writers of
|
|
// reader completion
|
|
|
|
HANDLE hevReaderPresent; // Readers are currently present
|
|
HANDLE hevWriterPresent; // Writers are currently present
|
|
long cReaders; // Count of current readers
|
|
long cWriters; // Count of writers waiting
|
|
|
|
BOOL fInitSucceeded; // TRUE if the constructor function succeeded
|
|
BOOL m_fReader; // Flag to signal that readers presence has
|
|
// been notifed
|
|
|
|
public:
|
|
UTSemCheapReadWrite(void); // Constructor
|
|
~UTSemCheapReadWrite(void); // Destructor
|
|
|
|
// This implementation supports Read and Write locks
|
|
SYNCH_LOCK_CAPS GetCaps(void) { return SLC_READWRITE; };
|
|
|
|
// This object is valid if it was initialized
|
|
BOOL IsValid(void) { return fInitSucceeded; }
|
|
|
|
BOOL Lock(SYNCH_LOCK_TYPE); // Lock the object
|
|
BOOL UnLock(SYNCH_LOCK_TYPE); // Unlock the object
|
|
};
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// IMPLEMENTATION of class UTSemCheapReadWrite
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
SYNCHRO class - Constructor
|
|
|
|
Create the event, initialize the critical section objects and reader count,
|
|
and return.
|
|
---------------------------------------------------------------------------- */
|
|
inline UTSemCheapReadWrite::UTSemCheapReadWrite(void)
|
|
{
|
|
// Create the manual-reset event (the only init that can fail)
|
|
hevReadDone = CreateEvent(NULL, TRUE, TRUE, NULL);
|
|
hevReaderPresent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
hevWriterPresent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
fInitSucceeded = (hevReadDone != NULL) &&
|
|
(hevReaderPresent != NULL) &&
|
|
(hevWriterPresent != NULL);
|
|
|
|
// If we created the event, proceed with the risk-free initialization
|
|
if (fInitSucceeded)
|
|
{
|
|
cReaders = -1;
|
|
cWriters = -1;
|
|
m_fReader = FALSE;
|
|
InitializeCriticalSection(&csExclusive);
|
|
InitializeCriticalSection(&csReader);
|
|
InitializeCriticalSection(&csWriter);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
SYNCHRO class - Destructor
|
|
|
|
Free the event, delete the critical section objects, and return.
|
|
---------------------------------------------------------------------------- */
|
|
inline UTSemCheapReadWrite::~UTSemCheapReadWrite(void)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
CloseHandle(hevReadDone);
|
|
DeleteCriticalSection(&csExclusive);
|
|
DeleteCriticalSection(&csReader);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
SYNCHRO class - Lock member function
|
|
---------------------------------------------------------------------------- */
|
|
inline BOOL UTSemCheapReadWrite::Lock(SYNCH_LOCK_TYPE lt)
|
|
{
|
|
// Verify that the object is valid
|
|
if (! IsValid())
|
|
return FALSE;
|
|
|
|
// Verify that the specified lock type is supported by this implementation
|
|
if (lt == SLT_READPROMOTE)
|
|
return FALSE;
|
|
|
|
// Claim the read lock or write lock as specified
|
|
if (lt == SLT_READ)
|
|
{
|
|
// First try to get the reader lock cheaply by incrementing
|
|
// the reader count. Only if reader count is positive
|
|
// do we try and test that a reader is present
|
|
if (InterlockedIncrement (&cReaders) > 0)
|
|
{
|
|
// Test that there is actually a reader holding on the the lock.
|
|
// It is possible to that the reader count is greater that -1
|
|
// but still there are no readers who have actually acquired the
|
|
// lock
|
|
if (WaitForSingleObject (hevReaderPresent, 0) == WAIT_OBJECT_0)
|
|
{
|
|
// Only if there are no writers waiting to acquire the lock
|
|
// do we try to acquire the lock. Without this we cannot
|
|
// guarantee that the writer wont starve.
|
|
if (WaitForSingleObject (hevWriterPresent, 0) == WAIT_TIMEOUT)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Decrement extra reader count
|
|
InterlockedDecrement (&cReaders);
|
|
|
|
// Claim the <csExclusive> critical section. This call blocks if there's
|
|
// an active writer or if there's a writer waiting for active readers to
|
|
// complete.
|
|
EnterCriticalSection(&csExclusive);
|
|
|
|
// Claim access to the reader count. If this blocks, it's only for the
|
|
// briefest moment, while other threads go through to increment or
|
|
// decrement the reader count.
|
|
EnterCriticalSection(&csReader);
|
|
|
|
// Increment the reader count. If this is the first reader, we reset the
|
|
// hevReadDone event so that the next writer blocks.
|
|
if (InterlockedIncrement (&cReaders) >= 0)
|
|
{
|
|
if (!m_fReader)
|
|
{
|
|
SetEvent (hevReaderPresent);
|
|
ResetEvent(hevReadDone);
|
|
m_fReader = TRUE;
|
|
}
|
|
}
|
|
|
|
// Release access to the reader count
|
|
LeaveCriticalSection(&csReader);
|
|
|
|
// Release access to the <csExclusive> critical section. This enables
|
|
// other readers to come through and the next writer to wait for active
|
|
// readers to complete (which in turn prevents new readers from entering).
|
|
LeaveCriticalSection(&csExclusive);
|
|
}
|
|
else
|
|
{
|
|
// Verify that since this isn't the read lock, that it's the write lock
|
|
Assert(lt == SLT_WRITE);
|
|
|
|
// Gain access to the writer count
|
|
EnterCriticalSection(&csWriter);
|
|
|
|
// Increment the writer count. If this is the writer reader, we set the
|
|
// hevWriterPresent event so that new readers give way to the writer.
|
|
if (InterlockedIncrement (&cWriters) == 0)
|
|
{
|
|
SetEvent (hevWriterPresent);
|
|
}
|
|
|
|
// Release access to the writer count
|
|
LeaveCriticalSection(&csWriter);
|
|
|
|
// Claim the <csExclusive> critical section. This not only prevents other
|
|
// threads from claiming the write lock, but also prevents any new threads
|
|
// from claiming the read lock.
|
|
EnterCriticalSection(&csExclusive);
|
|
|
|
// Wait for the active readers to release their read locks.
|
|
return WaitForSingleObject(hevReadDone, INFINITE) == WAIT_OBJECT_0;
|
|
}
|
|
|
|
return TRUE;
|
|
} //End Lock
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
SYNCHRO class - Unlock member function
|
|
---------------------------------------------------------------------------- */
|
|
inline BOOL UTSemCheapReadWrite::UnLock(SYNCH_LOCK_TYPE lt)
|
|
{
|
|
// Verify that the object is valid
|
|
if (! IsValid())
|
|
return FALSE;
|
|
|
|
// Verify that the specified lock type is supported by this implementation
|
|
if (lt == SLT_READPROMOTE)
|
|
return FALSE;
|
|
|
|
// Release the read lock or write lock as specified
|
|
if (lt == SLT_READ)
|
|
{
|
|
// Claim access to the reader count. If this blocks, it's only for the
|
|
// briefest moment, while other threads go through to increment or
|
|
// decrement the reader count.
|
|
EnterCriticalSection(&csReader);
|
|
|
|
// Decrement the reader count. If this is the last reader, set
|
|
// <hevReadDone>, which allows the first waiting writer to proceed.
|
|
if (InterlockedDecrement (&cReaders) < 0)
|
|
{
|
|
ResetEvent (hevReaderPresent);
|
|
SetEvent(hevReadDone);
|
|
m_fReader = FALSE;
|
|
}
|
|
|
|
// Release access to the reader count
|
|
LeaveCriticalSection(&csReader);
|
|
}
|
|
else
|
|
{
|
|
// Verify that since this isn't the read lock, that it's the write lock
|
|
Assert(lt == SLT_WRITE);
|
|
|
|
// Gain access to the writer count
|
|
EnterCriticalSection(&csWriter);
|
|
|
|
// Decrement the writer count. If this is the last writer, we reset the
|
|
// hevWriterPresent event.
|
|
if (InterlockedDecrement (&cWriters) < 0)
|
|
{
|
|
ResetEvent (hevWriterPresent);
|
|
}
|
|
|
|
// Release access to the writer count
|
|
LeaveCriticalSection(&csWriter);
|
|
|
|
// Make <csExclusive> available to one other writer or to the first reader
|
|
LeaveCriticalSection(&csExclusive);
|
|
}
|
|
|
|
return TRUE;
|
|
} //End Unlock
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@class CSemExclusive:
|
|
|
|
@rev 0 | 4th Feb,95 | GaganC | Created
|
|
---------------------------------------------------------------------------- */
|
|
class CSemExclusive
|
|
{
|
|
public:
|
|
CSemExclusive (void);
|
|
~CSemExclusive (void);
|
|
void Lock (void);
|
|
void UnLock (void);
|
|
private:
|
|
CRITICAL_SECTION m_csx;
|
|
}; //end class CSemExclusive
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// IMPLEMENTATION of class CSemExclusive
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
---------------------------------------------------------------------------- */
|
|
inline CSemExclusive::CSemExclusive
|
|
(
|
|
void
|
|
)
|
|
{
|
|
InitializeCriticalSection (&m_csx);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
---------------------------------------------------------------------------- */
|
|
inline CSemExclusive::~CSemExclusive
|
|
(
|
|
void
|
|
)
|
|
{
|
|
DeleteCriticalSection (&m_csx);
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
---------------------------------------------------------------------------- */
|
|
inline void CSemExclusive::Lock
|
|
(
|
|
void
|
|
)
|
|
{
|
|
EnterCriticalSection (&m_csx);
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
---------------------------------------------------------------------------- */
|
|
inline void CSemExclusive::UnLock
|
|
(
|
|
void
|
|
)
|
|
{
|
|
LeaveCriticalSection (&m_csx);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@class CSemExclusiveSL:
|
|
|
|
---------------------------------------------------------------------------- */
|
|
class CSemExclusiveSL
|
|
{
|
|
public:
|
|
CSemExclusiveSL (void);
|
|
~CSemExclusiveSL (void);
|
|
|
|
void Lock (void);
|
|
void UnLock (void);
|
|
private:
|
|
DWORD volatile m_dwLock;
|
|
DWORD volatile *m_pdwLock;
|
|
DWORD volatile m_dwOwningThread;
|
|
ULONG volatile m_ulRecursionCount;
|
|
};
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
---------------------------------------------------------------------------- */
|
|
inline CSemExclusiveSL::CSemExclusiveSL ( void )
|
|
{
|
|
m_dwOwningThread = 0;
|
|
m_ulRecursionCount = 0;
|
|
m_dwLock = 0;
|
|
m_pdwLock = &m_dwLock;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
---------------------------------------------------------------------------- */
|
|
inline CSemExclusiveSL::~CSemExclusiveSL ( void )
|
|
{
|
|
//Nothing to do
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
** Lock -- Obtains an SMP safe lock on the address given.
|
|
** WARNING: Does not release any semaphore or critsec when waiting.
|
|
**
|
|
|
|
@rev 0 Created 04/20/93 by LaleD
|
|
@rev 1 modified 7/13/96 by shaiwals
|
|
---------------------------------------------------------------------------- */
|
|
inline void CSemExclusiveSL::Lock ( void )
|
|
{
|
|
DWORD i;
|
|
DWORD n = 0;
|
|
int m = 0;
|
|
|
|
|
|
startover:
|
|
|
|
if (InterlockedExchange((long *)m_pdwLock, 1) == 0)
|
|
{
|
|
m_dwOwningThread = GetCurrentThreadId();
|
|
return;
|
|
}
|
|
|
|
if (m_dwOwningThread == GetCurrentThreadId())
|
|
{
|
|
m_ulRecursionCount++;
|
|
return;
|
|
}
|
|
|
|
// Give away my time slice to another thread as the probability
|
|
// of my getting this lock right away are low - shaiwals
|
|
//Sleep (1);
|
|
|
|
/* retry using safe test only after cheaper, unsafe test succeeds */
|
|
for (i = 0 ; i < (DWORD)(10000) ; i++)
|
|
{
|
|
if (*m_pdwLock == 0)
|
|
{
|
|
goto startover;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Yield after hitting the cspinctr limit
|
|
** Sleep(0) only yields to threads of same priority
|
|
** if hit limit 10000 times, sleep 5sec and test for kill
|
|
** this provides a chance to CTRL-C it if stuck in loop
|
|
*/
|
|
|
|
m++;
|
|
|
|
if( ( m % 10000 ) == 0)
|
|
{
|
|
Sleep(5000);
|
|
}
|
|
else
|
|
{
|
|
Sleep(0);
|
|
}
|
|
|
|
goto startover;
|
|
/* try again */
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
@mfunc
|
|
|
|
---------------------------------------------------------------------------- */
|
|
inline void CSemExclusiveSL::UnLock ( void )
|
|
{
|
|
AssertSz (m_dwOwningThread == GetCurrentThreadId(), \
|
|
"Lock released by someone who doesnt own the lock!!!");
|
|
|
|
if (m_ulRecursionCount > 0)
|
|
{
|
|
m_ulRecursionCount--;
|
|
return;
|
|
}
|
|
|
|
m_dwOwningThread = 0;
|
|
*m_pdwLock = 0;
|
|
}
|
|
|
|
|
|
|
|
#endif __UTSEM_H__
|