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.

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