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