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.

137 lines
3.5 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // RWLock.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file implements the class RWLock.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 09/04/1997 Original version.
  16. // 09/30/1998 Fix bug with recursive LockExclusive calls.
  17. //
  18. ///////////////////////////////////////////////////////////////////////////////
  19. #include <proxypch.h>
  20. #include <climits>
  21. #include <iaswin32.h>
  22. //////////
  23. // Large negative value used to block shared entry into the perimeter.
  24. //////////
  25. const LONG BLOCK_VALUE = (-LONG_MAX)/2;
  26. RWLock::RWLock()
  27. : sharing(0),
  28. waiting(0),
  29. count(&sharing),
  30. sharedOK(NULL),
  31. exclusiveOK(NULL)
  32. {
  33. bool success = false;
  34. do
  35. {
  36. sharedOK = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
  37. if (!sharedOK) { break; }
  38. exclusiveOK = CreateSemaphore(NULL, 0, 1, NULL);
  39. if (!exclusiveOK) { break; }
  40. if (!InitializeCriticalSectionAndSpinCount(&exclusive, 0x80001000))
  41. { break; }
  42. success = true;
  43. } while (FALSE);
  44. if (!success)
  45. {
  46. if (exclusiveOK) { CloseHandle(exclusiveOK); }
  47. if (sharedOK) { CloseHandle(sharedOK); }
  48. throw std::bad_alloc();
  49. }
  50. }
  51. RWLock::~RWLock() throw ()
  52. {
  53. CloseHandle(exclusiveOK);
  54. CloseHandle(sharedOK);
  55. DeleteCriticalSection(&exclusive);
  56. }
  57. void RWLock::Lock() const throw ()
  58. {
  59. // If this is less than zero, then an exlusive thread must have inserted
  60. // the BLOCK_VALUE, so ...
  61. if (InterlockedIncrement(count) <= 0)
  62. {
  63. // ... we have to wait until he's done.
  64. WaitForSingleObject(sharedOK, INFINITE);
  65. }
  66. }
  67. void RWLock::LockExclusive() throw ()
  68. {
  69. // This limits exclusive access to a single thread.
  70. EnterCriticalSection(&exclusive);
  71. // The first time through we have to wait for the sharers to finish.
  72. if (exclusive.RecursionCount == 1)
  73. {
  74. // Block any new shared threads.
  75. waiting = BLOCK_VALUE;
  76. InterlockedExchangePointer((PVOID *)&count, &waiting);
  77. // Find out how many shared threads are already in the perimeter ...
  78. LONG sharingNow = InterlockedExchangeAdd(&sharing, BLOCK_VALUE);
  79. if (sharingNow > 0)
  80. {
  81. // ... and wait until they're done.
  82. WaitForSingleObject(exclusiveOK, INFINITE);
  83. }
  84. // At this point there is no one left inside the perimeter.
  85. sharing = 0;
  86. }
  87. }
  88. void RWLock::Unlock() const throw ()
  89. {
  90. // If sharing is zero, we must be an exclusive thread.
  91. if (!sharing)
  92. {
  93. // Are we about to release our last lock ?
  94. if (exclusive.RecursionCount == 1)
  95. {
  96. // Allow any new shared access attempts.
  97. InterlockedExchangePointer((PVOID *)&count, &sharing);
  98. // Find out how many threads are waiting on the semaphore ...
  99. LONG waitingNow = waiting - BLOCK_VALUE;
  100. if (waitingNow > 0)
  101. {
  102. // ... and let them go.
  103. InterlockedExchangeAdd(count, waitingNow);
  104. ReleaseSemaphore(sharedOK, waitingNow, NULL);
  105. }
  106. }
  107. // Release the exclusive lock.
  108. LeaveCriticalSection(&exclusive);
  109. }
  110. else if (InterlockedDecrement(&sharing) == BLOCK_VALUE)
  111. {
  112. // If we end up here, we must have been the last shared thread out of
  113. // the perimeter while an exlusive thread is waiting, so wake him up.
  114. ReleaseSemaphore(exclusiveOK, 1, NULL) ;
  115. }
  116. }