Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 lines
5.3 KiB

  1. //
  2. // This file contains test implmentations of reader and writer locks.
  3. // These are intended to be used with the template class in rw.h so that
  4. // different implementations can be plugged in and tested.
  5. //
  6. // The semantics of the read/write classes should be as follows :
  7. // Functions CAN NOT be recursively called,
  8. // Multiple Readers should be able to enter the lock
  9. // Only a single writer may execute at a time.
  10. //
  11. #ifndef WIN16
  12. #include <windows.h>
  13. #include <limits.h>
  14. #define Assert(x) // Just define a dummy Assert, so we don't get
  15. // compilation errors from exrwlck.h
  16. #include "badstrfunctions.h"
  17. #include "exrwlck.h"
  18. #ifdef DEBUG
  19. #ifndef _VALIDATE
  20. #define _VALIDATE( f ) if( (f) ) ; else DebugBreak()
  21. #endif
  22. #else
  23. #ifndef _VALIDATE
  24. #define _VALIDATE( f )
  25. #endif
  26. #endif
  27. long const BlockValue = (-LONG_MAX) / 2;
  28. // Large in magnitude, negative value. Used to
  29. // indicate a waiting writer in cReadLock
  30. CExShareLock::CExShareLock( ) : cReadLock( 0 ), cOutRdrs( 0 ) {
  31. InitializeCriticalSection( &critWriters ) ;
  32. hWaitingWriters = CreateSemaphore( NULL, 0, 1, NULL ) ;
  33. hWaitingReaders = CreateSemaphore( NULL, 0, LONG_MAX, NULL ) ;
  34. }
  35. CExShareLock::~CExShareLock( ) {
  36. CloseHandle( hWaitingWriters ) ;
  37. CloseHandle( hWaitingReaders ) ;
  38. DeleteCriticalSection( &critWriters ) ;
  39. }
  40. void
  41. CExShareLock::ShareLock( ) {
  42. long sign = InterlockedIncrement( &cReadLock ) ;
  43. if( sign > 0 ) {
  44. return ;
  45. } else {
  46. // There must be a writer in the lock. Wait for him to leave.
  47. // The InterlockedIncrement recorded our presence so that the writer
  48. // can later release the correct number of threads.
  49. WaitForSingleObject( hWaitingReaders, INFINITE ) ;
  50. }
  51. }
  52. void
  53. CExShareLock::ShareUnlock( ) {
  54. //
  55. // Leave the lock. The return value will be negative if there is a writer
  56. // waiting.
  57. BOOL fWriterWaiting = InterlockedDecrement( &cReadLock ) < 0 ;
  58. if( fWriterWaiting ) {
  59. //
  60. // The following increment occurs when there is writer waiting, but
  61. // readers own the lock. So although cReadLock is temporarily inaccurate
  62. // about the number of readers waiting for the lock, it is not inaccurate
  63. // when it matters in WriteUnlock (which assumes a writer owns the lock.)
  64. //
  65. long junk = InterlockedIncrement( &cReadLock ) ; // restore the value in cReadLock, so that we
  66. // end up with an accurate count of readers waiting
  67. // for entry.
  68. long sign = InterlockedDecrement( &cOutRdrs ) ; // Make sure we don't lose track of the
  69. // number for readers who have left the lock.
  70. //
  71. // Are we the last reader out of the lock ?
  72. //
  73. if( sign == 0 ) {
  74. //
  75. // Definately the last reader out !
  76. //
  77. ReleaseSemaphore( hWaitingWriters, 1, &junk ) ;
  78. }
  79. }
  80. }
  81. void
  82. CExShareLock::ExclusiveLock( ) {
  83. // Only one writer allowed to try for the lock at a time.
  84. //
  85. EnterCriticalSection( &critWriters ) ;
  86. //
  87. // Need to track the number of readers who leave the lock while we
  88. // are trying to grab it.
  89. //
  90. cOutRdrs = 0 ;
  91. // Grab the lock
  92. long oldsign = InterlockedExchange( &cReadLock, BlockValue ) ;
  93. // How many readers left while we grabbed the lock ??
  94. long oldval = InterlockedExchange( &cOutRdrs, oldsign ) ;
  95. //
  96. // Accurately track all the readers who left the lock.
  97. //
  98. long cursign = 1 ; // Initialize to 1 so that if while loop not executed
  99. // following if statement works correctly.
  100. while( oldval++ )
  101. cursign = InterlockedDecrement( &cOutRdrs ) ;
  102. //
  103. // Do we own the lock ? Only if there were no readers, or they have all left already.
  104. //
  105. if( oldsign == 0 || cursign == 0 ) {
  106. // We have the lock
  107. } else {
  108. // Wait for a reader to signal us.
  109. WaitForSingleObject( hWaitingWriters, INFINITE ) ;
  110. }
  111. }
  112. void
  113. CExShareLock::ExclusiveUnlock( ) {
  114. // Estimate how many readers are waiting for the lock
  115. long cWaiting = cReadLock - BlockValue ;
  116. // This Exchange allows any readers who have just arrived to grab the lock.
  117. // Also, it accounts for cWaiting of the blocked readers.
  118. long cNewWaiting = InterlockedExchange( &cReadLock, cWaiting ) - BlockValue ;
  119. // cNewWaiting is the EXACT number of blocked readers - we will increment cReadLock
  120. // until we have accounted for the difference between our estimate and the correct
  121. // number !
  122. long cTotal = cNewWaiting ; // Save cNewWaiting for later use
  123. while( cNewWaiting-- > cWaiting )
  124. InterlockedIncrement( &cReadLock ) ;
  125. if( cTotal > 0 ) {
  126. long junk = 0 ;
  127. ReleaseSemaphore( hWaitingReaders, cTotal, &junk ) ; // let all those readers go!
  128. }
  129. // Let the next writer take his shot at the lock!
  130. LeaveCriticalSection( &critWriters ) ;
  131. }
  132. BOOL
  133. CExShareLock::SharedToExclusive( ) {
  134. // tbd - implement this!
  135. return( FALSE ) ;
  136. }
  137. #endif