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.

153 lines
3.8 KiB

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