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.

397 lines
10 KiB

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