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.

469 lines
12 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. LOCK.CPP
  5. Abstract:
  6. Implements the generic class for obtaining read and write locks to some
  7. resource.
  8. See lock.h for all documentation.
  9. Classes defined:
  10. CLock
  11. History:
  12. a-levn 5-Sept-96 Created.
  13. 3/10/97 a-levn Fully documented
  14. --*/
  15. #include "precomp.h"
  16. #include <stdio.h>
  17. #include "lock.h"
  18. // debugging.
  19. #define PRINTF
  20. #ifdef DBG
  21. OperationStat gTimeTraceReadLock;
  22. OperationStat gTimeTraceWriteLock;
  23. OperationStat gTimeTraceBackupLock;
  24. CStaticCritSec OperationStat::lock_;
  25. #endif
  26. //******************************************************************************
  27. //
  28. // See lock.h for documentation
  29. //
  30. //******************************************************************************
  31. CLock::CLock() : m_nReading(0), m_nWriting(0), m_nWaitingToRead(0),
  32. m_nWaitingToWrite(0),
  33. m_csEntering(THROW_LOCK,0x80000000 | 500L),
  34. m_csAll(THROW_LOCK,0x80000000 | 500L)
  35. {
  36. m_dwArrayIndex = 0;
  37. for (DWORD i=0;i<MaxRegistredReaders;i++)
  38. {
  39. m_adwReaders[i].ThreadId = 0;
  40. }
  41. // Create unnamed events for reading and writing
  42. // =============================================
  43. m_hCanRead = CreateEvent(NULL, TRUE, TRUE, NULL);
  44. m_hCanWrite = CreateEvent(NULL, TRUE, TRUE, NULL);
  45. if (NULL == m_hCanRead || NULL == m_hCanWrite)
  46. {
  47. CStaticCritSec::SetFailure();
  48. }
  49. }
  50. //******************************************************************************
  51. //
  52. // See lock.h for documentation
  53. //
  54. //******************************************************************************
  55. CLock::~CLock()
  56. {
  57. if (m_hCanWrite) CloseHandle(m_hCanWrite);
  58. if (m_hCanRead) CloseHandle(m_hCanRead);
  59. }
  60. //******************************************************************************
  61. //
  62. // See lock.h for documentation
  63. //
  64. //******************************************************************************
  65. int CLock::ReadLock(DWORD dwTimeout)
  66. {
  67. PRINTF("%d wants to read\n", GetCurrentThreadId());
  68. // Get in line for getting any kind of lock (those unlocking don't go into
  69. // this line)
  70. // =======================================================================
  71. DWORD_PTR dwThreadId = GetCurrentThreadId();
  72. LockGuard<CriticalSection> lgEnter(m_csEntering);
  73. if (!lgEnter.locked())
  74. {
  75. #ifdef DBG
  76. DebugBreak();
  77. #endif
  78. return TimedOut;
  79. }
  80. // We are the only ones allowed to get any kind of lock now. Wait for the
  81. // event indicating that reading is enabled to become signaled
  82. // ======================================================================
  83. PRINTF("%d next to enter\n", GetCurrentThreadId());
  84. if(m_nWriting != 0)
  85. {
  86. int nRes = WaitFor(m_hCanRead, dwTimeout);
  87. if(nRes != NoError)
  88. {
  89. return nRes;
  90. }
  91. }
  92. // Enter inner critical section (unlockers use it too), increment the
  93. // number of readers and disable writing.
  94. // ==================================================================
  95. PRINTF("%d got event\n", GetCurrentThreadId());
  96. LockGuard<CriticalSection> lgAll(m_csAll);
  97. if (!lgAll.locked())
  98. {
  99. if(m_nReading == 0)
  100. {
  101. // this is for the read lock acquired on one thread and release on one other
  102. m_dwArrayIndex = 0;
  103. if(!SetEvent(m_hCanWrite))
  104. {
  105. #ifdef DBG
  106. DebugBreak();
  107. #endif
  108. return Failed;
  109. }
  110. }
  111. #ifdef DBG
  112. DebugBreak();
  113. #endif
  114. return TimedOut;
  115. }
  116. m_nReading++;
  117. //DBG_PRINTFA((pBuff,"+ (%08x) %d\n",GetCurrentThreadId(),m_nReading));
  118. if (m_dwArrayIndex < MaxRegistredReaders)
  119. {
  120. m_adwReaders[m_dwArrayIndex].ThreadId = dwThreadId;
  121. ULONG Hash;
  122. //RtlCaptureStackBackTrace(1,MaxTraceSize,m_adwReaders[m_dwArrayIndex].Trace,&Hash);
  123. m_dwArrayIndex++;
  124. }
  125. PRINTF("Reset write\n");
  126. ResetEvent(m_hCanWrite);
  127. PRINTF("Done\n");
  128. if (m_nWriting)
  129. {
  130. #ifdef DBG
  131. OutputDebugString(L"WinMgmt: Read lock aquired while write lock is aquired!\n");
  132. DebugBreak();
  133. #endif
  134. }
  135. // Get out of all critical sections and return
  136. // ===========================================
  137. PRINTF("%d begins to read\n", GetCurrentThreadId());
  138. return NoError;
  139. }
  140. //******************************************************************************
  141. //
  142. // See lock.h for documentation
  143. //
  144. //******************************************************************************
  145. int CLock::ReadUnlock()
  146. {
  147. PRINTF("%d wants to unlock reading\n", GetCurrentThreadId());
  148. // Enter internal ciritcal section and decrement the number of readers
  149. // ===================================================================
  150. LockGuard<CriticalSection> gl(m_csAll);
  151. while (!gl.locked())
  152. {
  153. Sleep(20);
  154. gl.acquire();
  155. };
  156. m_nReading--;
  157. //DBG_PRINTFA((pBuff,"- (%08x) %d\n",GetCurrentThreadId(),m_nReading));
  158. if(m_nReading < 0)
  159. {
  160. #ifdef DBG
  161. OutputDebugString(L"WinMgmt: Repository detected more read unlocks than locks\n");
  162. DebugBreak();
  163. #endif
  164. return Failed;
  165. }
  166. DWORD_PTR dwThreadId = GetCurrentThreadId();
  167. for(int i = 0; i < MaxRegistredReaders; i++)
  168. {
  169. if(m_adwReaders[i].ThreadId == dwThreadId)
  170. {
  171. m_adwReaders[i].ThreadId = 0;
  172. break;
  173. }
  174. }
  175. // If all readers are gone, allow writers in
  176. // =========================================
  177. if(m_nReading == 0)
  178. {
  179. // this is for the read lock acquired on one thread and release on one other
  180. m_dwArrayIndex = 0;
  181. PRINTF("%d is the last reader\n", GetCurrentThreadId());
  182. PRINTF("Set write\n");
  183. if(!SetEvent(m_hCanWrite))
  184. {
  185. #ifdef DBG
  186. DebugBreak();
  187. #endif
  188. return Failed;
  189. }
  190. PRINTF("Done\n");
  191. }
  192. else PRINTF("%d sees %d still reading\n", GetCurrentThreadId(), m_nReading);
  193. // Get out and return
  194. // ==================
  195. return NoError;
  196. }
  197. //******************************************************************************
  198. //
  199. // See lock.h for documentation
  200. //
  201. //******************************************************************************
  202. int CLock::WriteLock(DWORD dwTimeout)
  203. {
  204. PRINTF("%d wants to write\n", GetCurrentThreadId());
  205. // Get in line for getting any kind of lock. Those unlocking don't use this
  206. // critical section.
  207. // ========================================================================
  208. LockGuard<CriticalSection> lgEnter(m_csEntering);
  209. if (!lgEnter.locked())
  210. {
  211. #ifdef DBG
  212. DebugBreak();
  213. #endif
  214. return TimedOut;
  215. }
  216. // We are the only ones allowed to get any kind of lock now
  217. // ========================================================
  218. PRINTF("%d next to enter\n", GetCurrentThreadId());
  219. // Wait for the event allowing writing to become signaled
  220. // ======================================================
  221. int nRes = WaitFor(m_hCanWrite, dwTimeout);
  222. PRINTF("%d got event\n", GetCurrentThreadId());
  223. if(nRes != NoError)
  224. {
  225. #ifdef DBG
  226. DebugBreak();
  227. #endif
  228. return nRes;
  229. }
  230. // Enter internal critical section (unlockers use it too), increment the
  231. // number of writers (from 0 to 1) and disable both reading and writing
  232. // from now on.
  233. // ======================================================================
  234. LockGuard<CriticalSection> lgAll(m_csAll);
  235. if (!lgAll.locked())
  236. {
  237. if(!SetEvent(m_hCanWrite))
  238. {
  239. #ifdef DBG
  240. DebugBreak();
  241. #endif
  242. };
  243. #ifdef DBG
  244. DebugBreak();
  245. #endif
  246. return TimedOut;
  247. }
  248. m_WriterId = GetCurrentThreadId();
  249. m_nWriting++;
  250. //DBG_PRINTFA((pBuff,"+ (%08x) %d W %d\n",GetCurrentThreadId(),m_nReading,m_nWriting));
  251. PRINTF("Reset both\n");
  252. ResetEvent(m_hCanWrite);
  253. ResetEvent(m_hCanRead);
  254. PRINTF("Done\n");
  255. if (m_nReading)
  256. {
  257. #ifdef DBG
  258. OutputDebugString(L"WinMgmt: Write lock aquired while read lock is aquired!\n");
  259. DebugBreak();
  260. #endif
  261. }
  262. // Get out and return
  263. // ==================
  264. PRINTF("%d begins to write\n", GetCurrentThreadId());
  265. return NoError;
  266. }
  267. //******************************************************************************
  268. //
  269. // See lock.h for documentation
  270. //
  271. //******************************************************************************
  272. int CLock::WriteUnlock()
  273. {
  274. PRINTF("%d wants to release writing\n", GetCurrentThreadId());
  275. // Enter lock determination critical section
  276. // =========================================
  277. LockGuard<CriticalSection> gl(m_csAll);
  278. while (!gl.locked())
  279. {
  280. Sleep(20);
  281. gl.acquire();
  282. };
  283. m_nWriting--;
  284. //DBG_PRINTFA((pBuff,"- (%08x) %d W %d\n",GetCurrentThreadId(),m_nReading,m_nWriting));
  285. m_WriterId = 0;
  286. if(m_nWriting < 0)
  287. {
  288. #ifdef DBG
  289. OutputDebugString(L"WinMgmt: Repository detected too many write unlocks\n");
  290. DebugBreak();
  291. #endif
  292. return Failed;
  293. }
  294. // Allow readers and writers in
  295. // ============================
  296. PRINTF("%d released writing\n", GetCurrentThreadId());
  297. PRINTF("Set both\n");
  298. if(!SetEvent(m_hCanRead))
  299. {
  300. #ifdef DBG
  301. DebugBreak();
  302. #endif
  303. return Failed;
  304. }
  305. else if(!SetEvent(m_hCanWrite))
  306. {
  307. #ifdef DBG
  308. DebugBreak();
  309. #endif
  310. return Failed;
  311. }
  312. else
  313. {
  314. PRINTF("Done\n");
  315. return NoError;
  316. }
  317. }
  318. //******************************************************************************
  319. //
  320. // See lock.h for documentation
  321. //
  322. //******************************************************************************
  323. int CLock::WaitFor(HANDLE hEvent, DWORD dwTimeout)
  324. {
  325. DWORD dwRes;
  326. dwRes = WaitForSingleObject(hEvent, dwTimeout);
  327. // Analyze the error code and convert to ours
  328. // ==========================================
  329. if(dwRes == WAIT_OBJECT_0) return NoError;
  330. else if(dwRes == WAIT_TIMEOUT) return TimedOut;
  331. else return Failed;
  332. }
  333. //******************************************************************************
  334. //
  335. // See lock.h for documentation
  336. //
  337. //******************************************************************************
  338. int CLock::DowngradeLock()
  339. {
  340. // Enter lock determination critical section
  341. // =========================================
  342. LockGuard<CriticalSection> gl(m_csAll);
  343. while (!gl.locked())
  344. {
  345. Sleep(20);
  346. gl.acquire();
  347. };
  348. m_nWriting--;
  349. m_WriterId = 0;
  350. if(!SetEvent(m_hCanRead))
  351. {
  352. DebugBreak();
  353. return Failed;
  354. }
  355. m_nReading++;
  356. if (1 != m_nReading)
  357. {
  358. #ifdef DBG
  359. DebugBreak();
  360. #endif
  361. }
  362. //DBG_PRINTFA((pBuff,"+ (%08x) %d\n",GetCurrentThreadId(),m_nReading));
  363. DWORD_PTR dwThreadId = GetCurrentThreadId();
  364. if (m_dwArrayIndex < MaxRegistredReaders)
  365. {
  366. m_adwReaders[m_dwArrayIndex].ThreadId = dwThreadId;
  367. ULONG Hash;
  368. //RtlCaptureStackBackTrace(1,MaxTraceSize,m_adwReaders[m_dwArrayIndex].Trace,&Hash);
  369. m_dwArrayIndex++;
  370. }
  371. return NoError;
  372. }