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.

331 lines
11 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // File: RWLock.hxx
  4. //
  5. // Contents: Reader writer lock implementation that supports the
  6. // following features
  7. // 1. Cheap enough to be used in large numbers
  8. // such as per object synchronization.
  9. // 2. Supports timeout. This is a valuable feature
  10. // to detect deadlocks
  11. // 3. Supports caching of events. The allows
  12. // the events to be moved from least contentious
  13. // regions to the most contentious regions.
  14. // In other words, the number of events needed by
  15. // Reader-Writer lockls is bounded by the number
  16. // of threads in the process.
  17. // 4. Supports nested locks by readers and writers
  18. // 5. Supports spin counts for avoiding context switches
  19. // on multi processor machines.
  20. // 6. Supports functionality for upgrading to a writer
  21. // lock with a return argument that indicates
  22. // intermediate writes. Downgrading from a writer
  23. // lock restores the state of the lock.
  24. // 7. Supports functionality to Release Lock for calling
  25. // app code. RestoreLock restores the lock state and
  26. // indicates intermediate writes.
  27. // 8. Recovers from most common failures such as creation of
  28. // events. In other words, the lock mainitains consistent
  29. // internal state and remains usable
  30. //
  31. // Classes: CRWLock,
  32. // CStaticRWLock
  33. //
  34. // History: 19-Aug-98 Gopalk Created
  35. //
  36. //--------------------------------------------------------------------
  37. #ifndef _RWLOCK_HXX_
  38. #define _RWLOCK_HXX_
  39. #if LOCK_PERF==1
  40. #define RWLOCK_STATISTICS 1
  41. #endif
  42. extern DWORD gdwDefaultTimeout;
  43. extern DWORD gdwDefaultSpinCount;
  44. extern DWORD gdwNumberOfProcessors;
  45. typedef struct {
  46. DWORD dwFlags;
  47. DWORD dwWriterSeqNum;
  48. WORD *pwReaderLevel;
  49. WORD wReaderLevel;
  50. WORD wWriterLevel;
  51. } LockCookie;
  52. typedef DWORD WriterCookie;
  53. //+-------------------------------------------------------------------
  54. //
  55. // Class: CRWLock
  56. //
  57. // Synopsis: Abstract base class the implements the locking
  58. // functionality. It supports nested read locks and
  59. // guarantees progress when the derived class is capable
  60. // of creating ReaderSlot
  61. //
  62. // History: 21-Aug-98 Gopalk Created
  63. //
  64. //+-------------------------------------------------------------------
  65. #define RWLOCKFLAG_INITIALIZED 1
  66. #ifdef RWLOCK_FULL_FUNCTIONALITY
  67. #define RWLOCKFLAG_CACHEEVENTS 2
  68. #define RWLOCKFLAG_RETURNERRORS 4
  69. #endif
  70. class CRWLock
  71. {
  72. public:
  73. // Constuctor
  74. CRWLock() :
  75. _hWriterEvent(NULL),
  76. _hReaderEvent(NULL),
  77. _dwState(0),
  78. _dwWriterID(0),
  79. _dwWriterSeqNum(1),
  80. _wFlags(0),
  81. _wWriterLevel(0)
  82. #ifdef RWLOCK_STATISTICS
  83. ,
  84. _dwReaderEntryCount(0),
  85. _dwReaderContentionCount(0),
  86. _dwWriterEntryCount(0),
  87. _dwWriterContentionCount(0)
  88. #endif
  89. {
  90. }
  91. // Initialize
  92. virtual void Initialize() { _wFlags |= RWLOCKFLAG_INITIALIZED; }
  93. BOOL IsInitialized() { return(_wFlags & RWLOCKFLAG_INITIALIZED); }
  94. // Cleanup
  95. virtual void Cleanup();
  96. // Lock functions
  97. HRESULT AcquireReaderLock(
  98. #ifdef RWLOCK_FULL_FUNCTIONALITY
  99. BOOL fReturnErrors = FALSE,
  100. DWORD dwDesiredTimeout = gdwDefaultTimeout
  101. #if LOCK_PERF==1
  102. ,
  103. #endif
  104. #endif
  105. #if LOCK_PERF==1
  106. const char *pszFile = "Unknown File",
  107. DWORD dwLine = 0,
  108. const char *pszLockName = "Unknown RWLock"
  109. #endif
  110. );
  111. HRESULT AcquireWriterLock(
  112. #ifdef RWLOCK_FULL_FUNCTIONALITY
  113. BOOL fReturnErrors = FALSE,
  114. DWORD dwDesiredTimeout = gdwDefaultTimeout
  115. #if LOCK_PERF==1
  116. ,
  117. #endif
  118. #endif
  119. #if LOCK_PERF==1
  120. const char *pszFile = "Unknown File",
  121. DWORD dwLine = 0,
  122. const char *pszLockName = "Unknown RWLock"
  123. #endif
  124. );
  125. HRESULT ReleaseReaderLock();
  126. HRESULT ReleaseWriterLock();
  127. HRESULT UpgradeToWriterLock(LockCookie *pLockCookie,
  128. BOOL *pfInterveningWrites = NULL
  129. #ifdef RWLOCK_FULL_FUNCTIONALITY
  130. ,
  131. BOOL fReturnErrors = FALSE,
  132. DWORD dwDesiredTimeout = gdwDefaultTimeout
  133. #endif
  134. #if LOCK_PERF==1
  135. ,
  136. const char *pszFile = "Unknown File",
  137. DWORD dwLine = 0,
  138. const char *pszLockName = "Unknown RWLock"
  139. #endif
  140. );
  141. HRESULT DowngradeFromWriterLock(LockCookie *pLockCookie
  142. #if LOCK_PERF==1
  143. ,
  144. const char *pszFile = "Unknown File",
  145. DWORD dwLine = 0,
  146. const char *pszLockName = "Unknown RWLock"
  147. #endif
  148. );
  149. HRESULT ReleaseLock(LockCookie *pLockCookie);
  150. HRESULT RestoreLock(LockCookie *pLockCookie,
  151. BOOL *pfInterveningWrites = NULL
  152. #if LOCK_PERF==1
  153. ,
  154. const char *pszFile = "Unknown File",
  155. DWORD dwLine = 0,
  156. const char *pszLockName = "Unknown RWLock"
  157. #endif
  158. );
  159. // Assert functions
  160. #if DBG==1
  161. BOOL AssertWriterLockHeld();
  162. BOOL AssertWriterLockNotHeld();
  163. BOOL AssertReaderLockHeld();
  164. BOOL AssertReaderLockNotHeld();
  165. BOOL AssertReaderOrWriterLockHeld();
  166. void AssertHeld() { AssertWriterLockHeld(); }
  167. void AssertNotHeld() { AssertWriterLockNotHeld();
  168. AssertReaderLockNotHeld(); }
  169. #else
  170. void AssertWriterLockHeld() { }
  171. void AssertWriterLockNotHeld() { }
  172. void AssertReaderLockHeld() { }
  173. void AssertReaderLockNotHeld() { }
  174. void AssertReaderOrWriterLockHeld() { }
  175. void AssertHeld() { }
  176. void AssertNotHeld() { }
  177. #endif
  178. // Helper functions
  179. WriterCookie GetWriterCookie() { return(_dwWriterSeqNum); }
  180. BOOL IntermediateWrites(WriterCookie cookie) { return((cookie+1) != _dwWriterSeqNum); }
  181. BOOL HeldExclusive() { return _dwWriterID == GetCurrentThreadId(); }
  182. #ifdef RWLOCK_FULL_FUNCTIONALITY
  183. void ReturnErrors() { _wFlags |= RWLOCKFLAG_RETURNERRORS; }
  184. void CacheEvents() { _wFlags |= RWLOCKFLAG_CACHEEVENTS; }
  185. #endif
  186. #ifdef RWLOCK_STATISTICS
  187. DWORD GetReaderEntryCount() { return(_dwReaderEntryCount); }
  188. DWORD GetReaderContentionCount() { return(_dwReaderContentionCount); }
  189. DWORD GetWriterEntryCount() { return(_dwWriterEntryCount); }
  190. DWORD GetWriterContentionCount() { return(_dwWriterContentionCount); }
  191. #endif
  192. // Static functions
  193. static void InitDefaults();
  194. static void SetTimeout(DWORD dwTimeout) { gdwDefaultTimeout = dwTimeout; }
  195. static DWORD GetTimeout() { return(gdwDefaultTimeout); }
  196. static void SetSpinCount(DWORD dwSpinCount) { gdwDefaultSpinCount = gdwNumberOfProcessors > 1
  197. ? dwSpinCount
  198. : 0; }
  199. static DWORD GetSpinCount() { return(gdwDefaultSpinCount); }
  200. private:
  201. virtual HRESULT GetTLSLockData(WORD **ppwReaderLevel) = 0;
  202. HANDLE GetReaderEvent();
  203. HANDLE GetWriterEvent();
  204. ULONG ModifyState(ULONG dwModifyState);
  205. #ifdef RWLOCK_FULL_FUNCTIONALITY
  206. void ReleaseEvents();
  207. #endif
  208. static void RWSetEvent(HANDLE event);
  209. static void RWResetEvent(HANDLE event);
  210. static void RWSleep(DWORD dwTime);
  211. HANDLE _hWriterEvent;
  212. HANDLE _hReaderEvent;
  213. DWORD _dwState;
  214. DWORD _dwWriterID;
  215. DWORD _dwWriterSeqNum;
  216. WORD _wFlags;
  217. WORD _wWriterLevel;
  218. #ifdef RWLOCK_STATISTICS
  219. DWORD _dwReaderEntryCount;
  220. DWORD _dwReaderContentionCount;
  221. DWORD _dwWriterEntryCount;
  222. DWORD _dwWriterContentionCount;
  223. #endif
  224. };
  225. //+-------------------------------------------------------------------
  226. //
  227. // Class: CStaticRWLock
  228. //
  229. // Synopsis: Instances of this class are statically created. It
  230. // manages creation and allocation of ReaderSlots
  231. //
  232. // History: 21-Aug-98 Gopalk Created
  233. //
  234. //+-------------------------------------------------------------------
  235. class CStaticRWLock : public CRWLock
  236. {
  237. public:
  238. // Constructor
  239. CStaticRWLock() :
  240. _dwLockNum(-1)
  241. {
  242. }
  243. // Initialize
  244. void Initialize();
  245. // Compatibility functions
  246. void Request(
  247. #if LOCK_PERF==1 || DBG==1
  248. const char *pszFile = "Unknown File",
  249. DWORD dwLine = 0,
  250. const char* pszLockName = "Unknown RWLock"
  251. #endif
  252. )
  253. {
  254. AcquireWriterLock(
  255. #if LOCK_PERF==1
  256. #ifdef RWLOCK_FULL_FUNCTIONALITY
  257. FALSE, gdwDefaultTimeout,
  258. #endif
  259. pszFile, dwLine, pszLockName
  260. #endif
  261. );
  262. }
  263. void Release()
  264. {
  265. ReleaseWriterLock();
  266. }
  267. private:
  268. HRESULT GetTLSLockData(WORD **ppwReaderLevel);
  269. DWORD _dwLockNum;
  270. };
  271. //+-------------------------------------------------------------------
  272. //
  273. // Class: CStaticWriteLock
  274. //
  275. // Synopsis: Helper class that simulates acquiring/releasing
  276. // write lock as constructing/destroying an object
  277. // on the stack
  278. //
  279. // History: 21-Aug-98 Gopalk Created
  280. //
  281. //+-------------------------------------------------------------------
  282. class CStaticWriteLock
  283. {
  284. public:
  285. CStaticWriteLock(CStaticRWLock &rwLock
  286. #if LOCK_PERF==1 || DBG==1
  287. ,
  288. const char *pszFile = "Unknown File",
  289. DWORD dwLine = 0,
  290. const char *pszLockName = "Unknown RWLock"
  291. #endif
  292. ) :
  293. _rwLock(rwLock)
  294. {
  295. _rwLock.Request(
  296. #if LOCK_PERF==1 || DBG==1
  297. pszFile, dwLine, pszLockName
  298. #endif
  299. );
  300. }
  301. ~CStaticWriteLock()
  302. {
  303. _rwLock.Release();
  304. }
  305. private:
  306. CStaticRWLock &_rwLock;
  307. };
  308. #endif // _RWLOCK_HXX_