home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / include / utsem.h < prev    next >
C/C++ Source or Header  |  1998-04-25  |  24KB  |  859 lines

  1. /* ----------------------------------------------------------------------------
  2. Microsoft    D.T.C (Distributed Transaction Coordinator)
  3.  
  4. (c)    1995    Microsoft Corporation.    All Rights Reserved
  5.  
  6. @doc
  7.  
  8. @module UTSem.H  |
  9.  
  10.     SYNCHRO - C++ class to provide synchronization object encapsulation
  11.  
  12.     This implementation of the SYNCHRO class provides multi-read XOR single-write
  13.     (a.k.a. shared vs. exclusive) lock capabilities, with protection against
  14.     writer starvation. Code origianly borrowed from 
  15.     (c) 1994 by Daniel S. Glasser and then modified for our needs.
  16.  
  17. @devnote None
  18.  
  19. @rev    3    | 1st-Aug-1996    |    GaganC        | Added the spin lock code and class
  20. @rev    2    | 31-May-1996    |    GaganC        | Removed the special code for x86
  21. @rev    1    | 18th Jan, 96    |    GaganC        | Special cased UTGuard for X86
  22. @rev     0     | 4th Feb,95    |    GaganC         | Created
  23. ---------------------------------------------------------------------------- */
  24. #ifndef __UTSEM_H__
  25. #define __UTSEM_H__
  26.  
  27.  
  28. // -------------------------------------------------------------
  29. //                INCLUDES
  30. // -------------------------------------------------------------
  31. #include "UTAssert.H"
  32.  
  33.  
  34. // -------------------------------------------------------------
  35. //                CONSTANTS AND TYPES
  36. // -------------------------------------------------------------
  37. typedef enum {SLC_WRITE, SLC_READWRITE, SLC_READWRITEPROMOTE}
  38.              SYNCH_LOCK_CAPS;
  39.  
  40. typedef enum {SLT_READ, SLT_READPROMOTE, SLT_WRITE}
  41.              SYNCH_LOCK_TYPE;
  42.  
  43. const int NUM_SYNCH_LOCK_TYPES = SLT_WRITE + 1;
  44.  
  45.  
  46.  
  47. // -------------------------------------------------------------
  48. //                FORWARDS
  49. // -------------------------------------------------------------
  50. class CSemExclusive;
  51. class CSemExclusiveSL;
  52. class UTGuard;
  53. class UTSemReadWrite;
  54. class UTSemCheapReadWrite;
  55.  
  56.  
  57. // -------------------------------------------------------------
  58. //                    GLOBAL HELPER FUNCTIONS
  59. // -------------------------------------------------------------
  60.  
  61.  
  62. /* ----------------------------------------------------------------------------
  63.  @func Description:<nl>
  64.  
  65.    Guarantees isolated increments of *pl.<nl><nl>
  66.  
  67.  Usage:<nl>
  68.    Use instead of InterlockedIncrement for Win16/Win32 portability.<nl><nl>
  69.  
  70.  @rev 0 | 3/21/95 | Rcraig | Created.
  71. ---------------------------------------------------------------------------- */
  72. inline LONG SafeIncrement ( LPLONG pl )
  73. {
  74.     return (InterlockedIncrement (pl));
  75. } // SafeIncrement
  76.  
  77.  
  78.  
  79. /* ----------------------------------------------------------------------------
  80.  @func Description:<nl>
  81.    Win16/Win32 abstraction wrapper: 
  82.    Guarantees isolated decrements of *pl.<nl><nl>
  83.  
  84.  Usage:<nl>
  85.    Use instead of InterlockedDecrement for Win16/Win32 portability.<nl><nl>
  86.  
  87.  @rev 0 | 3/21/95 | Rcraig | Created.
  88. ---------------------------------------------------------------------------- */
  89. inline LONG SafeDecrement ( LPLONG pl )
  90. {
  91.     return (InterlockedDecrement (pl));
  92. } // SafeDecrement
  93.  
  94.  
  95.  
  96. /* ----------------------------------------------------------------------------
  97. @class    UTGuard
  98.     This object represents a guard that can be acquired or released. The 
  99.     advantage with useing this instead of a critical section is that this
  100.     is non blocking. If AcquireGuard fails, it will return false and will not
  101.     block.
  102.  
  103. @rev     0     | 4th Feb,95 | GaganC         | Created
  104. ---------------------------------------------------------------------------- */
  105. class UTGuard
  106. {
  107. private:
  108.     long            m_lVal;
  109.  
  110. public:
  111.     //@cmember Constructor
  112.     UTGuard (void);
  113.     //@cmember Destructor
  114.     ~UTGuard (void);
  115.  
  116.     //@cmember    Acquires the guard
  117.     BOOL            AcquireGuard (void);
  118.     //@cmember    Releases the guard
  119.     void            ReleaseGuard (void);
  120.     
  121.     //@cmember    Initializes the Guard
  122.     void            Init (void);
  123. } ; //End class UTGuard
  124.  
  125.  
  126.  
  127. //-----------------------------------------------------------------------------
  128. //
  129. //        IMPLEMENTATION of class UTGuard
  130. //
  131. //-----------------------------------------------------------------------------
  132.  
  133.  
  134. /* ----------------------------------------------------------------------------
  135. @mfunc 
  136.  
  137. ---------------------------------------------------------------------------- */
  138. inline UTGuard::UTGuard ( void )
  139. {
  140.     m_lVal = 0;
  141. }
  142.  
  143.  
  144.  
  145. /* ----------------------------------------------------------------------------
  146. @mfunc 
  147.  
  148. ---------------------------------------------------------------------------- */
  149. inline UTGuard::~UTGuard ( void )
  150. {
  151.     //Do nothing
  152. }
  153.  
  154.  
  155.  
  156. /* ----------------------------------------------------------------------------
  157. @mfunc 
  158.  
  159. ---------------------------------------------------------------------------- */
  160. inline BOOL    UTGuard::AcquireGuard (void)
  161. {
  162.     long        lVal;
  163.  
  164.     lVal = InterlockedExchange (&m_lVal, 1);
  165.  
  166.     return (lVal == 0);
  167. }
  168.  
  169.  
  170.  
  171. /* ----------------------------------------------------------------------------
  172. @mfunc 
  173.  
  174. ---------------------------------------------------------------------------- */
  175. inline void    UTGuard::ReleaseGuard (void)
  176. {
  177.     m_lVal = 0;
  178. }
  179.  
  180.  
  181. /* ----------------------------------------------------------------------------
  182. @mfunc 
  183.  
  184. ---------------------------------------------------------------------------- */
  185. void inline UTGuard::Init ( void )
  186. {
  187.     m_lVal = 0;
  188. }
  189.  
  190.  
  191.  
  192. /* ----------------------------------------------------------------------------
  193. @class UTSemReadWrite
  194.  
  195. @rev     0     | 4th Feb,95 | GaganC         | Created
  196. ---------------------------------------------------------------------------- */
  197. class UTSemReadWrite
  198. {
  199. private:
  200.     CRITICAL_SECTION csExclusive;    // Critical section object to synchronize writers
  201.     CRITICAL_SECTION csReader;        // Critical section object to synchronize readers
  202.     HANDLE hevReadDone;                // Manual-reset event to notify writers of 
  203.                                     //reader completion
  204.     int cReaders;                    // Count of current readers
  205.  
  206.     BOOL fInitSucceeded;            // TRUE if the constructor function succeeded
  207.  
  208. public:
  209.     UTSemReadWrite(void);                // Constructor
  210.     ~UTSemReadWrite(void);                // Destructor
  211.  
  212.     // This implementation supports Read and Write locks
  213.     SYNCH_LOCK_CAPS GetCaps(void) { return SLC_READWRITE; };
  214.  
  215.     // This object is valid if it was initialized
  216.     BOOL IsValid(void) { return fInitSucceeded; }
  217.  
  218.     BOOL Lock(SYNCH_LOCK_TYPE);    // Lock the object
  219.     BOOL UnLock(SYNCH_LOCK_TYPE);    // Unlock the object
  220. };
  221.  
  222.  
  223.  
  224.  
  225. //-----------------------------------------------------------------------------
  226. //
  227. //        IMPLEMENTATION of class UTSemReadWrite
  228. //
  229. //-----------------------------------------------------------------------------
  230.  
  231. /* ----------------------------------------------------------------------------
  232. @mfunc 
  233.  
  234.     SYNCHRO class - Constructor
  235.  
  236.     Create the event, initialize the critical section objects and reader count,
  237.     and return.
  238. ---------------------------------------------------------------------------- */
  239. inline UTSemReadWrite::UTSemReadWrite(void)
  240. {
  241.     // Create the manual-reset event (the only init that can fail)
  242.     hevReadDone = CreateEvent(NULL, TRUE, TRUE, NULL);
  243.  
  244.     fInitSucceeded = hevReadDone != NULL;
  245.  
  246.     // If we created the event, proceed with the risk-free initialization
  247.     if (fInitSucceeded)
  248.     {
  249.         cReaders = 0;
  250.         InitializeCriticalSection(&csExclusive);
  251.         InitializeCriticalSection(&csReader);
  252.     }
  253.  
  254.     return;
  255. }
  256.  
  257.  
  258. /* ----------------------------------------------------------------------------
  259. @mfunc 
  260.  
  261.     SYNCHRO class - Destructor
  262.  
  263.     Free the event, delete the critical section objects, and return.
  264. ---------------------------------------------------------------------------- */
  265. inline UTSemReadWrite::~UTSemReadWrite(void)
  266. {
  267.     if (IsValid())
  268.     {
  269.         CloseHandle(hevReadDone);
  270.         DeleteCriticalSection(&csExclusive);
  271.         DeleteCriticalSection(&csReader);
  272.     }
  273.  
  274.     return;
  275. }
  276.  
  277.  
  278.  
  279.  
  280. /* ----------------------------------------------------------------------------
  281. @mfunc 
  282.  
  283.     SYNCHRO class - Lock member function
  284. ---------------------------------------------------------------------------- */
  285. inline BOOL UTSemReadWrite::Lock(SYNCH_LOCK_TYPE lt)
  286. {
  287.     // Verify that the object is valid
  288.     if (! IsValid())
  289.         return FALSE;
  290.  
  291.     // Verify that the specified lock type is supported by this implementation
  292.     if (lt == SLT_READPROMOTE)
  293.         return FALSE;
  294.  
  295.     // Claim the read lock or write lock as specified
  296.     if (lt == SLT_READ)
  297.     {
  298.         // Claim the <csExclusive> critical section.  This call blocks if there's
  299.         // an active writer or if there's a writer waiting for active readers to
  300.         // complete.
  301.         EnterCriticalSection(&csExclusive);
  302.  
  303.         // Claim access to the reader count.  If this blocks, it's only for the
  304.         // briefest moment, while other threads go through to increment or
  305.         // decrement the reader count.
  306.         EnterCriticalSection(&csReader);
  307.  
  308.         // Increment the reader count.  If this is the first reader, we reset the
  309.         // hevReadDone event so that the next writer blocks.
  310.         if (cReaders++ == 0)
  311.             ResetEvent(hevReadDone);
  312.  
  313.         // Release access to the reader count
  314.         LeaveCriticalSection(&csReader);
  315.  
  316.         // Release access to the <csExclusive> critical section.  This enables
  317.         // other readers to come through and the next writer to wait for active
  318.         // readers to complete (which in turn prevents new readers from entering).
  319.         LeaveCriticalSection(&csExclusive);
  320.     }
  321.     else
  322.     {
  323.         // Verify that since this isn't the read lock, that it's the write lock
  324.         Assert(lt == SLT_WRITE);
  325.  
  326.         // Claim the <csExclusive> critical section.  This not only prevents other
  327.         // threads from claiming the write lock, but also prevents any new threads
  328.         // from claiming the read lock.
  329.         EnterCriticalSection(&csExclusive);
  330.  
  331.         // Wait for the active readers to release their read locks.
  332.         return WaitForSingleObject(hevReadDone, INFINITE) == WAIT_OBJECT_0;
  333.     }
  334.  
  335.     return TRUE;
  336. } //End Lock
  337.  
  338.  
  339.  
  340. /* ----------------------------------------------------------------------------
  341. @mfunc 
  342.  
  343.     SYNCHRO class - Unlock member function
  344. ---------------------------------------------------------------------------- */
  345. inline BOOL UTSemReadWrite::UnLock(SYNCH_LOCK_TYPE lt)
  346. {
  347.     // Verify that the object is valid
  348.     if (! IsValid())
  349.         return FALSE;
  350.  
  351.     // Verify that the specified lock type is supported by this implementation
  352.     if (lt == SLT_READPROMOTE)
  353.         return FALSE;
  354.  
  355.     // Release the read lock or write lock as specified
  356.     if (lt == SLT_READ)
  357.     {
  358.         // Claim access to the reader count.  If this blocks, it's only for the
  359.         // briefest moment, while other threads go through to increment or
  360.         // decrement the reader count.
  361.         EnterCriticalSection(&csReader);
  362.  
  363.         // Decrement the reader count.  If this is the last reader, set 
  364.         // <hevReadDone>, which allows the first waiting writer to proceed.
  365.         if (--cReaders == 0)
  366.             SetEvent(hevReadDone);
  367.  
  368.         // Release access to the reader count
  369.         LeaveCriticalSection(&csReader);
  370.     }
  371.     else
  372.     {
  373.         // Verify that since this isn't the read lock, that it's the write lock
  374.         Assert(lt == SLT_WRITE);
  375.  
  376.         // Make <csExclusive> available to one other writer or to the first reader
  377.         LeaveCriticalSection(&csExclusive);
  378.     }
  379.  
  380.     return TRUE;
  381. } //End Unlock
  382.  
  383.  
  384. /* ----------------------------------------------------------------------------
  385. @class UTSemCheapReadWrite
  386.  
  387. @rev     0     | 5/1/97     | Shaiwals        | Created using UTSemReadWrite, reader
  388.             |             |                | access to the lock is cheaper if 
  389.             |             |                | there is already a reader present
  390. ---------------------------------------------------------------------------- */
  391. class UTSemCheapReadWrite
  392. {
  393. private:
  394.     CRITICAL_SECTION csExclusive;    // Critical section object to provide core locking
  395.     CRITICAL_SECTION csReader;        // Critical section object to synchronize readers
  396.     CRITICAL_SECTION csWriter;        // Critical section object to synchronize writers
  397.     HANDLE hevReadDone;                // Manual-reset event to notify writers of 
  398.                                     // reader completion
  399.  
  400.     HANDLE hevReaderPresent;        // Readers are currently present
  401.     HANDLE hevWriterPresent;        // Writers are currently present
  402.     long cReaders;                    // Count of current readers
  403.     long cWriters;                    // Count of writers waiting
  404.  
  405.     BOOL fInitSucceeded;            // TRUE if the constructor function succeeded
  406.     BOOL m_fReader;                    // Flag to signal that readers presence has
  407.                                     // been notifed
  408.  
  409. public:
  410.     UTSemCheapReadWrite(void);                // Constructor
  411.     ~UTSemCheapReadWrite(void);                // Destructor
  412.  
  413.     // This implementation supports Read and Write locks
  414.     SYNCH_LOCK_CAPS GetCaps(void) { return SLC_READWRITE; };
  415.  
  416.     // This object is valid if it was initialized
  417.     BOOL IsValid(void) { return fInitSucceeded; }
  418.  
  419.     BOOL Lock(SYNCH_LOCK_TYPE);    // Lock the object
  420.     BOOL UnLock(SYNCH_LOCK_TYPE);    // Unlock the object
  421. };
  422.  
  423.  
  424.  
  425.  
  426. //-----------------------------------------------------------------------------
  427. //
  428. //        IMPLEMENTATION of class UTSemCheapReadWrite
  429. //
  430. //-----------------------------------------------------------------------------
  431.  
  432. /* ----------------------------------------------------------------------------
  433. @mfunc 
  434.  
  435.     SYNCHRO class - Constructor
  436.  
  437.     Create the event, initialize the critical section objects and reader count,
  438.     and return.
  439. ---------------------------------------------------------------------------- */
  440. inline UTSemCheapReadWrite::UTSemCheapReadWrite(void)
  441. {
  442.     // Create the manual-reset event (the only init that can fail)
  443.     hevReadDone = CreateEvent(NULL, TRUE, TRUE, NULL);
  444.     hevReaderPresent = CreateEvent(NULL, TRUE, FALSE, NULL);
  445.     hevWriterPresent = CreateEvent(NULL, TRUE, FALSE, NULL);
  446.  
  447.     fInitSucceeded = (hevReadDone != NULL) && 
  448.                         (hevReaderPresent != NULL) && 
  449.                         (hevWriterPresent != NULL);
  450.  
  451.     // If we created the event, proceed with the risk-free initialization
  452.     if (fInitSucceeded)
  453.     {
  454.         cReaders = -1;
  455.         cWriters = -1;
  456.         m_fReader = FALSE;
  457.         InitializeCriticalSection(&csExclusive);
  458.         InitializeCriticalSection(&csReader);
  459.         InitializeCriticalSection(&csWriter);
  460.     }
  461.  
  462.     return;
  463. }
  464.  
  465.  
  466. /* ----------------------------------------------------------------------------
  467. @mfunc 
  468.  
  469.     SYNCHRO class - Destructor
  470.  
  471.     Free the event, delete the critical section objects, and return.
  472. ---------------------------------------------------------------------------- */
  473. inline UTSemCheapReadWrite::~UTSemCheapReadWrite(void)
  474. {
  475.     if (IsValid())
  476.     {
  477.         CloseHandle(hevReadDone);
  478.         DeleteCriticalSection(&csExclusive);
  479.         DeleteCriticalSection(&csReader);
  480.     }
  481.  
  482.     return;
  483. }
  484.  
  485.  
  486.  
  487.  
  488. /* ----------------------------------------------------------------------------
  489. @mfunc 
  490.  
  491.     SYNCHRO class - Lock member function
  492. ---------------------------------------------------------------------------- */
  493. inline BOOL UTSemCheapReadWrite::Lock(SYNCH_LOCK_TYPE lt)
  494. {
  495.     // Verify that the object is valid
  496.     if (! IsValid())
  497.         return FALSE;
  498.  
  499.     // Verify that the specified lock type is supported by this implementation
  500.     if (lt == SLT_READPROMOTE)
  501.         return FALSE;
  502.  
  503.     // Claim the read lock or write lock as specified
  504.     if (lt == SLT_READ)
  505.     {
  506.         // First try to get the reader lock cheaply by incrementing
  507.         // the reader count.  Only if reader count is positive
  508.         // do we try and test that a reader is present
  509.         if (InterlockedIncrement (&cReaders) > 0)
  510.         {
  511.             // Test that there is actually a reader holding on the the lock.
  512.             // It is possible to that the reader count is greater that -1
  513.             // but still there are no readers who have actually acquired the
  514.             // lock
  515.             if (WaitForSingleObject (hevReaderPresent, 0) == WAIT_OBJECT_0)
  516.             {
  517.                 // Only if there are no writers waiting to acquire the lock
  518.                 // do we try to acquire the lock. Without this we cannot
  519.                 // guarantee that the writer wont starve.
  520.                 if (WaitForSingleObject (hevWriterPresent, 0) == WAIT_TIMEOUT)
  521.                     return TRUE;
  522.             }
  523.         }
  524.  
  525.         // Decrement extra reader count
  526.         InterlockedDecrement (&cReaders);
  527.  
  528.         // Claim the <csExclusive> critical section.  This call blocks if there's
  529.         // an active writer or if there's a writer waiting for active readers to
  530.         // complete.
  531.         EnterCriticalSection(&csExclusive);
  532.  
  533.         // Claim access to the reader count.  If this blocks, it's only for the
  534.         // briefest moment, while other threads go through to increment or
  535.         // decrement the reader count.
  536.         EnterCriticalSection(&csReader);
  537.  
  538.         // Increment the reader count.  If this is the first reader, we reset the
  539.         // hevReadDone event so that the next writer blocks.
  540.         if (InterlockedIncrement (&cReaders) >= 0)
  541.         {
  542.             if (!m_fReader)
  543.             {
  544.                 SetEvent (hevReaderPresent);
  545.                 ResetEvent(hevReadDone);
  546.                 m_fReader = TRUE;
  547.             }
  548.         }
  549.  
  550.         // Release access to the reader count
  551.         LeaveCriticalSection(&csReader);
  552.  
  553.         // Release access to the <csExclusive> critical section.  This enables
  554.         // other readers to come through and the next writer to wait for active
  555.         // readers to complete (which in turn prevents new readers from entering).
  556.         LeaveCriticalSection(&csExclusive);
  557.     }
  558.     else
  559.     {
  560.         // Verify that since this isn't the read lock, that it's the write lock
  561.         Assert(lt == SLT_WRITE);
  562.  
  563.         // Gain access to the writer count
  564.         EnterCriticalSection(&csWriter);
  565.  
  566.         // Increment the writer count.  If this is the writer reader, we set the
  567.         // hevWriterPresent event so that new readers give way to the writer.
  568.         if (InterlockedIncrement (&cWriters) == 0)
  569.         {
  570.             SetEvent (hevWriterPresent);
  571.         }
  572.  
  573.         // Release access to the writer count
  574.         LeaveCriticalSection(&csWriter);
  575.  
  576.         // Claim the <csExclusive> critical section.  This not only prevents other
  577.         // threads from claiming the write lock, but also prevents any new threads
  578.         // from claiming the read lock.
  579.         EnterCriticalSection(&csExclusive);
  580.  
  581.         // Wait for the active readers to release their read locks.
  582.         return WaitForSingleObject(hevReadDone, INFINITE) == WAIT_OBJECT_0;
  583.     }
  584.  
  585.     return TRUE;
  586. } //End Lock
  587.  
  588.  
  589.  
  590. /* ----------------------------------------------------------------------------
  591. @mfunc 
  592.  
  593.     SYNCHRO class - Unlock member function
  594. ---------------------------------------------------------------------------- */
  595. inline BOOL UTSemCheapReadWrite::UnLock(SYNCH_LOCK_TYPE lt)
  596. {
  597.     // Verify that the object is valid
  598.     if (! IsValid())
  599.         return FALSE;
  600.  
  601.     // Verify that the specified lock type is supported by this implementation
  602.     if (lt == SLT_READPROMOTE)
  603.         return FALSE;
  604.  
  605.     // Release the read lock or write lock as specified
  606.     if (lt == SLT_READ)
  607.     {
  608.         // Claim access to the reader count.  If this blocks, it's only for the
  609.         // briefest moment, while other threads go through to increment or
  610.         // decrement the reader count.
  611.         EnterCriticalSection(&csReader);
  612.  
  613.         // Decrement the reader count.  If this is the last reader, set 
  614.         // <hevReadDone>, which allows the first waiting writer to proceed.
  615.         if (InterlockedDecrement (&cReaders) < 0)
  616.         {
  617.             ResetEvent (hevReaderPresent);
  618.             SetEvent(hevReadDone);
  619.             m_fReader = FALSE;
  620.         }
  621.  
  622.         // Release access to the reader count
  623.         LeaveCriticalSection(&csReader);
  624.     }
  625.     else
  626.     {
  627.         // Verify that since this isn't the read lock, that it's the write lock
  628.         Assert(lt == SLT_WRITE);
  629.         
  630.         // Gain access to the writer count
  631.         EnterCriticalSection(&csWriter);
  632.  
  633.         // Decrement the writer count.  If this is the last writer, we reset the
  634.         // hevWriterPresent event.
  635.         if (InterlockedDecrement (&cWriters) < 0)
  636.         {
  637.             ResetEvent (hevWriterPresent);
  638.         }
  639.  
  640.         // Release access to the writer count
  641.         LeaveCriticalSection(&csWriter);
  642.  
  643.         // Make <csExclusive> available to one other writer or to the first reader
  644.         LeaveCriticalSection(&csExclusive);
  645.     }
  646.  
  647.     return TRUE;
  648. } //End Unlock
  649.  
  650.  
  651.  
  652. /* ----------------------------------------------------------------------------
  653. @class CSemExclusive:
  654.  
  655.     @rev     0     | 4th Feb,95 | GaganC         | Created
  656. ---------------------------------------------------------------------------- */
  657. class CSemExclusive
  658. {
  659. public:
  660.     CSemExclusive (void);
  661.     ~CSemExclusive (void);
  662.     void Lock (void);
  663.     void UnLock (void);
  664. private:
  665.     CRITICAL_SECTION m_csx;
  666. };    //end class CSemExclusive
  667.  
  668.  
  669.  
  670.  
  671. //-----------------------------------------------------------------------------
  672. //
  673. //        IMPLEMENTATION of class CSemExclusive
  674. //
  675. //-----------------------------------------------------------------------------
  676. /* ----------------------------------------------------------------------------
  677. @mfunc 
  678. ---------------------------------------------------------------------------- */
  679. inline CSemExclusive::CSemExclusive 
  680.     (
  681.         void
  682.     )
  683. {
  684.     InitializeCriticalSection (&m_csx);
  685. }
  686.  
  687. /* ----------------------------------------------------------------------------
  688. @mfunc 
  689.  
  690. ---------------------------------------------------------------------------- */
  691. inline CSemExclusive::~CSemExclusive 
  692.     (
  693.         void
  694.     )
  695. {
  696.     DeleteCriticalSection (&m_csx);
  697. }
  698.  
  699.  
  700. /* ----------------------------------------------------------------------------
  701. @mfunc 
  702. ---------------------------------------------------------------------------- */
  703. inline void CSemExclusive::Lock
  704.     (
  705.         void
  706.     )
  707. {
  708.     EnterCriticalSection (&m_csx);
  709. }
  710.  
  711.  
  712. /* ----------------------------------------------------------------------------
  713. @mfunc 
  714. ---------------------------------------------------------------------------- */
  715. inline void CSemExclusive::UnLock
  716.     (
  717.         void
  718.     )
  719. {
  720.     LeaveCriticalSection (&m_csx);
  721. }
  722.  
  723.  
  724.  
  725.  
  726.  
  727.  
  728. /* ----------------------------------------------------------------------------
  729. @class CSemExclusiveSL:
  730.  
  731. ---------------------------------------------------------------------------- */
  732. class CSemExclusiveSL
  733. {
  734. public:
  735.     CSemExclusiveSL (void);
  736.     ~CSemExclusiveSL (void);
  737.  
  738.     void Lock (void);
  739.     void UnLock (void);
  740. private:
  741.     DWORD volatile m_dwLock;
  742.     DWORD volatile *m_pdwLock;
  743.     DWORD volatile m_dwOwningThread;
  744.     ULONG volatile m_ulRecursionCount;
  745. };
  746.  
  747.  
  748. /* ----------------------------------------------------------------------------
  749. @mfunc 
  750.  
  751. ---------------------------------------------------------------------------- */
  752. inline CSemExclusiveSL::CSemExclusiveSL ( void )
  753. {
  754.     m_dwOwningThread = 0;
  755.     m_ulRecursionCount = 0;
  756.     m_dwLock = 0;
  757.     m_pdwLock = &m_dwLock;
  758. }
  759.  
  760.  
  761. /* ----------------------------------------------------------------------------
  762. @mfunc 
  763.  
  764. ---------------------------------------------------------------------------- */
  765. inline CSemExclusiveSL::~CSemExclusiveSL ( void )
  766. {
  767.     //Nothing to do
  768. }
  769.  
  770.  
  771. /* ----------------------------------------------------------------------------
  772. @mfunc 
  773.  
  774. **  Lock -- Obtains an SMP safe lock on the address given.
  775. **    WARNING: Does not release any semaphore or critsec when waiting.
  776. **
  777.  
  778. @rev 0  Created 04/20/93 by LaleD 
  779. @rev 1    modified 7/13/96 by shaiwals
  780. ---------------------------------------------------------------------------- */
  781. inline void CSemExclusiveSL::Lock ( void )
  782. {
  783.     DWORD    i;
  784.     DWORD    n    =    0;
  785.     int        m    =    0;
  786.  
  787.  
  788. startover:
  789.  
  790.     if (InterlockedExchange((long *)m_pdwLock, 1) == 0)
  791.     {
  792.         m_dwOwningThread = GetCurrentThreadId();
  793.         return;
  794.     }
  795.  
  796.     if (m_dwOwningThread == GetCurrentThreadId())
  797.     {
  798.         m_ulRecursionCount++;
  799.         return;
  800.     }
  801.  
  802.     // Give away my time slice to another thread as the probability
  803.     // of my getting this lock right away are low - shaiwals
  804.     //Sleep (1); 
  805.  
  806.     /* retry using safe test only after cheaper, unsafe test succeeds */
  807.     for (i = 0 ; i < (DWORD)(10000) ; i++)
  808.     {
  809.         if (*m_pdwLock == 0)
  810.         {
  811.             goto startover;
  812.         }
  813.     }
  814.  
  815.     /*
  816.     **  Yield after hitting the cspinctr limit
  817.     **    Sleep(0) only yields to threads of same priority
  818.     **    if hit limit 10000 times, sleep 5sec and test for kill
  819.     **    this provides a chance to CTRL-C it if stuck in loop
  820.     */
  821.     
  822.     m++;
  823.  
  824.     if( ( m % 10000 ) == 0)
  825.     {
  826.         Sleep(5000);
  827.     }
  828.     else
  829.     {
  830.         Sleep(0);
  831.     }
  832.  
  833.     goto startover;
  834.     /* try again */
  835. }
  836.  
  837. /* ----------------------------------------------------------------------------
  838. @mfunc 
  839.  
  840. ---------------------------------------------------------------------------- */
  841. inline void CSemExclusiveSL::UnLock ( void )
  842. {
  843.     AssertSz (m_dwOwningThread == GetCurrentThreadId(), \
  844.                         "Lock released by someone who doesnt own the lock!!!");
  845.  
  846.     if (m_ulRecursionCount > 0)
  847.     {
  848.         m_ulRecursionCount--;
  849.         return;
  850.     }
  851.  
  852.     m_dwOwningThread = 0;
  853.     *m_pdwLock = 0;
  854. }
  855.  
  856.  
  857.  
  858. #endif __UTSEM_H__
  859.