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.

329 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. #if DBG==1
  90. ,
  91. _dwDeadLockCounter(0)
  92. #endif
  93. {
  94. }
  95. // Initialize
  96. virtual void Initialize() { _wFlags |= RWLOCKFLAG_INITIALIZED; }
  97. BOOL IsInitialized() { return(_wFlags & RWLOCKFLAG_INITIALIZED); }
  98. // Cleanup
  99. virtual void Cleanup();
  100. // Lock functions
  101. HRESULT AcquireReaderLock(
  102. #ifdef RWLOCK_FULL_FUNCTIONALITY
  103. BOOL fReturnErrors = FALSE,
  104. DWORD dwDesiredTimeout = gdwDefaultTimeout
  105. #if LOCK_PERF==1
  106. ,
  107. #endif
  108. #endif
  109. #if LOCK_PERF==1
  110. const char *pszFile = "Unknown File",
  111. DWORD dwLine = 0,
  112. const char *pszLockName = "Unknown RWLock"
  113. #endif
  114. );
  115. HRESULT AcquireWriterLock(
  116. #ifdef RWLOCK_FULL_FUNCTIONALITY
  117. BOOL fReturnErrors = FALSE,
  118. DWORD dwDesiredTimeout = gdwDefaultTimeout
  119. #if LOCK_PERF==1
  120. ,
  121. #endif
  122. #endif
  123. #if LOCK_PERF==1
  124. const char *pszFile = "Unknown File",
  125. DWORD dwLine = 0,
  126. const char *pszLockName = "Unknown RWLock"
  127. #endif
  128. );
  129. HRESULT ReleaseReaderLock();
  130. HRESULT ReleaseWriterLock();
  131. HRESULT UpgradeToWriterLock(LockCookie *pLockCookie,
  132. BOOL *pfInterveningWrites = NULL
  133. #ifdef RWLOCK_FULL_FUNCTIONALITY
  134. ,
  135. BOOL fReturnErrors = FALSE,
  136. DWORD dwDesiredTimeout = gdwDefaultTimeout
  137. #endif
  138. #if LOCK_PERF==1
  139. ,
  140. const char *pszFile = "Unknown File",
  141. DWORD dwLine = 0,
  142. const char *pszLockName = "Unknown RWLock"
  143. #endif
  144. );
  145. HRESULT DowngradeFromWriterLock(LockCookie *pLockCookie
  146. #if LOCK_PERF==1
  147. ,
  148. const char *pszFile = "Unknown File",
  149. DWORD dwLine = 0,
  150. const char *pszLockName = "Unknown RWLock"
  151. #endif
  152. );
  153. HRESULT ReleaseLock(LockCookie *pLockCookie);
  154. HRESULT RestoreLock(LockCookie *pLockCookie,
  155. BOOL *pfInterveningWrites = NULL
  156. #if LOCK_PERF==1
  157. ,
  158. const char *pszFile = "Unknown File",
  159. DWORD dwLine = 0,
  160. const char *pszLockName = "Unknown RWLock"
  161. #endif
  162. );
  163. // Assert functions
  164. #if DBG==1
  165. BOOL AssertWriterLockHeld();
  166. BOOL AssertWriterLockNotHeld();
  167. BOOL AssertReaderLockHeld();
  168. BOOL AssertReaderLockNotHeld();
  169. BOOL AssertReaderOrWriterLockHeld();
  170. void AssertHeld() { AssertWriterLockHeld(); }
  171. void AssertNotHeld() { AssertWriterLockNotHeld();
  172. AssertReaderLockNotHeld(); }
  173. #else
  174. void AssertWriterLockHeld() { }
  175. void AssertWriterLockNotHeld() { }
  176. void AssertReaderLockHeld() { }
  177. void AssertReaderLockNotHeld() { }
  178. void AssertReaderOrWriterLockHeld() { }
  179. void AssertHeld() { }
  180. void AssertNotHeld() { }
  181. #endif
  182. // Helper functions
  183. WriterCookie GetWriterCookie() { return(_dwWriterSeqNum); }
  184. BOOL IntermediateWrites(WriterCookie cookie) { return((cookie+1) != _dwWriterSeqNum); }
  185. BOOL HeldExclusive() { return _dwWriterID == GetCurrentThreadId(); }
  186. #ifdef RWLOCK_FULL_FUNCTIONALITY
  187. void ReturnErrors() { _wFlags |= RWLOCKFLAG_RETURNERRORS; }
  188. void CacheEvents() { _wFlags |= RWLOCKFLAG_CACHEEVENTS; }
  189. #endif
  190. #ifdef RWLOCK_STATISTICS
  191. DWORD GetReaderEntryCount() { return(_dwReaderEntryCount); }
  192. DWORD GetReaderContentionCount() { return(_dwReaderContentionCount); }
  193. DWORD GetWriterEntryCount() { return(_dwWriterEntryCount); }
  194. DWORD GetWriterContentionCount() { return(_dwWriterContentionCount); }
  195. #endif
  196. // Static functions
  197. static void InitDefaults();
  198. static void SetTimeout(DWORD dwTimeout) { gdwDefaultTimeout = dwTimeout; }
  199. static DWORD GetTimeout() { return(gdwDefaultTimeout); }
  200. static void SetSpinCount(DWORD dwSpinCount) { gdwDefaultSpinCount = gdwNumberOfProcessors > 1
  201. ? dwSpinCount
  202. : 0; }
  203. static DWORD GetSpinCount() { return(gdwDefaultSpinCount); }
  204. private:
  205. virtual HRESULT GetTLSLockData(WORD **ppwReaderLevel) = 0;
  206. HANDLE GetReaderEvent();
  207. HANDLE GetWriterEvent();
  208. ULONG ModifyState(ULONG dwModifyState);
  209. #ifdef RWLOCK_FULL_FUNCTIONALITY
  210. void ReleaseEvents();
  211. #endif
  212. static void RWSetEvent(HANDLE event);
  213. static void RWResetEvent(HANDLE event);
  214. static void RWSleep(DWORD dwTime);
  215. HANDLE _hWriterEvent;
  216. HANDLE _hReaderEvent;
  217. DWORD _dwState;
  218. DWORD _dwWriterID;
  219. DWORD _dwWriterSeqNum;
  220. WORD _wFlags;
  221. WORD _wWriterLevel;
  222. #ifdef RWLOCK_STATISTICS
  223. DWORD _dwReaderEntryCount;
  224. DWORD _dwReaderContentionCount;
  225. DWORD _dwWriterEntryCount;
  226. DWORD _dwWriterContentionCount;
  227. #endif
  228. #if DBG==1
  229. DWORD _dwDeadLockCounter;
  230. #endif
  231. };
  232. //+-------------------------------------------------------------------
  233. //
  234. // Class: CStaticRWLock
  235. //
  236. // Synopsis: Instances of this class are statically created. It
  237. // manages creation and allocation of ReaderSlots
  238. //
  239. // History: 21-Aug-98 Gopalk Created
  240. //
  241. //+-------------------------------------------------------------------
  242. class CStaticRWLock : public CRWLock
  243. {
  244. public:
  245. // Constructor
  246. CStaticRWLock() :
  247. _dwLockNum(-1)
  248. {
  249. }
  250. // Initialize
  251. void Initialize();
  252. // Compatibility functions
  253. void Request(
  254. const char *pszFile = "Unknown File",
  255. DWORD dwLine = 0,
  256. const char* pszLockName = "Unknown RWLock"
  257. )
  258. {
  259. AcquireWriterLock(
  260. #if LOCK_PERF==1
  261. #ifdef RWLOCK_FULL_FUNCTIONALITY
  262. FALSE, gdwDefaultTimeout,
  263. #endif
  264. pszFile, dwLine, pszLockName
  265. #endif
  266. );
  267. }
  268. void Release()
  269. {
  270. ReleaseWriterLock();
  271. }
  272. private:
  273. HRESULT GetTLSLockData(WORD **ppwReaderLevel);
  274. DWORD _dwLockNum;
  275. };
  276. //+-------------------------------------------------------------------
  277. //
  278. // Class: CStaticWriteLock
  279. //
  280. // Synopsis: Helper class that simulates acquiring/releasing
  281. // write lock as constructing/destroying an object
  282. // on the stack
  283. //
  284. // History: 21-Aug-98 Gopalk Created
  285. //
  286. //+-------------------------------------------------------------------
  287. class CStaticWriteLock
  288. {
  289. public:
  290. CStaticWriteLock(
  291. CStaticRWLock &rwLock,
  292. const char *pszFile = "Unknown File",
  293. DWORD dwLine = 0,
  294. const char* pszLockName = "Unknown RWLock") :
  295. _rwLock(rwLock)
  296. {
  297. _rwLock.Request(pszFile, dwLine, pszLockName);
  298. }
  299. ~CStaticWriteLock()
  300. {
  301. _rwLock.Release();
  302. }
  303. private:
  304. CStaticRWLock &_rwLock;
  305. };
  306. #endif // _RWLOCK_HXX_