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.

427 lines
11 KiB

  1. /*++
  2. Copyright (c) 2000, Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. The file contains the READ_WRITE_LOCK definition which allows
  6. multiple-reader/single-writer. This implementation DOES NOT
  7. starve a thread trying to acquire write accesss if there are
  8. a large number of threads interested in acquiring read access.
  9. Revision History:
  10. mohitt, sachins, Apr 23 2000, Created
  11. --*/
  12. #include "pcheapol.h"
  13. #pragma hdrstop
  14. //----------------------------------------------------------------------------
  15. // Function: CreateReadWriteLock
  16. //
  17. // Initializes a multiple-reader/single-writer lock object
  18. //----------------------------------------------------------------------------
  19. DWORD
  20. CreateReadWriteLock(
  21. PREAD_WRITE_LOCK pRWL,
  22. PCHAR szName
  23. )
  24. {
  25. sprintf(pRWL->RWL_Name, "%.3s", szName);
  26. pRWL->RWL_ReaderCount = 0;
  27. __try {
  28. InitializeCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
  29. }
  30. __except(EXCEPTION_EXECUTE_HANDLER) {
  31. return GetLastError();
  32. }
  33. pRWL->RWL_ReaderDoneEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  34. if (pRWL->RWL_ReaderDoneEvent == NULL) {
  35. return GetLastError();
  36. }
  37. return NO_ERROR;
  38. }
  39. //----------------------------------------------------------------------------
  40. // Function: DeleteReadWriteLock
  41. //
  42. // Frees resources used by a multiple-reader/single-writer lock object
  43. //----------------------------------------------------------------------------
  44. VOID
  45. DeleteReadWriteLock(
  46. PREAD_WRITE_LOCK pRWL
  47. )
  48. {
  49. CloseHandle(pRWL->RWL_ReaderDoneEvent);
  50. pRWL->RWL_ReaderDoneEvent = NULL;
  51. DeleteCriticalSection(&pRWL->RWL_ReadWriteBlock);
  52. pRWL->RWL_ReaderCount = 0;
  53. }
  54. //----------------------------------------------------------------------------
  55. // Function: AcquireReadLock
  56. //
  57. // Secures shared ownership of the lock object for the caller.
  58. //
  59. // readers enter the read-write critical section, increment the count,
  60. // and leave the critical section
  61. //----------------------------------------------------------------------------
  62. VOID
  63. AcquireReadLock(
  64. PREAD_WRITE_LOCK pRWL
  65. )
  66. {
  67. EnterCriticalSection(&pRWL->RWL_ReadWriteBlock);
  68. InterlockedIncrement(&pRWL->RWL_ReaderCount);
  69. LeaveCriticalSection(&pRWL->RWL_ReadWriteBlock);
  70. }
  71. //----------------------------------------------------------------------------
  72. // Function: ReleaseReadLock
  73. //
  74. // Relinquishes shared ownership of the lock object.
  75. //
  76. // the last reader sets the event to wake any waiting writers
  77. //----------------------------------------------------------------------------
  78. VOID
  79. ReleaseReadLock(
  80. PREAD_WRITE_LOCK pRWL
  81. )
  82. {
  83. if (InterlockedDecrement(&pRWL->RWL_ReaderCount) < 0) {
  84. SetEvent(pRWL->RWL_ReaderDoneEvent);
  85. }
  86. }
  87. //----------------------------------------------------------------------------
  88. // Function: AcquireWriteLock
  89. //
  90. // Secures exclusive ownership of the lock object.
  91. //
  92. // the writer blocks other threads by entering the ReadWriteBlock section,
  93. // and then waits for any thread(s) owning the lock to finish
  94. //----------------------------------------------------------------------------
  95. VOID
  96. AcquireWriteLock(
  97. PREAD_WRITE_LOCK pRWL
  98. )
  99. {
  100. EnterCriticalSection(&pRWL->RWL_ReadWriteBlock);
  101. if (InterlockedDecrement(&pRWL->RWL_ReaderCount) >= 0) {
  102. WaitForSingleObject(pRWL->RWL_ReaderDoneEvent, INFINITE);
  103. }
  104. }
  105. //----------------------------------------------------------------------------
  106. // Function: ReleaseWriteLock
  107. //
  108. // Relinquishes exclusive ownership of the lock object.
  109. //
  110. // the writer releases the lock by setting the count to zero
  111. // and then leaving the ReadWriteBlock critical section
  112. //----------------------------------------------------------------------------
  113. VOID
  114. ReleaseWriteLock(
  115. PREAD_WRITE_LOCK pRWL
  116. )
  117. {
  118. InterlockedIncrement(&pRWL->RWL_ReaderCount);
  119. LeaveCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
  120. }
  121. #if 0
  122. //----------------------------------------------------------------------------
  123. // InitializeDynamicLocksStore
  124. //
  125. // Initialize the structure from which dynamic readwrite locks are allocated.
  126. //----------------------------------------------------------------------------
  127. DWORD
  128. InitializeDynamicLocksStore (
  129. PDYNAMIC_LOCKS_STORE pStore,
  130. HANDLE hHeap,
  131. PCHAR szName
  132. )
  133. {
  134. sprintf(pStore->szName, "%.3s", szName);
  135. // initialize the heap from where dynamic locks are allocated
  136. pStore->hHeap = hHeap;
  137. INITIALIZE_LOCKED_LIST(&pStore->llFreeLocksList, szName);
  138. if (!LOCKED_LIST_INITIALIZED(&pStore->llFreeLocksList))
  139. return GetLastError();
  140. // initialize the count of the number of free and allocated locks
  141. pStore->ulCountAllocated = pStore->ulCountFree = 0;
  142. return NO_ERROR;
  143. }
  144. //----------------------------------------------------------------------------
  145. // DeInitializeDynamicLocksStore
  146. //
  147. // Fail if any allocated locks have not been freed.
  148. // Delete the free locks and the FreeLocksList.
  149. //----------------------------------------------------------------------------
  150. DWORD
  151. DeInitializeDynamicLocksStore (
  152. PDYNAMIC_LOCKS_STORE pStore
  153. )
  154. {
  155. PDYNAMIC_READWRITE_LOCK pLock;
  156. PLIST_ENTRY pleHead, ple;
  157. // can't complete if any locks are still allocated!!!
  158. if (pStore->ulCountAllocated)
  159. return ERROR_CAN_NOT_COMPLETE;
  160. // deinitialize the count of the number of free and allocated locks
  161. pStore->ulCountAllocated = pStore->ulCountFree = 0;
  162. // deinitialize the FreeLocksList
  163. pStore->llFreeLocksList.created = 0;
  164. // delete all dynamic readwrite locks and free the memory.
  165. pleHead = &(pStore->llFreeLocksList.head);
  166. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  167. {
  168. pLock = CONTAINING_RECORD(ple, DYNAMIC_READWRITE_LOCK, leLink);
  169. DELETE_READ_WRITE_LOCK(&pLock->rwlLock);
  170. HeapFree(pStore->hHeap, 0, pLock);
  171. }
  172. DeleteCriticalSection(&(pStore->llFreeLocksList.lock));
  173. // deinitialize the heap from where dynamic locks are allocated
  174. pStore->hHeap = NULL;
  175. return NO_ERROR;
  176. }
  177. //----------------------------------------------------------------------------
  178. // GetDynamicReadwriteLock
  179. //
  180. // Return a free dynamic readwrite lock, if one is available.
  181. // Else allocate a new dynamic readwrite lock.
  182. // Assumes pStore->llFreeLocksList is locked.
  183. //----------------------------------------------------------------------------
  184. PDYNAMIC_READWRITE_LOCK
  185. GetDynamicReadwriteLock (
  186. PDYNAMIC_LOCKS_STORE pStore
  187. )
  188. {
  189. PDYNAMIC_READWRITE_LOCK pLock;
  190. PLIST_ENTRY pleHead, ple;
  191. do // breakout loop
  192. {
  193. // a free dynamic lock is available. Return it
  194. pleHead = &(pStore->llFreeLocksList.head);
  195. if (!IsListEmpty(pleHead))
  196. {
  197. pStore->ulCountFree--;
  198. ple = RemoveHeadList(pleHead);
  199. pLock = CONTAINING_RECORD(ple, DYNAMIC_READWRITE_LOCK, leLink);
  200. break;
  201. }
  202. // allocate memory for a new dynamic lock
  203. pLock = HeapAlloc(pStore->hHeap, 0, sizeof(DYNAMIC_READWRITE_LOCK));
  204. if (pLock == NULL)
  205. break;
  206. // initialize the fields
  207. CREATE_READ_WRITE_LOCK(&(pLock->rwlLock), pStore->szName);
  208. if (!READ_WRITE_LOCK_CREATED(&(pLock->rwlLock)))
  209. {
  210. HeapFree(pStore->hHeap, 0, pLock);
  211. pLock = NULL;
  212. break;
  213. }
  214. } while (FALSE);
  215. if (pLock != NULL)
  216. {
  217. pStore->ulCountAllocated++;
  218. pLock->ulCount = 0;
  219. }
  220. return pLock;
  221. }
  222. //----------------------------------------------------------------------------
  223. // FreeDynamicReadwriteLock
  224. //
  225. // Accepts a released dynamic readwrite lock.
  226. // Frees it if there are too many dynamic readwrite locks.
  227. // Assumes pStore->llFreeLocksList is locked.
  228. //----------------------------------------------------------------------------
  229. VOID
  230. FreeDynamicReadwriteLock (
  231. PDYNAMIC_READWRITE_LOCK pLock,
  232. PDYNAMIC_LOCKS_STORE pStore
  233. )
  234. {
  235. PLIST_ENTRY pleHead;
  236. // decrement count of allocated locks
  237. pStore->ulCountAllocated--;
  238. // if there are too many dynamic readwrite locks, then free this lock
  239. if ((pStore->ulCountAllocated + pStore->ulCountFree + 1) >
  240. DYNAMIC_LOCKS_HIGH_THRESHOLD)
  241. {
  242. DELETE_READ_WRITE_LOCK(&pLock->rwlLock);
  243. HeapFree(pStore->hHeap, 0, pLock);
  244. }
  245. else // insert into the list of free locks
  246. {
  247. pleHead = &(pStore->llFreeLocksList.head);
  248. InsertHeadList(pleHead, &pLock->leLink);
  249. pStore->ulCountFree++;
  250. }
  251. return;
  252. }
  253. //----------------------------------------------------------------------------
  254. // AcquireDynamicLock
  255. //
  256. // Locks the FreeLocksList.
  257. // Allocates a new dynamic lock if required.
  258. // Increments the count.
  259. // Unlocks the FreeLocksList.
  260. // Acquires the dynamic lock.
  261. //----------------------------------------------------------------------------
  262. DWORD
  263. AcquireDynamicReadwriteLock (
  264. PDYNAMIC_READWRITE_LOCK *ppLock,
  265. LOCK_MODE lmMode,
  266. PDYNAMIC_LOCKS_STORE pStore
  267. )
  268. {
  269. // acquire the lock for the free locks list
  270. AcquireListLock(&pStore->llFreeLocksList);
  271. // if it does not already exist, allocate a new dynamic lock
  272. if (*ppLock == NULL)
  273. {
  274. *ppLock = GetDynamicReadwriteLock(pStore);
  275. // if could not get a lock we are in serious trouble
  276. if (*ppLock == NULL)
  277. {
  278. ReleaseListLock(&pStore->llFreeLocksList);
  279. return ERROR_CAN_NOT_COMPLETE;
  280. }
  281. }
  282. // increment count in the dynamic lock
  283. (*ppLock)->ulCount++;
  284. // release the lock for the free locks list
  285. ReleaseListLock(&pStore->llFreeLocksList);
  286. // acquire dynamic lock
  287. if (lmMode == READ_MODE)
  288. AcquireReadLock(&(*ppLock)->rwlLock);
  289. else
  290. AcquireWriteLock(&(*ppLock)->rwlLock);
  291. return NO_ERROR;
  292. }
  293. //----------------------------------------------------------------------------
  294. // ReleaseDynamicReadwriteLock
  295. //
  296. // Locks the FreeLocksList.
  297. // Releases the dynamic lock.
  298. // Decrements the count.
  299. // Free the dynamic lock if count becomes 0.
  300. // Unlocks the FreeLocksList.
  301. //----------------------------------------------------------------------------
  302. VOID
  303. ReleaseDynamicReadwriteLock (
  304. PDYNAMIC_READWRITE_LOCK *ppLock,
  305. LOCK_MODE lmMode,
  306. PDYNAMIC_LOCKS_STORE pStore
  307. )
  308. {
  309. // acquire the lock for the free locks list
  310. AcquireListLock(&pStore->llFreeLocksList);
  311. // release the dynamic readwrite lock
  312. if (lmMode == READ_MODE)
  313. ReleaseReadLock(&(*ppLock)->rwlLock);
  314. else
  315. ReleaseWriteLock(&(*ppLock)->rwlLock);
  316. // decrement count in the dynamic lock, free it if count becomes 0
  317. (*ppLock)->ulCount--;
  318. if ((*ppLock)->ulCount is 0)
  319. {
  320. FreeDynamicReadwriteLock(*ppLock, pStore);
  321. *ppLock = NULL; // so it is known that it doesn't exist
  322. }
  323. // release the lock for the free locks list
  324. ReleaseListLock(&pStore->llFreeLocksList);
  325. return;
  326. }
  327. #endif