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.

1465 lines
38 KiB

  1. //=============================================================================
  2. // Copyright (c) 1997 Microsoft Corporation
  3. // File Name: igmptimer.c
  4. //
  5. // Abstract: This module implements the igmptimer
  6. //
  7. // Author: K.S.Lokesh (lokeshs@) 11-1-97
  8. //
  9. // Revision History:
  10. //=============================================================================
  11. #include "pchigmp.h"
  12. //DebugCheck //ksltodo
  13. //DWORD MyDebug = 0x0;
  14. DWORD MyDebug = 0x0; //DebugScanTimerQueue while running
  15. DWORD DebugIgmpVersion = 13;
  16. ULONG g_DebugPrint = 0; //flag to enable DebugPrintTimerQueue while running
  17. DWORD DEBUG_CHECK_LOW_INDEX_ARRAY[100][2]; //deldel
  18. DWORD DebugIgmpIndex; //deldel
  19. #if DEBUG_TIMER_LEVEL & DEBUG_TIMER_TIMERID
  20. DWORD TimerId =0;
  21. #endif
  22. ULONG g_Fire = 0; // global variable
  23. //------------------------------------------------------------------------------
  24. //
  25. // FUNCTION PROTOTYPES USED ONLY IN THIS FILE
  26. //
  27. VOID
  28. SetNextTime(
  29. DWORD dwLowIndex
  30. );
  31. VOID
  32. ResyncTimerBuckets(
  33. LONGLONG llCurTime
  34. );
  35. VOID
  36. InsertTimerInSortedList(
  37. PIGMP_TIMER_ENTRY pteNew,
  38. PLIST_ENTRY pHead
  39. );
  40. //------------------------------------------------------------------------------
  41. //
  42. // #DEFINES USED ONLY IN THIS FILE
  43. //
  44. //
  45. //approx 16 secs in each bucket:
  46. //it is approx not accurate as I divide by 2^10 instead of 1000
  47. //TIMER_BUCKET_GRANULARITY should be 2^TIMER_BUCKET_GRANULARITY_SHIFT
  48. //
  49. #define TIMER_BUCKET_GRANULARITY 16
  50. #define TIMER_BUCKET_GRANULARITY_SHIFT 4
  51. #define SEC_CONV_SHIFT 10
  52. #define TIMER_BUCKET_GRANULARITY_ABS \
  53. ((LONGLONG) (1 << (TIMER_BUCKET_GRANULARITY_SHIFT + SEC_CONV_SHIFT) ))
  54. #define MAP_TO_BUCKET(dwBucket, ilTime) \
  55. dwBucket = (DWORD) (((ilTime)-g_TimerStruct.SyncTime) \
  56. >> (TIMER_BUCKET_GRANULARITY_SHIFT+SEC_CONV_SHIFT)); \
  57. dwBucket = dwBucket>NUM_TIMER_BUCKETS-1? NUM_TIMER_BUCKETS-1: dwBucket
  58. // I fire a timer even if it is set to 10 millisec in the future.
  59. #define FORWARD_TIMER_FIRED 10
  60. //------------------------------------------------------------------------------
  61. ULONG
  62. QueryRemainingTime(
  63. PIGMP_TIMER_ENTRY pte,
  64. LONGLONG llCurTime
  65. )
  66. {
  67. if (llCurTime==0)
  68. llCurTime = GetCurrentIgmpTime();
  69. return llCurTime>pte->Timeout ? 0 : (ULONG)(pte->Timeout-llCurTime);
  70. }
  71. // DebugCheck
  72. VOID
  73. DebugCheckLowTimer(
  74. DWORD Flags
  75. )
  76. {
  77. PIGMP_TIMER_GLOBAL ptg = &g_TimerStruct;
  78. DWORD i;
  79. PIGMP_TIMER_ENTRY pte, pteMin;
  80. LONGLONG ilMinTime;
  81. PLIST_ENTRY pHead, ple;
  82. Trace0(ENTER1, "In _DebugCheckLowTimer");
  83. if (ptg->NumTimers==0)
  84. return;
  85. for (i=0; i<=ptg->TableLowIndex; i++) {
  86. pHead = &ptg->TimesTable[i];
  87. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  88. pte = CONTAINING_RECORD(ple, IGMP_TIMER_ENTRY, Link);
  89. CHECK_TIMER_SIGNATURE(pte);
  90. if (Flags & 1) {
  91. if (pte->Timeout<ptg->WTTimeout) {
  92. DbgBreakPoint();
  93. }
  94. }
  95. if (i<ptg->TableLowIndex)
  96. DbgBreakPoint();
  97. }
  98. }
  99. return;
  100. }
  101. //------------------------------------------------------------------------------
  102. // _InsertTimer
  103. //
  104. // Inserts a timer into the local timer queue. Time should always be relative.
  105. //
  106. // Locks: Assumes lock taken on ptg->CS
  107. //------------------------------------------------------------------------------
  108. DWORD
  109. InsertTimer (
  110. PIGMP_TIMER_ENTRY pte,
  111. LONGLONG llNewTime,
  112. BOOL bResync,
  113. BOOL bDbg
  114. )
  115. {
  116. LONGLONG llCurTime = GetCurrentIgmpTime();
  117. PIGMP_TIMER_GLOBAL ptg;
  118. DWORD dwBucket, Error = NO_ERROR;
  119. CHECK_TIMER_SIGNATURE(pte);
  120. CHECK_IF_ACQUIRED_TIMER_LOCK();
  121. DebugCheckLowTimer(1);//deldel
  122. DEBUG_CHECK_LOW_INDEX(1);//deldel
  123. if (pte->Status & TIMER_STATUS_ACTIVE) {
  124. UpdateLocalTimer(pte, llNewTime, bDbg);
  125. return NO_ERROR;
  126. }
  127. // deldel
  128. if (MyDebug&0x1) DebugScanTimerQueue(1);
  129. Trace0(ENTER1, "_InsertTimer()");
  130. // print the queue before inserting the timer
  131. #if DEBUG_TIMER_INSERTTIMER1
  132. Trace0(TIMER1, "Printing Timer Queue before InsertTimer");
  133. DebugPrintTimerQueue();
  134. #endif
  135. ptg = &g_TimerStruct;
  136. // convert relative time to absolute time
  137. llNewTime += llCurTime;
  138. pte->Timeout = llNewTime;
  139. MAP_TO_BUCKET(dwBucket, pte->Timeout);
  140. // print info about the timer being inserted
  141. #if DEBUG_TIMER_ACTIVITY
  142. {
  143. DWORD dwBucket, dwDiffTime;
  144. CHAR str1[20], str2[20];
  145. MAP_TO_BUCKET(dwBucket, pte->Timeout);
  146. GetTimerDebugInfo(str1, str2, &dwDiffTime, pte, llCurTime);
  147. Trace7(TIMER, "Inserting timer <%d><%d><%d> Timeout:%lu <%s> "
  148. "<%s> Status:%d", dwBucket, pte->Id, pte->Id2, dwDiffTime,
  149. str1, str2, pte->Status);
  150. }
  151. #endif
  152. //
  153. // insert timer in appropriate list
  154. //
  155. if (dwBucket==0) { // bucket 0 contains a sorted list
  156. InsertTimerInSortedList(pte, &ptg->TimesTable[0]);
  157. }
  158. else {
  159. InsertTailList(&ptg->TimesTable[dwBucket], &pte->Link);
  160. }
  161. DEBUG_CHECK_LOW_INDEX(2);//deldel
  162. ptg->NumTimers++;
  163. ptg->TableLowIndex = ptg->TableLowIndex<dwBucket
  164. ? ptg->TableLowIndex : dwBucket;
  165. DEBUG_CHECK_LOW_INDEX(3);//deldel
  166. //resynchronize timer list
  167. if (bResync) {
  168. if ( (ptg->TableLowIndex!=0)
  169. && (ptg->SyncTime + TIMER_BUCKET_GRANULARITY_ABS < llCurTime) ) {
  170. ResyncTimerBuckets(llCurTime);
  171. }
  172. }
  173. DEBUG_CHECK_LOW_INDEX(4);//deldel
  174. //
  175. // if time being inserted is lower than the minimum, then update wait timer
  176. //
  177. if ((IS_TIMER_INFINITE(ptg->WTTimeout)) || (pte->Timeout<=ptg->WTTimeout)) {
  178. ptg->WTTimeout = pte->Timeout;
  179. if (!IS_TIMER_INFINITE(ptg->WTTimeout)) {
  180. BOOL bSuccess ;
  181. bSuccess = ChangeTimerQueueTimer(ptg->WTTimer, ptg->WTTimer1,
  182. llCurTime<ptg->WTTimeout
  183. ?(ULONG) ((ptg->WTTimeout - llCurTime))
  184. : 0,
  185. 1000000 // set a periodic timer
  186. );
  187. if (!bSuccess) {
  188. Error = GetLastError();
  189. Trace1(ERR, "ChangeTimerQueueTimer returned error:%d", Error);
  190. IgmpAssertOnError(FALSE);
  191. }
  192. else {
  193. #if DEBUG_TIMER_ACTIVITY
  194. Trace1(TIMER1, "ChangeTimerQueueTimer set to %lu",
  195. (ULONG) ((ptg->WTTimeout - llCurTime))/1000);
  196. #if DEBUG_TIMER_ID
  197. g_Fire = (ULONG) ((ptg->WTTimeout - llCurTime)/1000);
  198. #endif
  199. #endif
  200. }
  201. }
  202. }
  203. pte->Status = TIMER_STATUS_ACTIVE;
  204. #if DEBUG_TIMER_INSERTTIMER2
  205. if (bDbg||g_DebugPrint) {
  206. Trace0(TIMER1, " ");
  207. Trace0(TIMER1, "Printing Timer Queue after _InsertTimer");
  208. DebugPrintTimerQueue();
  209. }
  210. #endif
  211. //kslksl
  212. if (MyDebug&0x2) DebugScanTimerQueue(2);
  213. DebugCheckLowTimer(1);//deldel
  214. DEBUG_CHECK_LOW_INDEX(5);//deldel
  215. Trace0(LEAVE1, "Leaving _InsertTimer()");
  216. return NO_ERROR;
  217. } //end _InsertTimer
  218. //------------------------------------------------------------------------------
  219. // _UpdateLocalTimer
  220. //
  221. // Change the time in a timer structure and (re)insert it in the timer queue.
  222. // Locks: Assumes lock on the global timer
  223. //------------------------------------------------------------------------------
  224. VOID
  225. UpdateLocalTimer (
  226. PIGMP_TIMER_ENTRY pte,
  227. LONGLONG llNewTime,
  228. BOOL bDbgPrint
  229. )
  230. {
  231. Trace0(ENTER1, "_UpdateLocalTimer():");
  232. CHECK_TIMER_SIGNATURE(pte);
  233. CHECK_IF_ACQUIRED_TIMER_LOCK();
  234. DebugCheckLowTimer(1);//deldel
  235. DEBUG_CHECK_LOW_INDEX(6);//deldel
  236. // print info about the timer being updated
  237. #if DEBUG_TIMER_ACTIVITY
  238. {
  239. DWORD dwBucket, dwDiffTime;
  240. CHAR str1[20], str2[20];
  241. LONGLONG llCurTime = GetCurrentIgmpTime();
  242. MAP_TO_BUCKET(dwBucket, pte->Timeout);
  243. GetTimerDebugInfo(str1, str2, &dwDiffTime, pte, llCurTime);
  244. Trace0(TIMER, " \n");
  245. Trace8(TIMER, "Updating timer <%d><%d><%d> Timeout:%lu <%s> <%s> "
  246. "to %d Status:%d\n", dwBucket, pte->Id, pte->Id2, dwDiffTime,
  247. str1, str2, (DWORD)llNewTime, pte->Status);
  248. }
  249. #endif
  250. // first remove the timer
  251. if (pte->Status&TIMER_STATUS_ACTIVE) {
  252. RemoveTimer(pte, DBG_N);
  253. }
  254. DEBUG_CHECK_LOW_INDEX(7);//deldel
  255. // now insert the timer back into the timer queue. Resync flag is set
  256. InsertTimer(pte, llNewTime, TRUE, DBG_N);
  257. #if DEBUG_TIMER_UPDATETIMER1
  258. if (bDbgPrint||g_DebugPrint) {
  259. Trace0(TIMER1, " ");
  260. Trace0(TIMER1, "Printing Timer Queue after _UpdateTimer");
  261. DebugPrintTimerQueue();
  262. }
  263. #endif
  264. //kslksl
  265. if (MyDebug&0x4) DebugScanTimerQueue(4);
  266. DebugCheckLowTimer(1);//deldel
  267. DEBUG_CHECK_LOW_INDEX(8);//deldel
  268. Trace0(LEAVE1, "_UpdateLocalTimer()");
  269. return;
  270. }
  271. //------------------------------------------------------------------------------
  272. // _RemoveTimer
  273. //
  274. // Removes the timer from the list. Changes the status of the timer to CREATED.
  275. // Assumes global timer lock.
  276. //------------------------------------------------------------------------------
  277. VOID
  278. RemoveTimer (
  279. PIGMP_TIMER_ENTRY pte,
  280. BOOL bDbg
  281. )
  282. {
  283. LONGLONG llCurTime = GetCurrentIgmpTime();
  284. PIGMP_TIMER_GLOBAL ptg = &g_TimerStruct;
  285. Trace0(ENTER1, "_RemoveTimer()");
  286. CHECK_TIMER_SIGNATURE(pte);
  287. CHECK_IF_ACQUIRED_TIMER_LOCK();
  288. DebugCheckLowTimer(1);//deldel
  289. DEBUG_CHECK_LOW_INDEX(9);//deldel
  290. // print info about the timer being removed
  291. #if DEBUG_TIMER_ACTIVITY
  292. {
  293. DWORD dwBucket, dwDiffTime;
  294. CHAR str1[20], str2[20];
  295. MAP_TO_BUCKET(dwBucket, pte->Timeout);
  296. GetTimerDebugInfo(str1, str2, &dwDiffTime, pte, llCurTime);
  297. Trace7(TIMER, "Removing timer <%d><%d><%d> Timeout:%lu <%s> <%s> "
  298. "Status:%d", dwBucket, pte->Id, pte->Id2, dwDiffTime, str1,
  299. str2, pte->Status);
  300. }
  301. #endif
  302. // remove the timer from the timer queue and decrement the number of timers
  303. RemoveEntryList(&pte->Link);
  304. ptg->NumTimers--;
  305. // reset the minimum timeout for the timer queue, if this timer was the min
  306. if (pte->Timeout==ptg->WTTimeout) {
  307. SetNextTime(ptg->TableLowIndex);
  308. }
  309. DEBUG_CHECK_LOW_INDEX(10);//deldel
  310. // reset the timer status to created
  311. pte->Status = TIMER_STATUS_CREATED;
  312. // print timer queue
  313. #if DEBUG_TIMER_REMOVETIMER2
  314. if (bDbg||g_DebugPrint) {
  315. Trace0(TIMER1, " ");
  316. Trace0(TIMER1, "Printing Timer Queue after _RemoveTimer");
  317. DebugPrintTimerQueue();
  318. }
  319. #endif
  320. //kslksl
  321. if (MyDebug&0x8) DebugScanTimerQueue(8);
  322. DebugCheckLowTimer(1);//deldel
  323. DEBUG_CHECK_LOW_INDEX(11);//deldel
  324. Trace0(LEAVE1, "Leaving _RemoveTimer()");
  325. return;
  326. }
  327. //------------------------------------------------------------------------------
  328. // _SetNextTime
  329. // called when a timer==WTTimeout has been removed or fired,used to set the
  330. // next min time.
  331. //------------------------------------------------------------------------------
  332. VOID
  333. SetNextTime (
  334. DWORD dwLowIndex
  335. )
  336. {
  337. PIGMP_TIMER_GLOBAL ptg = &g_TimerStruct;
  338. PIGMP_TIMER_ENTRY pte, pteMin=NULL;
  339. LONGLONG ilMinTime;
  340. PLIST_ENTRY pHead, ple;
  341. DWORD Error = NO_ERROR;
  342. LONGLONG llCurTime=GetCurrentIgmpTime();
  343. //kslksl
  344. //Trace0(TIMER1, "entering _SetNextTime()");
  345. DEBUG_CHECK_LOW_INDEX(12);//deldel
  346. //kslksl
  347. if (MyDebug&0x11) DebugScanTimerQueue(0x11);
  348. //
  349. // if timer list empty, set lowIndex, and timer to infinite, and return.
  350. //
  351. if (ptg->NumTimers==0) {
  352. ptg->TableLowIndex = (DWORD)~0;
  353. SET_TIMER_INFINITE(ptg->WTTimeout);
  354. ptg->Status = TIMER_STATUS_INACTIVE;
  355. return;
  356. }
  357. DEBUG_CHECK_LOW_INDEX(13);//deldel
  358. //
  359. // find lowest table index having an entry
  360. //
  361. if (dwLowIndex>NUM_TIMER_BUCKETS-1)
  362. dwLowIndex = 0;
  363. for (; dwLowIndex<=NUM_TIMER_BUCKETS-1; dwLowIndex++) {
  364. if (IsListEmpty(&ptg->TimesTable[dwLowIndex]) )
  365. continue;
  366. else
  367. break;
  368. }
  369. DEBUG_CHECK_LOW_INDEX(14);//deldel
  370. ptg->TableLowIndex = dwLowIndex;
  371. DEBUG_CHECK_LOW_INDEX(15);//deldel
  372. //kslksl
  373. if (dwLowIndex==NUM_TIMER_BUCKETS)
  374. DbgBreakPoint();
  375. //
  376. // find timer entry with the lowest time
  377. //
  378. if (dwLowIndex==0) {
  379. pteMin = CONTAINING_RECORD(ptg->TimesTable[0].Flink,
  380. IGMP_TIMER_ENTRY, Link);
  381. }
  382. else {
  383. // except bucket[0], other buckets are not sorted
  384. pHead = &ptg->TimesTable[dwLowIndex];
  385. ilMinTime = (((LONGLONG)0x7FFFFFF)<<32)+ ~0;
  386. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  387. pte = CONTAINING_RECORD(ple, IGMP_TIMER_ENTRY, Link);
  388. if (pte->Timeout<ilMinTime) {
  389. ilMinTime = pte->Timeout;
  390. pteMin = pte;
  391. }
  392. }
  393. }
  394. //
  395. // update global time
  396. //
  397. if ((IS_TIMER_INFINITE(ptg->WTTimeout))
  398. || (pteMin->Timeout<=ptg->WTTimeout))
  399. {
  400. ptg->WTTimeout = pteMin->Timeout;
  401. if (!IS_TIMER_INFINITE(ptg->WTTimeout)) {
  402. BOOL bSuccess ;
  403. bSuccess = ChangeTimerQueueTimer(ptg->WTTimer, ptg->WTTimer1,
  404. llCurTime<ptg->WTTimeout
  405. ?(ULONG) ((ptg->WTTimeout - llCurTime))
  406. : 0,
  407. 1000000 // set a periodic timer
  408. );
  409. if (!bSuccess) {
  410. Error = GetLastError();
  411. Trace1(ERR, "ChangeTimerQueueTimer returned error:%d in SetNextTime",
  412. Error);
  413. IgmpAssertOnError(FALSE);
  414. }
  415. else {
  416. #if DEBUG_TIMER_ACTIVITY
  417. Trace1(TIMER1, "ChangeTimerQueueTimer set to %lu",
  418. (ULONG) ((ptg->WTTimeout - llCurTime))/1000);
  419. #if DEBUG_TIMER_ID
  420. g_Fire = (ULONG) ((ptg->WTTimeout - llCurTime)/1000);
  421. #endif
  422. #endif
  423. }
  424. }
  425. ptg->Status = TIMER_STATUS_ACTIVE;
  426. }
  427. DEBUG_CHECK_LOW_INDEX(16);//deldel
  428. //
  429. // resynchronize timer list if required
  430. //
  431. if ( (ptg->TableLowIndex!=0)
  432. && (ptg->SyncTime + TIMER_BUCKET_GRANULARITY_ABS > llCurTime) ) {
  433. ResyncTimerBuckets(llCurTime);
  434. }
  435. //kslksl
  436. if (MyDebug&0x12) DebugScanTimerQueue(0x12);
  437. DebugCheckLowTimer(1);//deldel
  438. DEBUG_CHECK_LOW_INDEX(17);//deldel
  439. Trace0(LEAVE1, "_SetNextTime()");
  440. return;
  441. } //end _SetNextTime
  442. //------------------------------------------------------------------------------
  443. // _InitializeIgmpTime
  444. // Initialize the igmp absolute timer
  445. //------------------------------------------------------------------------------
  446. VOID
  447. InitializeIgmpTime(
  448. )
  449. {
  450. g_TimerStruct.CurrentTime.HighPart = 0;
  451. g_TimerStruct.CurrentTime.LowPart = GetTickCount();
  452. return;
  453. }
  454. //------------------------------------------------------------------------------
  455. // _GetCurrentIgmpTimer
  456. // uses GetTickCount(). converts it into 64 bit absolute timer.
  457. //------------------------------------------------------------------------------
  458. LONGLONG
  459. GetCurrentIgmpTime(
  460. )
  461. {
  462. ULONG ulCurTimeLow = GetTickCount();
  463. //
  464. // see if timer has wrapped
  465. //
  466. // since multi-threaded, it might get preempted and CurrentTime
  467. // might get lower than the global variable g_TimerStruct.CurrentTime.LowPart
  468. // which might be set by another thread. So we also explicitly verify the
  469. // switch from a very large DWORD to a small one.
  470. // (code thanks to murlik&jamesg)
  471. //
  472. if ( (ulCurTimeLow < g_TimerStruct.CurrentTime.LowPart)
  473. && ((LONG)g_TimerStruct.CurrentTime.LowPart < 0)
  474. && ((LONG)ulCurTimeLow > 0) )
  475. {
  476. // use global CS instead of creating a new CS
  477. ACQUIRE_GLOBAL_LOCK("_GetCurrentIgmpTime");
  478. // make sure that the global timer has not been updated meanwhile
  479. if ( (LONG)g_TimerStruct.CurrentTime.LowPart < 0)
  480. {
  481. g_TimerStruct.CurrentTime.HighPart++;
  482. g_TimerStruct.CurrentTime.LowPart = ulCurTimeLow;
  483. }
  484. RELEASE_GLOBAL_LOCK("_GetCurrentIgmpTime");
  485. }
  486. g_TimerStruct.CurrentTime.LowPart = ulCurTimeLow;
  487. return g_TimerStruct.CurrentTime.QuadPart;
  488. }
  489. //------------------------------------------------------------------------------
  490. // _WF_ProcessTimerEvent
  491. //
  492. // Processes the timer queue, firing events and sets the next timer at the end.
  493. // Is queued by the Wait Server Thread.
  494. //
  495. // Locks: Acquires global timer lock before entering into the timer queue.
  496. //------------------------------------------------------------------------------
  497. VOID
  498. WF_ProcessTimerEvent (
  499. PVOID pContext
  500. )
  501. {
  502. PIGMP_TIMER_GLOBAL ptg = &g_TimerStruct;
  503. LONGLONG ilDiffTime, llCurTime = GetCurrentIgmpTime();
  504. DWORD Error = NO_ERROR;
  505. PLIST_ENTRY pHead, ple;
  506. PIGMP_TIMER_ENTRY pte;
  507. LONGLONG llFiredTimeout;
  508. #if DEBUG_TIMER_PROCESSQUEUE2
  509. BOOL bDbg = FALSE;
  510. #endif
  511. if (!EnterIgmpWorker()) {return;}
  512. Trace0(ENTER1, "Entering _WF_ProcessTimerEvent");
  513. // acquire timer lock
  514. ACQUIRE_TIMER_LOCK("_WF_ProcessTimerEvent");
  515. // print the timer queue
  516. #if DEBUG_TIMER_PROCESSQUEUE1
  517. Trace0(TIMER1, "Printing Timer Queue before processing the timer queue");
  518. DebugPrintTimerQueue();
  519. #endif
  520. BEGIN_BREAKOUT_BLOCK1 {
  521. // I fire a timer if it is set to within + FORWARD_TIMER_FIRED from now
  522. llFiredTimeout = llCurTime + FORWARD_TIMER_FIRED;
  523. // if there are no timers, then I am done
  524. if (ptg->NumTimers<1) {
  525. Trace1(TIMER1, "Num timers%d less than 1 in _WF_ProcessTimerEvent",
  526. ptg->NumTimers);
  527. GOTO_END_BLOCK1;
  528. }
  529. //
  530. // find all the timers with lower timeouts and fire callbacks in my context
  531. //
  532. for ( ; ptg->TableLowIndex <= NUM_TIMER_BUCKETS-1; ptg->TableLowIndex++) {
  533. pHead = &ptg->TimesTable[ptg->TableLowIndex];
  534. for (ple=pHead->Flink; ple!=pHead; ) {
  535. pte = CONTAINING_RECORD(ple, IGMP_TIMER_ENTRY, Link);
  536. ple = ple->Flink;
  537. // this timer is fired
  538. if (pte->Timeout < llFiredTimeout) {
  539. RemoveEntryList(&pte->Link);
  540. pte->Status = TIMER_STATUS_FIRED;
  541. ptg->NumTimers --;
  542. //or should i queue to other worker threads
  543. (pte->Function)(pte->Context);
  544. #if DEBUG_TIMER_PROCESSQUEUE2
  545. if (pte->Function!=WT_MibDisplay && pte->Function!=T_QueryTimer)
  546. bDbg = TRUE;
  547. #endif
  548. }
  549. else {
  550. if (ptg->TableLowIndex==0) //only the 1st bucket is sorted
  551. break;
  552. }
  553. }
  554. // if any bucket is empty, then I am done, as I start with LowIndex
  555. if (!IsListEmpty(&ptg->TimesTable[ptg->TableLowIndex]))
  556. break;
  557. } //end for loop
  558. if ( (ptg->TableLowIndex!=0)
  559. && (ptg->SyncTime + TIMER_BUCKET_GRANULARITY_ABS < llCurTime) ) {
  560. ResyncTimerBuckets(llCurTime);
  561. }
  562. //
  563. // set the next lowest time
  564. //
  565. SET_TIMER_INFINITE(ptg->WTTimeout);
  566. SetNextTime(ptg->TableLowIndex);
  567. } END_BREAKOUT_BLOCK1;
  568. // print the timer queue
  569. #if DEBUG_TIMER_PROCESSQUEUE2
  570. if (bDbg||g_DebugPrint) {
  571. Trace0(TIMER1, " ");
  572. Trace0(TIMER1, "Printing Timer Queue after processing the timer queue");
  573. DebugPrintTimerQueue();
  574. }
  575. #endif
  576. //kslksl
  577. if (MyDebug&0x14) DebugScanTimerQueue(0x14);
  578. RELEASE_TIMER_LOCK("_WF_ProcessTimerEvent");
  579. Trace0(LEAVE1, "Leaving _WF_ProcessTimerEvent()");
  580. LeaveIgmpWorker();
  581. return ;
  582. } //end _WF_ProcessTimerEvent
  583. //------------------------------------------------------------------------------
  584. // WT_ProcessTimerEvent
  585. //
  586. // Callback: fired when the timer set by this dll is timed out by the NtdllTimer
  587. //------------------------------------------------------------------------------
  588. VOID
  589. WT_ProcessTimerEvent (
  590. PVOID pContext,
  591. BOOLEAN Unused
  592. )
  593. {
  594. //enter/leaveIgmpApi not required as the timer queue is persistent
  595. Trace0(ENTER1, "Entering _WT_ProcessTimerEvent()");
  596. QueueIgmpWorker((LPTHREAD_START_ROUTINE)WF_ProcessTimerEvent, pContext);
  597. Trace0(LEAVE1, "Leaving _WT_ProcessTimerEvent()");
  598. return;
  599. }
  600. //------------------------------------------------------------------------------
  601. // _InsertTimerInSortedList
  602. // Used to insert a timer in the sorted bucket=0
  603. //------------------------------------------------------------------------------
  604. VOID
  605. InsertTimerInSortedList(
  606. PIGMP_TIMER_ENTRY pteNew,
  607. PLIST_ENTRY pHead
  608. )
  609. {
  610. PLIST_ENTRY ple;
  611. PIGMP_TIMER_ENTRY pte;
  612. LONGLONG llNewTime;
  613. llNewTime = pteNew->Timeout;
  614. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  615. pte = CONTAINING_RECORD(ple, IGMP_TIMER_ENTRY, Link);
  616. if (llNewTime<= pte->Timeout)
  617. break;
  618. }
  619. InsertTailList(ple, &pteNew->Link);
  620. return;
  621. }
  622. //------------------------------------------------------------------------------
  623. // _ResyncTimerBuckets
  624. //
  625. // Called during insert: when the 1st bucket is empty, and other buckets have
  626. // to be moved left
  627. //------------------------------------------------------------------------------
  628. VOID
  629. ResyncTimerBuckets(
  630. LONGLONG llCurTime
  631. )
  632. {
  633. PIGMP_TIMER_GLOBAL ptg = &g_TimerStruct;
  634. PLIST_ENTRY pHead, ple, pleCur;
  635. LIST_ENTRY le;
  636. PIGMP_TIMER_ENTRY pte;
  637. LONGLONG lastBucketTime;
  638. DWORD numShift, dwCount, dwBucket, i, j;
  639. Trace0(TIMER1, "entering _ResyncTimerBuckets()");
  640. DebugCheckLowTimer(0);//deldel
  641. DEBUG_CHECK_LOW_INDEX(21);//deldel
  642. Trace0(TIMER1, "Printing Timer Queue before _ResyncTimerBuckets"); //deldel
  643. DebugPrintTimerQueue(); //deldel
  644. if (ptg->NumTimers == 0)
  645. return;
  646. //kslksl
  647. if (MyDebug&0x18) DebugScanTimerQueue(0x18);
  648. //
  649. // SyncTime should always be <= to currentTime
  650. //
  651. numShift = 0;
  652. while (numShift<NUM_TIMER_BUCKETS
  653. && (ptg->SyncTime+TIMER_BUCKET_GRANULARITY_ABS <= llCurTime)
  654. ) {
  655. if (!IsListEmpty(&ptg->TimesTable[numShift]))
  656. break;
  657. ptg->SyncTime += TIMER_BUCKET_GRANULARITY_ABS;
  658. numShift++;
  659. }
  660. if (numShift==0 || numShift==NUM_TIMER_BUCKETS)
  661. return;
  662. //
  663. // shift all buckets left, except for the last bucket and reinitialize the
  664. // list heads
  665. //
  666. for (i=0,j=numShift; i<NUM_TIMER_BUCKETS-1-numShift; i++,j++) {
  667. if (IsListEmpty(&ptg->TimesTable[j])) {
  668. ptg->TimesTable[j].Flink = ptg->TimesTable[j].Blink
  669. = &ptg->TimesTable[i];
  670. }
  671. else {
  672. ptg->TimesTable[j].Flink->Blink = &ptg->TimesTable[i];
  673. ptg->TimesTable[j].Blink->Flink = &ptg->TimesTable[i];
  674. }
  675. }
  676. MoveMemory( (PVOID)&(ptg->TimesTable[0]),
  677. (VOID *)&(ptg->TimesTable[numShift]),
  678. (sizeof(LIST_ENTRY) * (NUM_TIMER_BUCKETS-1-numShift))
  679. );
  680. for (dwCount=1; dwCount<=numShift; dwCount++)
  681. InitializeListHead(&ptg->TimesTable[NUM_TIMER_BUCKETS-1-dwCount]);
  682. //
  683. // go through the last bucket and redistribute it
  684. //
  685. lastBucketTime = ptg->SyncTime
  686. + (TIMER_BUCKET_GRANULARITY_ABS*(NUM_TIMER_BUCKETS-1));
  687. pHead = &ptg->TimesTable[NUM_TIMER_BUCKETS-1];
  688. for (ple=pHead->Flink; ple!=pHead; ) {
  689. pte = CONTAINING_RECORD(ple, IGMP_TIMER_ENTRY, Link);
  690. pleCur = ple;
  691. ple = ple->Flink;
  692. if (pte->Timeout<lastBucketTime) {
  693. RemoveEntryList(pleCur);
  694. MAP_TO_BUCKET(dwBucket, pte->Timeout);
  695. if (dwBucket==0) {
  696. InsertTimerInSortedList(pte, &ptg->TimesTable[0]);
  697. }
  698. else {
  699. InsertTailList(&ptg->TimesTable[dwBucket], pleCur);
  700. }
  701. }
  702. }
  703. DEBUG_CHECK_LOW_INDEX(22);//deldel
  704. //
  705. // sort the times in the first bucket
  706. //
  707. InitializeListHead(&le);
  708. InsertHeadList(&ptg->TimesTable[0], &le);
  709. RemoveEntryList(&ptg->TimesTable[0]);
  710. InitializeListHead(&ptg->TimesTable[0]);
  711. for (ple=le.Flink; ple!=&le; ) {
  712. pte = CONTAINING_RECORD(ple, IGMP_TIMER_ENTRY, Link);
  713. RemoveEntryList(ple);
  714. ple = ple->Flink;
  715. InsertTimerInSortedList(pte, &ptg->TimesTable[0]);
  716. }
  717. DEBUG_CHECK_LOW_INDEX(23);//deldel
  718. //
  719. // set the TableLowIndex
  720. //
  721. if (ptg->TableLowIndex>=NUM_TIMER_BUCKETS-1) {
  722. for (ptg->TableLowIndex=0; ptg->TableLowIndex<=NUM_TIMER_BUCKETS-1;
  723. ptg->TableLowIndex++)
  724. {
  725. if (IsListEmpty(&ptg->TimesTable[ptg->TableLowIndex]) )
  726. continue;
  727. else
  728. break;
  729. }
  730. DEBUG_CHECK_LOW_INDEX(24);//deldel
  731. }
  732. else {
  733. ptg->TableLowIndex -= numShift;
  734. DEBUG_CHECK_LOW_INDEX(25);//deldel
  735. }
  736. //#if DEBUG_TIMER_RESYNCTIMER deldel
  737. Trace0(TIMER1, "Printing Timer Queue after _ResyncTimerBuckets");
  738. DebugPrintTimerQueue();
  739. //#endif deldel
  740. //kslksl
  741. if (MyDebug&0x21) DebugScanTimerQueue(0x21);
  742. DebugCheckLowTimer(0);//deldel
  743. DEBUG_CHECK_LOW_INDEX(26);//deldel
  744. // debugdebug
  745. if (g_TimerStruct.TableLowIndex>=64 && g_TimerStruct.TableLowIndex!=~0) {
  746. DbgBreakPoint();
  747. g_TimerStruct.TableLowIndex = 0;
  748. SetNextTime(0);
  749. ResyncTimerBuckets(llCurTime);
  750. }
  751. Trace0(LEAVE1, "leaving _ResyncTimerBuckets()");
  752. return;
  753. } //end _ResyncTimerBuckets
  754. //------------------------------------------------------------------------------
  755. // _InitializeTimerGlobal
  756. //
  757. // create the timer CS and WaitTimer. registers a queue and timer with NtdllTimer.
  758. //
  759. // Called by: _StartProtocol()
  760. // Locks: no locks taken here.
  761. //------------------------------------------------------------------------------
  762. DWORD
  763. InitializeTimerGlobal (
  764. )
  765. {
  766. DWORD Error = NO_ERROR, i;
  767. PIGMP_TIMER_GLOBAL ptg = &g_TimerStruct;
  768. BOOL bErr;
  769. LONGLONG llCurTime = GetTickCount();
  770. Trace0(ENTER1, "Entering _InitializeTimerGlobal()");
  771. bErr = TRUE;
  772. BEGIN_BREAKOUT_BLOCK1 {
  773. // initialize igmp timer used to get tick count
  774. InitializeIgmpTime();
  775. //
  776. // initialize timer critical section
  777. //
  778. try {
  779. InitializeCriticalSection(&ptg->CS);
  780. }
  781. except (EXCEPTION_EXECUTE_HANDLER) {
  782. Error = GetExceptionCode();
  783. Trace1(
  784. ANY, "exception %d initializing global timer critical section",
  785. Error
  786. );
  787. Logerr0(INIT_CRITSEC_FAILED, Error);
  788. GOTO_END_BLOCK1;
  789. }
  790. #if DEBUG_FLAGS_SIGNATURE
  791. ptg->CSFlag = 0; //deldel
  792. #endif
  793. // create WaitTimer for igmp
  794. ptg->WTTimer = CreateTimerQueue();
  795. if ( ! ptg->WTTimer) {
  796. Error = GetLastError();
  797. Trace1(ERR, "CreateTimerQueue() failed:%d", Error);
  798. IgmpAssertOnError(FALSE);
  799. GOTO_END_BLOCK1;
  800. }
  801. //
  802. // create a periodic timer which does not get deletd
  803. //
  804. if (! CreateTimerQueueTimer(
  805. &ptg->WTTimer1,
  806. ptg->WTTimer, WT_ProcessTimerEvent,
  807. NULL, //context
  808. 1000000,
  809. 1000000,
  810. 0
  811. ))
  812. {
  813. Error = GetLastError();
  814. Trace1(ERR, "CreateTimerQueue() failed:%d", Error);
  815. IgmpAssertOnError(FALSE);
  816. GOTO_END_BLOCK1;
  817. }
  818. // set initial timeout to infinite, and SyncTime to the current time
  819. SET_TIMER_INFINITE(ptg->WTTimeout);
  820. ptg->SyncTime = llCurTime;
  821. ptg->CurrentTime.QuadPart = llCurTime;
  822. ptg->NumTimers = 0;
  823. // initialize the timer buckets
  824. for (i=0; i<NUM_TIMER_BUCKETS; i++) {
  825. InitializeListHead(&ptg->TimesTable[i]);
  826. }
  827. // set the TableLowIndex
  828. ptg->TableLowIndex = (DWORD)~0;
  829. // set the status of the global timer
  830. ptg->Status = TIMER_STATUS_CREATED;
  831. bErr = FALSE;
  832. } END_BREAKOUT_BLOCK1;
  833. if (bErr) {
  834. DeInitializeTimerGlobal();
  835. Trace0(LEAVE1, "Leaving. Could not _InitializeTimerGlobal():");
  836. return ERROR_CAN_NOT_COMPLETE;
  837. }
  838. else {
  839. Trace0(LEAVE1, "Leaving _InitializeTimerGlobal()");
  840. return NO_ERROR;
  841. }
  842. } //end _InitializeTimerGlobal
  843. //------------------------------------------------------------------------------
  844. // _DeInitializeTimerGlobal
  845. //
  846. // deinitializes the timer CS, and deletes the timer queue with Rtl
  847. //------------------------------------------------------------------------------
  848. VOID
  849. DeInitializeTimerGlobal (
  850. )
  851. {
  852. DeleteCriticalSection(&g_TimerStruct.CS);
  853. DeleteTimerQueueEx(g_TimerStruct.WTTimer, NULL);
  854. return;
  855. } //end _DeInitializeTimerGlobal
  856. //------------------------------------------------------------------------------
  857. // _DebugPrintTimerEntry
  858. //
  859. // Assumes DEBUG_TIMER_TIMERID is true
  860. //------------------------------------------------------------------------------
  861. VOID
  862. DebugPrintTimerEntry (
  863. PIGMP_TIMER_ENTRY pte,
  864. DWORD dwBucket,
  865. LONGLONG llCurTime
  866. )
  867. {
  868. DWORD dwDiffTime;
  869. CHAR str1[20], str2[20];
  870. #if DEBUG_TIMER_TIMERID
  871. CHECK_TIMER_SIGNATURE(pte);
  872. //deldel
  873. //if (pte->Id==920)
  874. // return;
  875. if (dwBucket==(DWORD)~0) {
  876. MAP_TO_BUCKET(dwBucket, pte->Timeout);
  877. }
  878. GetTimerDebugInfo(str1, str2, &dwDiffTime, pte, llCurTime);
  879. if (pte->Timeout - llCurTime > 0) {
  880. Trace8(TIMER, "---- <%2d><%d><%d> Timeout:%lu <%s> <%s> Status:%d %x",
  881. dwBucket, pte->Id, pte->Id2, dwDiffTime, str1, str2,
  882. pte->Status, pte->Context);
  883. }
  884. else {
  885. Trace8(TIMER, "---- <%d><%d><%d> Timeout:--%lu <%s> <%s> Status:%d %x %x",
  886. dwBucket, pte->Id, pte->Id2, dwDiffTime, str1, str2,
  887. pte->Status, pte->Context);
  888. }
  889. #endif //#if DEBUG_TIMER_TIMERID
  890. return;
  891. }
  892. //------------------------------------------------------------------------------
  893. // _GetTimerDebugInfo
  894. //
  895. // returns info regarding what type of timer it is
  896. //------------------------------------------------------------------------------
  897. VOID
  898. GetTimerDebugInfo(
  899. CHAR str1[20],
  900. CHAR str2[20],
  901. DWORD *pdwDiffTime,
  902. PIGMP_TIMER_ENTRY pte,
  903. LONGLONG llCurTime
  904. )
  905. {
  906. LONGLONG diffTime;
  907. #if DEBUG_TIMER_TIMERID
  908. diffTime = (pte->Timeout - llCurTime > 0)
  909. ? pte->Timeout - llCurTime
  910. : llCurTime - pte->Timeout;
  911. diffTime /= (LONGLONG)1000; //in seconds
  912. *pdwDiffTime = (DWORD)diffTime;
  913. strcpy(str2, " ");
  914. switch (pte->Id) {
  915. case 110:
  916. case 120: strcpy(str1, "iGenQuery "); break;
  917. case 210:
  918. case 220: strcpy(str1, "iOtherQry "); break;
  919. case 211: strcpy(str1, "iOtherQry* "); break;
  920. case 331:
  921. case 321: strcpy(str1, "gMemTimer* "); INET_COPY(str2, pte->Group); break;
  922. case 300:
  923. case 320:
  924. case 330:
  925. case 340: strcpy(str1, "gMemTimer "); INET_COPY(str2, pte->Group); break;
  926. case 400:
  927. case 410:
  928. case 420: strcpy(str1, "gGrpSpQry "); INET_COPY(str2, pte->Group); break;
  929. case 510:
  930. case 520: strcpy(str1, "gLstV1Rpt "); INET_COPY(str2, pte->Group); break;
  931. case 511: strcpy(str1, "gLstV1Rpt* "); INET_COPY(str2, pte->Group); break;
  932. case 550:
  933. case 560: strcpy(str1, "gLstV2Rpt "); INET_COPY(str2, pte->Group); break;
  934. case 610:
  935. case 620: strcpy(str1, "gGSrcExp "); INET_COPY(str2, pte->Group);
  936. lstrcat(str2, ":"); INET_CAT(str2, pte->Source); break;
  937. case 720:
  938. case 740: strcpy(str1, "iV1Router "); break;
  939. case 741: strcpy(str1, "iV1Router* "); break;
  940. case 920:
  941. case 910: strcpy(str1, "_MibTimer "); break;
  942. case 1001: strcpy(str1, "_gSrcQry "); INET_COPY(str2, pte->Group); break;
  943. default: strcpy(str1, "???? "); break;
  944. }
  945. #endif //DEBUG_TIMER_TIMERID
  946. return;
  947. }
  948. VOID
  949. DebugCheckTimerContexts(
  950. )
  951. {
  952. PIGMP_TIMER_GLOBAL ptg = &g_TimerStruct;
  953. PIGMP_TIMER_ENTRY pte;
  954. PLIST_ENTRY pHead, ple;
  955. DWORD i;
  956. ACQUIRE_TIMER_LOCK("_DebugPrintTimerQueue");
  957. //Trace0(ERR, "%d*************", Id);
  958. for (i=0; i<NUM_TIMER_BUCKETS; i++) {
  959. pHead = &ptg->TimesTable[i];
  960. if (IsListEmpty(pHead))
  961. continue;
  962. else {
  963. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  964. pte = CONTAINING_RECORD(ple, IGMP_TIMER_ENTRY, Link);
  965. if ( ((ULONG_PTR)pte->Context) & 0x3)
  966. DbgBreakPoint();
  967. }
  968. }
  969. }
  970. RELEASE_TIMER_LOCK("_DebugPrintTimerQueue");
  971. return;
  972. }
  973. DWORD g_igmp1, g_igmp2, g_igmp3;
  974. PLIST_ENTRY g_ple1, g_pHead;
  975. PIGMP_TIMER_ENTRY g_pte;
  976. //DebugCheck
  977. DWORD
  978. DebugScanTimerQueue(
  979. DWORD Id
  980. )
  981. {
  982. Trace1(TIMER1, "_TimerQueue:%d", Id);
  983. #if DEBUG_TIMER_TIMERID
  984. if ( (g_igmp3++ & 0x7) == 0x7) { //deldel
  985. //if ( 1){
  986. DebugPrintTimerQueue();
  987. return 0;
  988. }
  989. for (g_igmp1=0; g_igmp1<NUM_TIMER_BUCKETS; g_igmp1++) {
  990. g_pHead = &g_TimerStruct.TimesTable[g_igmp1];
  991. if (IsListEmpty(g_pHead))
  992. continue;
  993. else {
  994. for (g_ple1=g_pHead->Flink; g_ple1!=g_pHead; g_ple1=g_ple1->Flink) {
  995. g_pte = CONTAINING_RECORD(g_ple1, IGMP_TIMER_ENTRY, Link);
  996. CHECK_TIMER_SIGNATURE(g_pte);
  997. g_igmp2 = g_pte->Id;
  998. }
  999. }
  1000. }
  1001. return g_igmp1+g_igmp2;
  1002. #else
  1003. return 0;
  1004. #endif
  1005. }
  1006. //------------------------------------------------------------------------------
  1007. // _DebugPrintTimerQueue
  1008. // takes the timer lock
  1009. //------------------------------------------------------------------------------
  1010. VOID
  1011. APIENTRY
  1012. DebugPrintTimerQueue (
  1013. )
  1014. {
  1015. PIGMP_TIMER_GLOBAL ptg = &g_TimerStruct;
  1016. PIGMP_TIMER_ENTRY pte;
  1017. PLIST_ENTRY pHead, ple;
  1018. LONGLONG llCurTime = GetCurrentIgmpTime();
  1019. DWORD Error=NO_ERROR, i, count;
  1020. //kslksl
  1021. /*if (g_Info.CurrentGroupMemberships > 240)
  1022. return;
  1023. */
  1024. #if DEBUG_TIMER_TIMERID
  1025. ENTER_CRITICAL_SECTION(&g_CS, "g_CS", "_DebugPrintTimerQueue");
  1026. if (g_RunningStatus != IGMP_STATUS_RUNNING) {
  1027. Error = ERROR_CAN_NOT_COMPLETE;
  1028. }
  1029. else {
  1030. ++g_ActivityCount;
  1031. }
  1032. LEAVE_CRITICAL_SECTION(&g_CS, "g_CS", "_DebugPrintTimerQueue");
  1033. if (Error!=NO_ERROR)
  1034. return;
  1035. if (!EnterIgmpWorker()) {return;}
  1036. ACQUIRE_TIMER_LOCK("_DebugPrintTimerQueue");
  1037. if (g_TimerStruct.NumTimers==0) {
  1038. Trace0(TIMER, "No timers present in the timer queue");
  1039. }
  1040. else {
  1041. Trace0(TIMER, "---------------------LOCAL-TIMER-QUEUE-------------------------");
  1042. Trace6(TIMER, "-- LastFire:%d FireAfter:%d WTTimeout<%d:%lu> SyncTime<%d:%lu>",
  1043. g_Fire, (DWORD)(ptg->WTTimeout - llCurTime),
  1044. TIMER_HIGH(ptg->WTTimeout), TIMER_LOW(ptg->WTTimeout),
  1045. TIMER_HIGH(ptg->SyncTime), TIMER_LOW(ptg->SyncTime) );
  1046. Trace3(TIMER, "-- NumTimers:<%d> TableLowIndex:<%lu> Status:<%d>",
  1047. ptg->NumTimers, ptg->TableLowIndex, ptg->Status);
  1048. Trace0(TIMER, "---------------------------------------------------------------");
  1049. count =0;
  1050. for (i=0; i<NUM_TIMER_BUCKETS; i++) {
  1051. pHead = &ptg->TimesTable[i];
  1052. if (IsListEmpty(pHead))
  1053. continue;
  1054. else {
  1055. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  1056. pte = CONTAINING_RECORD(ple, IGMP_TIMER_ENTRY, Link);
  1057. DebugPrintTimerEntry(pte, i, llCurTime);
  1058. count ++;
  1059. }
  1060. }
  1061. }
  1062. Trace0(TIMER,
  1063. "---------------------------------------------------------------\n\n");
  1064. }
  1065. RELEASE_TIMER_LOCK("_DebugPrintTimerQueue");
  1066. LeaveIgmpWorker();
  1067. #endif //DEBUG_TIMER_TIMERID
  1068. return;
  1069. }