Source code of Windows XP (NT5)
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.

220 lines
3.5 KiB

  1. // ReadWriteLock.cpp: implementation of the CReadWriteLock class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "dncmni.h"
  5. //////////////////////////////////////////////////////////////////////
  6. // Construction/Destruction
  7. //////////////////////////////////////////////////////////////////////
  8. #undef DPF_MODNAME
  9. #define DPF_MODNAME "CReadWriteLock::CReadWriteLock"
  10. CReadWriteLock::CReadWriteLock() :
  11. m_hReadSem(0),
  12. m_hWriteSem(0),
  13. m_nReaderWaitingCount(0),
  14. m_nWriterWaitingCount(0),
  15. m_nActiveCount(0),
  16. m_fCritSecInited(FALSE)
  17. #ifdef DEBUG
  18. ,m_dwWriteThread(0)
  19. #endif
  20. {
  21. DPF_ENTER();
  22. DPF_EXIT();
  23. }
  24. #undef DPF_MODNAME
  25. #define DPF_MODNAME "CReadWriteLock::~CReadWriteLock"
  26. CReadWriteLock::~CReadWriteLock()
  27. {
  28. DPF_ENTER();
  29. DNASSERT(m_nActiveCount == 0);
  30. if (m_fCritSecInited)
  31. {
  32. DNDeleteCriticalSection(&m_csWrite);
  33. }
  34. if (m_hReadSem)
  35. {
  36. CloseHandle(m_hReadSem);
  37. }
  38. if (m_hWriteSem)
  39. {
  40. CloseHandle(m_hWriteSem);
  41. }
  42. DPF_EXIT();
  43. }
  44. #undef DPF_MODNAME
  45. #define DPF_MODNAME "CReadWriteLock::Init"
  46. BOOL CReadWriteLock::Init()
  47. {
  48. DPF_ENTER();
  49. // Core will attempt to initialize us multiple times, just take the first
  50. if (!m_fCritSecInited)
  51. {
  52. m_hReadSem = CreateSemaphore(0,0,MAXLONG,0);
  53. if (!m_hReadSem)
  54. {
  55. goto error;
  56. }
  57. m_hWriteSem = CreateSemaphore(0,0,MAXLONG,0);
  58. if (!m_hWriteSem)
  59. {
  60. goto error;
  61. }
  62. if (!DNInitializeCriticalSection(&m_csWrite))
  63. {
  64. goto error;
  65. }
  66. m_fCritSecInited = TRUE;
  67. }
  68. DPF_EXIT();
  69. return TRUE;
  70. error:
  71. if (m_hReadSem)
  72. {
  73. CloseHandle(m_hReadSem);
  74. m_hReadSem = 0;
  75. }
  76. if (m_hWriteSem)
  77. {
  78. CloseHandle(m_hWriteSem);
  79. m_hWriteSem = 0;
  80. }
  81. DPF_EXIT();
  82. return FALSE;
  83. }
  84. #undef DPF_MODNAME
  85. #define DPF_MODNAME "CReadWriteLock::EnterReadLock"
  86. void CReadWriteLock::EnterReadLock()
  87. {
  88. DPF_ENTER();
  89. DNASSERT(m_fCritSecInited);
  90. DNEnterCriticalSection(&m_csWrite);
  91. // If there is a Writer writing or waiting to write, they have priority
  92. BOOL fWaitOnWriters = (m_nWriterWaitingCount || (m_nActiveCount < 0));
  93. if (fWaitOnWriters)
  94. {
  95. m_nReaderWaitingCount++;
  96. }
  97. else
  98. {
  99. m_nActiveCount++;
  100. }
  101. DNLeaveCriticalSection(&m_csWrite);
  102. if (fWaitOnWriters)
  103. {
  104. WaitForSingleObject(m_hReadSem, INFINITE);
  105. }
  106. DPF_EXIT();
  107. }
  108. #undef DPF_MODNAME
  109. #define DPF_MODNAME "CReadWriteLock::LeaveLock"
  110. void CReadWriteLock::LeaveLock()
  111. {
  112. DPF_ENTER();
  113. DNASSERT(m_fCritSecInited);
  114. DNEnterCriticalSection(&m_csWrite);
  115. if (m_nActiveCount > 0)
  116. {
  117. m_nActiveCount--;
  118. }
  119. else
  120. {
  121. DEBUG_ONLY(m_dwWriteThread = 0);
  122. m_nActiveCount++;
  123. }
  124. HANDLE hSem = 0;
  125. LONG lCount = 1;
  126. if (m_nActiveCount == 0)
  127. {
  128. if (m_nWriterWaitingCount > 0)
  129. {
  130. m_nActiveCount = -1;
  131. m_nWriterWaitingCount--;
  132. hSem = m_hWriteSem;
  133. }
  134. else if (m_nReaderWaitingCount > 0)
  135. {
  136. m_nActiveCount = m_nReaderWaitingCount;
  137. m_nReaderWaitingCount = 0;
  138. hSem = m_hReadSem;
  139. lCount = m_nActiveCount;
  140. }
  141. }
  142. DNLeaveCriticalSection(&m_csWrite);
  143. if (hSem)
  144. {
  145. ReleaseSemaphore(hSem, lCount, 0);
  146. }
  147. DPF_EXIT();
  148. }
  149. #undef DPF_MODNAME
  150. #define DPF_MODNAME "CReadWriteLock::EnterWriteLock"
  151. void CReadWriteLock::EnterWriteLock()
  152. {
  153. DPF_ENTER();
  154. DNASSERT(m_fCritSecInited);
  155. DNEnterCriticalSection(&m_csWrite);
  156. BOOL fAvailable = (m_nActiveCount == 0);
  157. if (fAvailable)
  158. {
  159. m_nActiveCount = -1;
  160. }
  161. else
  162. {
  163. DNASSERT(m_dwWriteThread != GetCurrentThreadId()); // No re-entrance!
  164. m_nWriterWaitingCount++;
  165. }
  166. DNLeaveCriticalSection(&m_csWrite);
  167. if (!fAvailable)
  168. {
  169. WaitForSingleObject(m_hWriteSem, INFINITE);
  170. }
  171. DEBUG_ONLY(m_dwWriteThread = GetCurrentThreadId());
  172. DPF_EXIT();
  173. }