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.

311 lines
6.9 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996
  5. //
  6. // File: readwrit.hxx
  7. //
  8. // Contents: Single writer / multiple reader locking class
  9. //
  10. // Classes: CReadWriteAccess, CReadAccess, CWriteAccess
  11. //
  12. // History: 15-Feb-96 dlee Created
  13. // 2-Dec-96 dlee Re-wrote using Kyle's algorithm
  14. //
  15. //----------------------------------------------------------------------------
  16. #pragma once
  17. //+-------------------------------------------------------------------------
  18. //
  19. // Class: CReadWriteLockRecord
  20. //
  21. // Purpose: Atomically maintains a count of readers and writers.
  22. //
  23. // Notes: Reads are atomic -- there is no need for Interlocked access
  24. //
  25. // History: 23-Feb-96 dlee Created
  26. // 02-Dec-96 dlee Renamed and moved from proplock.hxx
  27. //
  28. //----------------------------------------------------------------------------
  29. class CReadWriteLockRecord
  30. {
  31. public:
  32. void Init() { _cReaders = 0; _cWriters = 0; }
  33. #if CIDBG == 1
  34. BOOL LokIsBeingWrittenTwice() { return _cWriters > 1; }
  35. #endif
  36. BOOL isBeingRead() { return 0 != _cReaders; }
  37. BOOL isBeingWritten() { return 0 != _cWriters; }
  38. void AddReader() { InterlockedIncrement( &_cReaders ); }
  39. void RemoveReader() { InterlockedDecrement( &_cReaders ); }
  40. void AddWriter() { InterlockedIncrement( &_cWriters ); }
  41. void RemoveWriter() { InterlockedDecrement( &_cWriters ); }
  42. private:
  43. LONG _cWriters; // 0 or 1
  44. LONG _cReaders; // # of active readers
  45. };
  46. //+-------------------------------------------------------------------------
  47. //
  48. // Class: CReadWriteAccess
  49. //
  50. // Purpose: Implements single writer / multiple reader
  51. //
  52. // History: 15-Feb-96 dlee Created
  53. //
  54. //----------------------------------------------------------------------------
  55. class CReadWriteAccess
  56. {
  57. public:
  58. CReadWriteAccess()
  59. {
  60. _rec.Init();
  61. }
  62. ~CReadWriteAccess()
  63. {
  64. }
  65. void GetReadAccess()
  66. {
  67. do
  68. {
  69. if ( _rec.isBeingWritten() )
  70. SyncRead();
  71. _rec.AddReader();
  72. if ( !_rec.isBeingWritten() )
  73. break;
  74. else
  75. SyncReadDecrement();
  76. } while ( TRUE );
  77. }
  78. void ReleaseReadAccess()
  79. {
  80. if ( _rec.isBeingWritten() )
  81. {
  82. CLock lock( _mtxWrite );
  83. _rec.RemoveReader();
  84. if ( !_rec.isBeingRead() )
  85. {
  86. LokInitWriteEvent();
  87. _evtWrite->Set();
  88. }
  89. }
  90. else
  91. {
  92. _rec.RemoveReader();
  93. if ( _rec.isBeingWritten() )
  94. {
  95. CLock lock( _mtxWrite );
  96. if ( !_rec.isBeingRead() )
  97. {
  98. LokInitWriteEvent();
  99. _evtWrite->Set();
  100. }
  101. }
  102. }
  103. }
  104. void GetWriteAccess()
  105. {
  106. _mtxWriterBusy.Request();
  107. _rec.AddWriter();
  108. BOOL fWait = FALSE;
  109. {
  110. CLock lock( _mtxWrite );
  111. Win4Assert( !_rec.LokIsBeingWrittenTwice() );
  112. if ( _rec.isBeingRead() )
  113. {
  114. LokInitWriteEvent();
  115. _evtWrite->Reset();
  116. fWait = TRUE;
  117. }
  118. }
  119. if ( fWait )
  120. _evtWrite->Wait();
  121. }
  122. void ReleaseWriteAccess()
  123. {
  124. {
  125. CLock lock( _mtxWrite );
  126. _rec.RemoveWriter();
  127. LokInitReadEvent();
  128. _evtRead->Set();
  129. }
  130. _mtxWriterBusy.Release();
  131. }
  132. CMutexSem & WriteMutex() { return _mtxWrite; }
  133. private:
  134. void SyncRead()
  135. {
  136. do
  137. {
  138. BOOL fNeedToWait = FALSE;
  139. {
  140. CLock lock( _mtxWrite );
  141. if ( _rec.isBeingWritten() )
  142. {
  143. LokInitReadEvent();
  144. _evtRead->Reset();
  145. fNeedToWait = TRUE;
  146. }
  147. }
  148. if ( fNeedToWait )
  149. _evtRead->Wait();
  150. } while ( _rec.isBeingWritten() );
  151. }
  152. void SyncReadDecrement()
  153. {
  154. BOOL fDecrementRead = TRUE;
  155. do
  156. {
  157. BOOL fNeedToWait = FALSE;
  158. {
  159. CLock lock( _mtxWrite );
  160. if ( _rec.isBeingWritten() )
  161. {
  162. if ( fDecrementRead )
  163. {
  164. _rec.RemoveReader();
  165. if ( !_rec.isBeingRead() )
  166. {
  167. LokInitWriteEvent();
  168. _evtWrite->Set();
  169. }
  170. }
  171. LokInitReadEvent();
  172. _evtRead->Reset();
  173. fNeedToWait = TRUE;
  174. }
  175. else
  176. {
  177. if ( fDecrementRead )
  178. _rec.RemoveReader();
  179. }
  180. fDecrementRead = FALSE;
  181. }
  182. if ( fNeedToWait )
  183. _evtRead->Wait();
  184. } while ( _rec.isBeingWritten() );
  185. Win4Assert( !fDecrementRead );
  186. }
  187. void LokInitReadEvent()
  188. {
  189. if ( _evtRead.IsNull() )
  190. _evtRead.Set( new CEventSem() );
  191. }
  192. void LokInitWriteEvent()
  193. {
  194. if ( _evtWrite.IsNull() )
  195. _evtWrite.Set( new CEventSem() );
  196. }
  197. CReadWriteLockRecord _rec;
  198. CMutexSem _mtxWriterBusy;
  199. CMutexSem _mtxWrite;
  200. XPtr<CEventSem> _evtRead;
  201. XPtr<CEventSem> _evtWrite;
  202. };
  203. //+-------------------------------------------------------------------------
  204. //
  205. // Class: CReadAccess
  206. //
  207. // Purpose: Grabs a read lock in the constructor, and releases it in
  208. // the destructor
  209. //
  210. // History: 15-Feb-96 dlee Created
  211. //
  212. //----------------------------------------------------------------------------
  213. class CReadAccess
  214. {
  215. public:
  216. CReadAccess( CReadWriteAccess & rwAccess ) :
  217. _rwAccess( rwAccess )
  218. {
  219. _rwAccess.GetReadAccess();
  220. }
  221. ~CReadAccess()
  222. {
  223. _rwAccess.ReleaseReadAccess();
  224. }
  225. private:
  226. CReadWriteAccess & _rwAccess;
  227. };
  228. //+-------------------------------------------------------------------------
  229. //
  230. // Class: CWriteAccess
  231. //
  232. // Purpose: Grabs a write lock in the constructor, and releases it in
  233. // the destructor
  234. //
  235. // History: 15-Feb-96 dlee Created
  236. //
  237. //----------------------------------------------------------------------------
  238. class CWriteAccess
  239. {
  240. public:
  241. CWriteAccess( CReadWriteAccess & rwAccess ) :
  242. _rwAccess( rwAccess )
  243. {
  244. _rwAccess.GetWriteAccess();
  245. }
  246. ~CWriteAccess()
  247. {
  248. _rwAccess.ReleaseWriteAccess();
  249. }
  250. private:
  251. CReadWriteAccess & _rwAccess;
  252. };