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.

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