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.

868 lines
22 KiB

  1. //============================================================================
  2. // Copyright (c) 1996, Microsoft Corporation
  3. // File: sync.c
  4. //
  5. // History:
  6. // Abolade Gbadegesin
  7. // K.S.Lokesh (added Dynamic locking)
  8. //
  9. // Synchronization routines used by DVMRP.
  10. //============================================================================
  11. #include "pchdvmrp.h"
  12. #pragma hdrstop
  13. // for debugging, Set ids for each dynamic lock
  14. #ifdef LOCK_DBG
  15. DWORD DynamicCSLockId;
  16. DWORD DynamicRWLockId;
  17. #endif;
  18. //----------------------------------------------------------------------------
  19. // _QueueDvmrpWorker
  20. //
  21. // This function is called to queue a Dvmrp function in a safe fashion;
  22. // If cleanup is in progress or if Dvmrp has stopped, this function
  23. // discards the work-item. So dont use this function if you want the
  24. // work item to be executed when the protocol is being stopped.
  25. //----------------------------------------------------------------------------
  26. DWORD
  27. QueueDvmrpWorker(
  28. LPTHREAD_START_ROUTINE pFunction,
  29. PVOID pContext
  30. )
  31. {
  32. DWORD Error = NO_ERROR;
  33. BOOL Success;
  34. EnterCriticalSection(&Globals1.WorkItemCS);
  35. if (Globals1.RunningStatus != DVMRP_STATUS_RUNNING) {
  36. //
  37. // cannot queue a work function when dvmrp has quit or is quitting
  38. //
  39. Error = ERROR_CAN_NOT_COMPLETE;
  40. }
  41. else {
  42. ++Globals.ActivityCount;
  43. Success = QueueUserWorkItem(pFunction, pContext, 0);
  44. if (!Success) {
  45. Error = GetLastError();
  46. Trace1(ERR, "Error: Attempt to queue work item returned:%d",
  47. Error);
  48. if (--Globals.ActivityCount == 0) {
  49. SetEvent(Globals.ActivityEvent);
  50. }
  51. }
  52. }
  53. LeaveCriticalSection(&Globals1.WorkItemCS);
  54. return Error;
  55. }
  56. //----------------------------------------------------------------------------
  57. // _EnterDvmrpWorker
  58. //
  59. // This function is called when entering a dvmrp worker-function.
  60. // Since there is a lapse between the time a worker-function is queued
  61. // and the time the function is actually invoked by a worker thread,
  62. // this function must check to see if dvmrp has stopped or is stopping;
  63. // if this is the case, then it decrements the activity count,
  64. // sets ActivityEvent if outstanding work items == 0, and quits.
  65. //----------------------------------------------------------------------------
  66. BOOL
  67. EnterDvmrpWorker(
  68. )
  69. {
  70. BOOL Entered;
  71. EnterCriticalSection(&Globals1.WorkItemCS);
  72. if (Globals1.RunningStatus == DVMRP_STATUS_RUNNING) {
  73. // dvmrp is running, so the function may continue
  74. Entered = TRUE;
  75. }
  76. else if (Globals1.RunningStatus == DVMRP_STATUS_STOPPING) {
  77. // dvmrp is not running, but it was, so the function must stop.
  78. if (--Globals.ActivityCount == 0) {
  79. SetEvent(Globals.ActivityEvent);
  80. }
  81. Entered = FALSE;
  82. }
  83. LeaveCriticalSection(&Globals1.WorkItemCS);
  84. return Entered;
  85. }
  86. //----------------------------------------------------------------------------
  87. // _LeaveDvmrpWorker
  88. //
  89. // This function is called when leaving a dvmrp worker function.
  90. // It decrements the activity count, and sets the ActivityEvent if
  91. // dvmrp is stopping and there are no pending work items.
  92. //----------------------------------------------------------------------------
  93. VOID
  94. LeaveDvmrpWorker(
  95. )
  96. {
  97. EnterCriticalSection(&Globals1.WorkItemCS);
  98. if (--Globals.ActivityCount == 0) {
  99. SetEvent(Globals.ActivityEvent);
  100. }
  101. LeaveCriticalSection(&Globals1.WorkItemCS);
  102. }
  103. //----------------------------------------------------------------------------
  104. // _CreateReadWriteLock
  105. //
  106. // Initializes a multiple-reader/single-writer lock object
  107. //----------------------------------------------------------------------------
  108. DWORD
  109. CreateReadWriteLock(
  110. PREAD_WRITE_LOCK pRWL
  111. )
  112. {
  113. pRWL->RWL_ReaderCount = 0;
  114. try {
  115. InitializeCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
  116. }
  117. except (EXCEPTION_EXECUTE_HANDLER) {
  118. return GetLastError();
  119. }
  120. pRWL->RWL_ReaderDoneEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  121. if (pRWL->RWL_ReaderDoneEvent != NULL) {
  122. return GetLastError();
  123. }
  124. return NO_ERROR;
  125. }
  126. //----------------------------------------------------------------------------
  127. // _DeleteReadWriteLock
  128. //
  129. // Frees resources used by a multiple-reader/single-writer lock object
  130. //----------------------------------------------------------------------------
  131. VOID
  132. DeleteReadWriteLock(
  133. PREAD_WRITE_LOCK pRWL
  134. )
  135. {
  136. CloseHandle(pRWL->RWL_ReaderDoneEvent);
  137. pRWL->RWL_ReaderDoneEvent = NULL;
  138. DeleteCriticalSection(&pRWL->RWL_ReadWriteBlock);
  139. pRWL->RWL_ReaderCount = 0;
  140. }
  141. //----------------------------------------------------------------------------
  142. // _AcquireReadLock
  143. //
  144. // Secures shared ownership of the lock object for the caller.
  145. //
  146. // readers enter the read-write critical section, increment the count,
  147. // and leave the critical section
  148. //----------------------------------------------------------------------------
  149. VOID
  150. AcquireReadLock(
  151. PREAD_WRITE_LOCK pRWL
  152. )
  153. {
  154. EnterCriticalSection(&pRWL->RWL_ReadWriteBlock);
  155. InterlockedIncrement(&pRWL->RWL_ReaderCount);
  156. LeaveCriticalSection(&pRWL->RWL_ReadWriteBlock);
  157. }
  158. //----------------------------------------------------------------------------
  159. // _ReleaseReadLock
  160. //
  161. // Relinquishes shared ownership of the lock object.
  162. //
  163. // the last reader sets the event to wake any waiting writers
  164. //----------------------------------------------------------------------------
  165. VOID
  166. ReleaseReadLock (
  167. PREAD_WRITE_LOCK pRWL
  168. )
  169. {
  170. if (InterlockedDecrement(&pRWL->RWL_ReaderCount) < 0) {
  171. SetEvent(pRWL->RWL_ReaderDoneEvent);
  172. }
  173. }
  174. //----------------------------------------------------------------------------
  175. // _AcquireWriteLock
  176. //
  177. // Secures exclusive ownership of the lock object.
  178. //
  179. // the writer blocks other threads by entering the ReadWriteBlock section,
  180. // and then waits for any thread(s) owning the lock to finish
  181. //----------------------------------------------------------------------------
  182. VOID
  183. AcquireWriteLock(
  184. PREAD_WRITE_LOCK pRWL
  185. )
  186. {
  187. EnterCriticalSection(&pRWL->RWL_ReadWriteBlock);
  188. if (InterlockedDecrement(&pRWL->RWL_ReaderCount) >= 0) {
  189. WaitForSingleObject(pRWL->RWL_ReaderDoneEvent, INFINITE);
  190. }
  191. }
  192. //----------------------------------------------------------------------------
  193. // _ReleaseWriteLock
  194. //
  195. // Relinquishes exclusive ownership of the lock object.
  196. //
  197. // the writer releases the lock by setting the count to zero
  198. // and then leaving the ReadWriteBlock critical section
  199. //----------------------------------------------------------------------------
  200. VOID
  201. ReleaseWriteLock(
  202. PREAD_WRITE_LOCK pRWL
  203. )
  204. {
  205. pRWL->RWL_ReaderCount = 0;
  206. LeaveCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
  207. }
  208. //----------------------------------------------------------------------------
  209. // _InitializeDynamicLocks
  210. //
  211. // Initialize the global struct from which dynamic CS / RW locks are allocated
  212. //----------------------------------------------------------------------------
  213. DWORD
  214. InitializeDynamicLocks (
  215. PDYNAMIC_LOCKS_STORE pDLStore //ptr to Dynamic Locks store
  216. )
  217. {
  218. DWORD Error=NO_ERROR;
  219. BEGIN_BREAKOUT_BLOCK1 {
  220. //
  221. // initialize the main CS lock which protects the list of free locks
  222. //
  223. try {
  224. InitializeCriticalSection(&pDLStore->CS);
  225. }
  226. HANDLE_CRITICAL_SECTION_EXCEPTION(Error, GOTO_END_BLOCK1);
  227. // initialize list of free locks
  228. InitializeListHead(&pDLStore->ListOfFreeLocks);
  229. // initialize counts for number of locks free and allocated to 0.
  230. pDLStore->CountAllocated = pDLStore->CountFree = 0;
  231. } END_BREAKOUT_BLOCK1;
  232. return Error;
  233. }
  234. //----------------------------------------------------------------------------
  235. // _DeInitializeDynamicLocksStore
  236. //
  237. // Delete the main CS lock and the other free locks. Print warning if any
  238. // locks have been allocated and not freed.
  239. //----------------------------------------------------------------------------
  240. VOID
  241. DeInitializeDynamicLocks (
  242. PDYNAMIC_LOCKS_STORE pDLStore,
  243. LOCK_TYPE LockType //LOCK_TYPE_CS,LOCK_TYPE_RW
  244. )
  245. {
  246. PDYNAMIC_CS_LOCK pDCSLock;
  247. PDYNAMIC_RW_LOCK pDRWLock;
  248. PLIST_ENTRY pHead, pLe;
  249. Trace0(ENTER1, "Entering _DeInitializeDynamicLocksStore()");
  250. if (pDLStore==NULL)
  251. return;
  252. // delete the main CS lock
  253. DeleteCriticalSection(&pDLStore->CS);
  254. // print warning if any dynamic lock has not been freed
  255. if (pDLStore->CountFree>0) {
  256. Trace1(ERR,
  257. "%d Dynamic locks have not been freed during Deinitialization",
  258. pDLStore->CountFree);
  259. }
  260. //
  261. // delete all dynamic CS/RW locks. I dont free memory(left to heapDestroy)
  262. //
  263. pHead = &pDLStore->ListOfFreeLocks;
  264. for (pLe=pHead->Flink; pLe!=pHead; pLe=pLe->Flink) {
  265. // if bCSLocks flag, then it is a store of CS locks
  266. if (LockType==LOCK_TYPE_CS) {
  267. pDCSLock = CONTAINING_RECORD(pLe, DYNAMIC_CS_LOCK, Link);
  268. DeleteCriticalSection(&pDCSLock->CS);
  269. }
  270. // delete the RW lock
  271. else {
  272. pDRWLock = CONTAINING_RECORD(pLe, DYNAMIC_RW_LOCK, Link);
  273. DELETE_READ_WRITE_LOCK(&pDRWLock->RWL);
  274. }
  275. }
  276. Trace0(LEAVE1, "Leaving _DeInitializeDynamicLocksStore()");
  277. return;
  278. }
  279. //----------------------------------------------------------------------------
  280. // _AcquireDynamicCSLock
  281. //
  282. // Acquires the MainLock associated with the table, Acquires a new dynamic
  283. // lock if required, increments the count, releases the MainLock and
  284. // locks the LockedList.
  285. //----------------------------------------------------------------------------
  286. DWORD
  287. AcquireDynamicCSLock (
  288. PDYNAMIC_CS_LOCK *ppDCSLock,
  289. PDYNAMIC_LOCKS_STORE pDCSStore
  290. )
  291. {
  292. // acquire the main lock for the Dynamic CS store
  293. ENTER_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
  294. "_AcquireDynamicCSLock");
  295. //
  296. // If it is not already locked then allocate a lock
  297. //
  298. if (*ppDCSLock==NULL) {
  299. *ppDCSLock = GetDynamicCSLock(pDCSStore);
  300. // if could not get a lock, then igmp is in serious trouble
  301. if (*ppDCSLock==NULL) {
  302. LEAVE_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
  303. "_AcquireDynamicCSLock");
  304. return ERROR_CAN_NOT_COMPLETE;
  305. }
  306. }
  307. // increment Count in the Dynamic Lock
  308. (*ppDCSLock)->Count++;
  309. // leave main CS lock
  310. LEAVE_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
  311. "_AcquireDynamicCSLock");
  312. //
  313. // enter dynamic lock's CS lock
  314. //
  315. ENTER_CRITICAL_SECTION(&(*ppDCSLock)->CS, "pDynamicLock",
  316. "_AcquireDynamicCSLock");
  317. return NO_ERROR;
  318. } //end _AcquireDynamicCSLock
  319. //----------------------------------------------------------------------------
  320. // _GetDynamicCSLock
  321. //
  322. // If a free lock is available, returns it. Else allocates a new CS lock
  323. // Lock: Assumes the DCSStore MainLock
  324. // Called by: _AcquireDynamicCSLock
  325. //----------------------------------------------------------------------------
  326. PDYNAMIC_CS_LOCK
  327. GetDynamicCSLock (
  328. PDYNAMIC_LOCKS_STORE pDCSStore
  329. )
  330. {
  331. PDYNAMIC_CS_LOCK pDCSLock;
  332. DWORD Error = NO_ERROR;
  333. PLIST_ENTRY pLe;
  334. //
  335. // free dynamic lock available. Return it
  336. //
  337. if (!IsListEmpty(&pDCSStore->ListOfFreeLocks)) {
  338. pDCSStore->CountFree--;
  339. pLe = RemoveTailList(&pDCSStore->ListOfFreeLocks);
  340. pDCSLock = CONTAINING_RECORD(pLe, DYNAMIC_CS_LOCK, Link);
  341. Trace1(DYNLOCK, "Leaving GetDynamicCSLock.1(%d):reusing lock",
  342. pDCSLock->Id);
  343. return pDCSLock;
  344. }
  345. // allocate memory for a new dynamic lock
  346. pDCSLock = DVMRP_ALLOC(sizeof(DYNAMIC_CS_LOCK));
  347. PROCESS_ALLOC_FAILURE2(pDCSLock, "dynamic CS lock",
  348. Error, sizeof(DYNAMIC_CS_LOCK), return NULL);
  349. pDCSStore->CountAllocated++;
  350. //
  351. // initialize the fields
  352. //
  353. try {
  354. InitializeCriticalSection(&pDCSLock->CS);
  355. }
  356. HANDLE_CRITICAL_SECTION_EXCEPTION(Error, return NULL);
  357. // no need to initialize the link field
  358. //InitializeListEntry(&pDCSLock->List);
  359. pDCSLock->Count = 0;
  360. #ifdef LOCK_DBG
  361. pDCSLock->Id = ++DynamicCSLockId;
  362. #endif
  363. Trace1(DYNLOCK, "Leaving _GetDynamicCSLock(%d):new lock",
  364. DynamicCSLockId);
  365. return pDCSLock;
  366. } //end _GetDynamicCSLock
  367. //----------------------------------------------------------------------------
  368. // _ReleaseDynamicCSLock
  369. //
  370. // Acquires the MainLock associated with the table, decrements the count,
  371. // releases the DynamicLock if count becomes 0 and releases the MainLock.
  372. //----------------------------------------------------------------------------
  373. VOID
  374. ReleaseDynamicCSLock (
  375. PDYNAMIC_CS_LOCK *ppDCSLock,
  376. PDYNAMIC_LOCKS_STORE pDCSStore
  377. )
  378. {
  379. PDYNAMIC_CS_LOCK pDCSLock = *ppDCSLock;
  380. // acquire the main lock for the Dynamic CS store
  381. ENTER_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
  382. "_ReleaseDynamicCSLock");
  383. // leave the dynamic lock CS
  384. LEAVE_CRITICAL_SECTION(&pDCSLock->CS, "pDynamicLock",
  385. "_ReleaseDynamicCSLock");
  386. // Decrement Count in the Dynamic Lock. Free the dynamic lock if count==0
  387. if (--pDCSLock->Count==0) {
  388. FreeDynamicCSLock(pDCSLock, pDCSStore);
  389. // make the pDCSLock NULL so that it is known that it is not locked
  390. *ppDCSLock = NULL;
  391. }
  392. // leave main CS lock
  393. LEAVE_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
  394. "_ReleaseDynamicCSLock");
  395. //Trace0(LEAVE1, "Leaving _ReleaseDynamicCSLock()");
  396. return;
  397. } //end _ReleaseDynamicCSLock
  398. //----------------------------------------------------------------------------
  399. // _FreeDynamicCSLock
  400. // Called by: _ReleaseDynamicCSLock
  401. //----------------------------------------------------------------------------
  402. VOID
  403. FreeDynamicCSLock (
  404. PDYNAMIC_CS_LOCK pDCSLock,
  405. PDYNAMIC_LOCKS_STORE pDCSStore
  406. )
  407. {
  408. // decrement count of allocated locks
  409. pDCSStore->CountAllocated--;
  410. // if there are too many dynamic CS locks, then free this lock
  411. if (pDCSStore->CountAllocated+pDCSStore->CountFree+1
  412. > DYNAMIC_LOCKS_CS_HIGH_THRESHOLD)
  413. {
  414. DeleteCriticalSection(&pDCSLock->CS);
  415. DVMRP_FREE(pDCSLock);
  416. }
  417. // else put it into the list of free locks
  418. else {
  419. InsertHeadList(&pDCSStore->ListOfFreeLocks, &pDCSLock->Link);
  420. pDCSStore->CountFree++;
  421. }
  422. return;
  423. }
  424. //----------------------------------------------------------------------------
  425. // _AcquireDynamicRWLock
  426. //
  427. // Acquires the MainLock associated with the table, Acquires a new dynamic
  428. // lock if required, increments the count, releases the MainLock and
  429. // locks the LockedList.
  430. //----------------------------------------------------------------------------
  431. DWORD
  432. AcquireDynamicRWLock (
  433. PDYNAMIC_RW_LOCK *ppDRWLock,
  434. LOCK_TYPE LockMode,
  435. PDYNAMIC_LOCKS_STORE pDRWStore
  436. )
  437. {
  438. //Trace0(ENTER1, "Entering _AcquireDynamicRWLock()");
  439. // acquire the main lock for the Dynamic RW store
  440. ENTER_CRITICAL_SECTION(&pDRWStore->CS, "pDRWStore->CS",
  441. "AcquireDynamicRWLock");
  442. //
  443. // If it is not already locked then allocate a lock
  444. //
  445. if (*ppDRWLock==NULL) {
  446. *ppDRWLock = GetDynamicRWLock(pDRWStore);
  447. //Trace1(DYNLOCK, "Acquired dynamicRWLock(%d)", (*ppDRWLock)->Id);
  448. // if could not get a lock, then igmp is in serious trouble
  449. if (*ppDRWLock==NULL) {
  450. LEAVE_CRITICAL_SECTION(&pDRWStore->CS, "pDRWStore->CS",
  451. "AcquireDynamicRWLock");
  452. return ERROR_CAN_NOT_COMPLETE;
  453. }
  454. }
  455. else
  456. ;//Trace1(DYNLOCK, "Acquired existing dynamicRWLock(%d)", (*ppDRWLock)->Id);
  457. // increment Count in the Dynamic Lock
  458. (*ppDRWLock)->Count++;
  459. // leave main CS lock
  460. LEAVE_CRITICAL_SECTION(&pDRWStore->CS, "pDRWStore->CS",
  461. "_AcquireDynamicRWLock");
  462. //
  463. // acquire dynamic lock
  464. //
  465. if (LockMode==LOCK_MODE_READ) {
  466. ACQUIRE_READ_LOCK(&(*ppDRWLock)->RWL, "pDynamicLock(Read)",
  467. "_AcquireDynamicRWLock");
  468. }
  469. else {
  470. ACQUIRE_WRITE_LOCK(&(*ppDRWLock)->RWL, "pDynamicLock(Write)",
  471. "_AcquireDynamicRWLock");
  472. }
  473. return NO_ERROR;
  474. } //end _AcquireDynamicRWLock
  475. //----------------------------------------------------------------------------
  476. // _GetDynamicRWLock
  477. //
  478. // If a free lock is available, returns it. Else allocates a new CS lock
  479. // Lock: assumes the DRWStore MainLock
  480. //----------------------------------------------------------------------------
  481. PDYNAMIC_RW_LOCK
  482. GetDynamicRWLock (
  483. PDYNAMIC_LOCKS_STORE pDRWStore
  484. )
  485. {
  486. PDYNAMIC_RW_LOCK pDRWLock;
  487. DWORD Error = NO_ERROR;
  488. PLIST_ENTRY pLe;
  489. //
  490. // free dynamic lock available. Return it
  491. //
  492. if (!IsListEmpty(&pDRWStore->ListOfFreeLocks)) {
  493. pDRWStore->CountFree--;
  494. pLe = RemoveTailList(&pDRWStore->ListOfFreeLocks);
  495. pDRWLock = CONTAINING_RECORD(pLe, DYNAMIC_RW_LOCK, Link);
  496. /*Trace1(LEAVE1, "Leaving GetDynamicRWLock(%d):reusing lock",
  497. pDRWLock->Id);
  498. Trace2(DYNLOCK, "-------------%d %d", pDRWLock->Id, DynamicRWLockId);
  499. */
  500. return pDRWLock;
  501. }
  502. // allocate memory for a new dynamic lock
  503. pDRWLock = DVMRP_ALLOC(sizeof(DYNAMIC_RW_LOCK));
  504. PROCESS_ALLOC_FAILURE2(pDRWLock, "dynamic RW lock",
  505. Error, sizeof(DYNAMIC_RW_LOCK), return NULL);
  506. pDRWStore->CountAllocated++;
  507. //
  508. // initialize the fields
  509. //
  510. try {
  511. CREATE_READ_WRITE_LOCK(&pDRWLock->RWL);
  512. }
  513. HANDLE_CRITICAL_SECTION_EXCEPTION(Error, return NULL);
  514. // no need to initialize the link field
  515. //InitializeListEntry(&pDRWLock->List);
  516. pDRWLock->Count = 0;
  517. #ifdef LOCK_DBG
  518. pDRWLock->Id = ++DynamicRWLockId;
  519. #endif
  520. //Trace1(LEAVE1, "Leaving GetDynamicRWLock(%d):new lock", DynamicRWLockId);
  521. //Trace2(DYNLOCK, "--------------------%d %d", pDRWLock->Id, DynamicRWLockId);
  522. return pDRWLock;
  523. } //end _GetDynamicRWLock
  524. //------------------------------------------------------------------------------
  525. // _ReleaseDynamicRWLock
  526. //
  527. // Acquires the MainLock associated with the table, decrements the count,
  528. // releases the DynamicLock if count becomes 0 and releases the MainLock.
  529. //------------------------------------------------------------------------------
  530. VOID
  531. ReleaseDynamicRWLock (
  532. PDYNAMIC_RW_LOCK *ppDRWLock,
  533. LOCK_TYPE LockMode,
  534. PDYNAMIC_LOCKS_STORE pDRWStore
  535. )
  536. {
  537. PDYNAMIC_RW_LOCK pDRWLock = *ppDRWLock;
  538. // acquire the main lock for the Dynamic RW store
  539. ENTER_CRITICAL_SECTION(&pDRWStore->CS, "pDRWStore->CS",
  540. "_ReleaseDynamicRWLock");
  541. IgmpAssert(pDRWLock!=NULL);
  542. #if DBG
  543. if (pDRWLock==NULL)
  544. DbgBreakPoint();
  545. #endif
  546. // leave the dynamic RW lock
  547. if (LockMode==LOCK_MODE_READ) {
  548. RELEASE_READ_LOCK(&pDRWLock->RWL, "pDynamicLock(read)",
  549. "_ReleaseDynamicRWLock");
  550. }
  551. else {
  552. RELEASE_WRITE_LOCK(&pDRWLock->RWL, "pDynamicLock(write)",
  553. "_ReleaseDynamicRWLock");
  554. }
  555. // Decrement Count in the Dynamic Lock. Free the dynamic lock if count==0
  556. if (--pDRWLock->Count==0) {
  557. FreeDynamicRWLock(pDRWLock, pDRWStore);
  558. // make the pDRWLock NULL so that it is known that it is not locked
  559. *ppDRWLock = NULL;
  560. }
  561. // leave main CS lock
  562. LEAVE_CRITICAL_SECTION(&pDRWStore->CS, "pDCSStore->CS",
  563. "_ReleaseDynamicRWLock");
  564. return;
  565. } //end _ReleaseDynamicRWLock
  566. //------------------------------------------------------------------------------
  567. // _FreeDynamicRWLock
  568. //------------------------------------------------------------------------------
  569. VOID
  570. FreeDynamicRWLock (
  571. PDYNAMIC_RW_LOCK pDRWLock,
  572. PDYNAMIC_LOCKS_STORE pDRWStore
  573. )
  574. {
  575. // decrement count of allocated locks
  576. pDRWStore->CountAllocated--;
  577. // if there are too many dynamic RW locks, then free this lock
  578. if (pDRWStore->CountAllocated+pDRWStore->CountFree+1
  579. > DYNAMIC_LOCKS_CS_HIGH_THRESHOLD)
  580. {
  581. DELETE_READ_WRITE_LOCK(&pDRWLock->RWL);
  582. DVMRP_FREE(pDRWLock);
  583. }
  584. // else put it into the list of free locks
  585. else {
  586. InsertHeadList(&pDRWStore->ListOfFreeLocks, &pDRWLock->Link);
  587. pDRWStore->CountFree++;
  588. }
  589. return;
  590. }