1
0

timer.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. timer.c
  9. Abstract:
  10. This module implements support for software timers in the kernel.
  11. Author:
  12. Evan Green 2-Feb-2013
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/kernel.h>
  20. #include "kep.h"
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // Define the internal timer flags.
  26. //
  27. #define KTIMER_FLAG_INTERNAL_QUEUED 0x80000000
  28. //
  29. // Define the mask of internal flags.
  30. //
  31. #define KTIMER_FLAG_INTERNAL_MASK (KTIMER_FLAG_INTERNAL_QUEUED)
  32. //
  33. // Define the threshold above which the microsecond to time tick calculation is
  34. // done the low-precision way to avoid potential rollover. At 10 seconds, the
  35. // time counter would have to run at 115 GHz.
  36. //
  37. #define TIME_COUNTER_MICROSECOND_CUTOFF (10 * MICROSECONDS_PER_SECOND)
  38. //
  39. // ------------------------------------------------------ Data Type Definitions
  40. //
  41. typedef enum _KTIMER_CRASH_REASON {
  42. KTimerCrashInvalid,
  43. KTimerCrashDoubleQueue,
  44. KTimerCrashUnqueuedTimerFoundInQueue,
  45. KTimerCrashCorrupt,
  46. KTimerCrashQueuingTimerFromTimerDpc,
  47. } KTIMER_CRASH_REASON, *PKTIMER_CRASH_REASON;
  48. /*++
  49. Structure Description:
  50. This structure defines a kernel software timer.
  51. Members:
  52. Header - Stores the object header.
  53. TreeNode - Stores the information about this timer's entry in the timer
  54. queue.
  55. DueTime - Stores the time counter expiration time, in ticks.
  56. Period - Stores the period of the timer if it is periodic, or 0 if it is a
  57. one-shot timer.
  58. QueueType - Stores the queue type of this timer.
  59. Dpc - Stores an optional pointer to a DPC to queue when this timer
  60. completes.
  61. Flags - Stores a bitfield of flags governing the operation and state of the
  62. timer. See KTIMER_FLAG_* definitions.
  63. Processor - Stores the processor number that the timer is queued on, if it
  64. is queued.
  65. --*/
  66. struct _KTIMER {
  67. OBJECT_HEADER Header;
  68. RED_BLACK_TREE_NODE TreeNode;
  69. ULONGLONG DueTime;
  70. ULONGLONG Period;
  71. TIMER_QUEUE_TYPE QueueType;
  72. PDPC Dpc;
  73. ULONG Flags;
  74. ULONG Processor;
  75. };
  76. /*++
  77. Structure Description:
  78. This structure defines a kernel software timer queue.
  79. Members:
  80. Tree - Stores the Red-Black tree structure that timers are stored in.
  81. NextTimer - Stores a pointer to the next timer that will expire, or NULL if
  82. the queue is empty.
  83. NextDueTime - Stores the due time of the next timer.
  84. QueuedTimerCount - Stores the number of times a timer has been added to
  85. this queue.
  86. ExpiredTimerCount - Stores the number of times a timer has come out of this
  87. queue because it expired.
  88. CancelledTimerCount - Stores the number of times a timer has come out of
  89. this queue because it was cancelled.
  90. --*/
  91. typedef struct _KTIMER_QUEUE {
  92. RED_BLACK_TREE Tree;
  93. PKTIMER NextTimer;
  94. ULONGLONG NextDueTime;
  95. UINTN QueuedTimerCount;
  96. UINTN ExpiredTimerCount;
  97. UINTN CancelledTimerCount;
  98. } KTIMER_QUEUE, *PKTIMER_QUEUE;
  99. /*++
  100. Structure Description:
  101. This structure defines the context for per-processor kernel software timer
  102. management.
  103. Members:
  104. Lock - Stores a spin lock protecting access to the queues.
  105. NextTimer - Stores the next timer to expire across all queues.
  106. NextDueTime - Stores the next due time across all timer queues.
  107. Queues - Stores the timer queues, except for the soft timer queue, which is
  108. global. Since the soft timer queue is not in this array, the array is
  109. indexed by the timer queue type minus one.
  110. --*/
  111. struct _KTIMER_DATA {
  112. KSPIN_LOCK Lock;
  113. PKTIMER NextTimer;
  114. ULONGLONG NextDueTime;
  115. PKTIMER NextWakingTimer;
  116. ULONGLONG NextWakeTime;
  117. KTIMER_QUEUE Queues[TimerQueueCount - 1];
  118. };
  119. //
  120. // ----------------------------------------------- Internal Function Prototypes
  121. //
  122. VOID
  123. KepInsertTimer (
  124. PPROCESSOR_BLOCK ProcessorBlock,
  125. PKTIMER_QUEUE Queue,
  126. PKTIMER Timer
  127. );
  128. VOID
  129. KepRemoveTimer (
  130. PPROCESSOR_BLOCK ProcessorBlock,
  131. PKTIMER_QUEUE Queue,
  132. PKTIMER Timer
  133. );
  134. COMPARISON_RESULT
  135. KepCompareTimerTreeNodes (
  136. PRED_BLACK_TREE Tree,
  137. PRED_BLACK_TREE_NODE FirstNode,
  138. PRED_BLACK_TREE_NODE SecondNode
  139. );
  140. //
  141. // -------------------------------------------------------------------- Globals
  142. //
  143. //
  144. // Store the global soft timer queue, which is serviced by whichever processor
  145. // gets there first.
  146. //
  147. KTIMER_QUEUE KeSoftTimerQueue;
  148. KSPIN_LOCK KeSoftTimerLock;
  149. POBJECT_HEADER KeTimerDirectory;
  150. //
  151. // ------------------------------------------------------------------ Functions
  152. //
  153. KERNEL_API
  154. PKTIMER
  155. KeCreateTimer (
  156. ULONG AllocationTag
  157. )
  158. /*++
  159. Routine Description:
  160. This routine creates a new timer object. Once created, this timer needs to
  161. be initialized before it can be queued. This routine must be called at or
  162. below dispatch level.
  163. Arguments:
  164. AllocationTag - Supplies a pointer to an identifier to use for the
  165. allocation that uniquely identifies the driver or module allocating the
  166. timer.
  167. Return Value:
  168. Returns a pointer to the timer on success.
  169. NULL on resource allocation failure.
  170. --*/
  171. {
  172. PKTIMER Timer;
  173. Timer = ObCreateObject(ObjectTimer,
  174. KeTimerDirectory,
  175. NULL,
  176. 0,
  177. sizeof(KTIMER),
  178. NULL,
  179. 0,
  180. AllocationTag);
  181. return Timer;
  182. }
  183. KERNEL_API
  184. VOID
  185. KeDestroyTimer (
  186. PKTIMER Timer
  187. )
  188. /*++
  189. Routine Description:
  190. This routine destroys a timer object. If the timer is currently queued, this
  191. routine cancels the timer and then destroys it. This routine must be called
  192. at or below dispatch level.
  193. Arguments:
  194. Timer - Supplies a pointer to the timer to destroy.
  195. Return Value:
  196. None.
  197. --*/
  198. {
  199. //
  200. // Check to see if the timer is queued. If it is, cancel it.
  201. //
  202. if ((Timer->Flags & KTIMER_FLAG_INTERNAL_QUEUED) != 0) {
  203. KeCancelTimer(Timer);
  204. }
  205. ObReleaseReference(Timer);
  206. return;
  207. }
  208. KERNEL_API
  209. KSTATUS
  210. KeQueueTimer (
  211. PKTIMER Timer,
  212. TIMER_QUEUE_TYPE QueueType,
  213. ULONGLONG DueTime,
  214. ULONGLONG Period,
  215. ULONG Flags,
  216. PDPC Dpc
  217. )
  218. /*++
  219. Routine Description:
  220. This routine configures and queues a timer object. The timer must not
  221. already be queued, otherwise the system will crash. This routine must be
  222. called at or below dispatch level.
  223. Arguments:
  224. Timer - Supplies a pointer to the timer to configure and queue.
  225. QueueType - Supplies the queue the timer should reside on. Valid values are:
  226. TimerQueueSoft - The timer will be expired at the first applicable
  227. clock interrupt, but a clock interrupt will not be scheduled solely
  228. for this timer. This timer type has the best power management
  229. profile, but may cause the expiration of the timer to be fairly
  230. late, as the system will not come out of idle to service this timer.
  231. The DPC for this timer may run on any processor.
  232. TimerQueueSoftWake - The timer will be expired at the first applicable
  233. clock interrupt. If the system was otherwise idle, a clock
  234. interrupt will be scheduled for this timer. This is a balanced
  235. choice for timers that can have some slack in their expiration, but
  236. need to run approximately when scheduled, even if the system is
  237. idle. The DPC will run on the processor where the timer was queued.
  238. TimerQueueHard - A clock interrupt will be scheduled for exactly the
  239. specified deadline. This is the best choice for high performance
  240. timers that need to expire as close to their deadlines as possible.
  241. It is the most taxing on power management, as it pulls the system
  242. out of idle, schedules an extra clock interrupt, and requires
  243. programming hardware. The DPC will run on the processor where the
  244. timer was queued.
  245. DueTime - Supplies the value of the time tick counter when this timer
  246. should expire (an absolute value in time counter ticks). If this value
  247. is 0, then an automatic due time of the current time plus the given
  248. period will be computed.
  249. Period - Supplies an optional period, in time counter ticks, for periodic
  250. timers. If this value is non-zero, the period will be added to the
  251. original due time and the timer will be automatically rearmed.
  252. Flags - Supplies an optional bitfield of flags. See KTIMER_FLAG_*
  253. definitions.
  254. Dpc - Supplies an optional pointer to a DPC that will be queued when this
  255. timer expires.
  256. Return Value:
  257. Status code.
  258. --*/
  259. {
  260. PKSPIN_LOCK Lock;
  261. RUNLEVEL OldRunLevel;
  262. PPROCESSOR_BLOCK ProcessorBlock;
  263. PKTIMER_QUEUE Queue;
  264. PKTIMER_DATA TimerData;
  265. ASSERT(KeGetRunLevel() <= RunLevelDispatch);
  266. if (DueTime == 0) {
  267. DueTime = HlQueryTimeCounter() + Period;
  268. }
  269. if (QueueType >= TimerQueueCount) {
  270. return STATUS_INVALID_PARAMETER;
  271. }
  272. //
  273. // Raise to dispatch and acquire the lock.
  274. //
  275. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  276. ProcessorBlock = KeGetCurrentProcessorBlock();
  277. //
  278. // Because the DPCs get run directly with the timer lock held, it is
  279. // illegal to queue a timer from its DPC. This doesn't catch all cases,
  280. // but its a start.
  281. //
  282. if ((Dpc != NULL) && (Dpc == ProcessorBlock->DpcInProgress)) {
  283. KeCrashSystem(CRASH_KTIMER_FAILURE,
  284. KTimerCrashQueuingTimerFromTimerDpc,
  285. (UINTN)Timer,
  286. (UINTN)ProcessorBlock,
  287. (UINTN)Dpc);
  288. }
  289. TimerData = ProcessorBlock->TimerData;
  290. if (QueueType == TimerQueueSoft) {
  291. Timer->Processor = -1;
  292. Lock = &KeSoftTimerLock;
  293. Queue = &KeSoftTimerQueue;
  294. } else {
  295. Timer->Processor = ProcessorBlock->ProcessorNumber;
  296. Lock = &(TimerData->Lock);
  297. Queue = &(TimerData->Queues[QueueType - 1]);
  298. }
  299. KeAcquireSpinLock(Lock);
  300. //
  301. // Crash the system if the timer is already queued.
  302. //
  303. if ((Timer->Flags & KTIMER_FLAG_INTERNAL_QUEUED) != 0) {
  304. KeCrashSystem(CRASH_KTIMER_FAILURE,
  305. KTimerCrashDoubleQueue,
  306. (UINTN)Timer,
  307. 0,
  308. 0);
  309. }
  310. ObSignalObject(Timer, SignalOptionUnsignal);
  311. Timer->QueueType = QueueType;
  312. Timer->DueTime = DueTime;
  313. Timer->Period = Period;
  314. Timer->Flags &= ~KTIMER_FLAG_PUBLIC_MASK;
  315. Timer->Flags |= Flags & KTIMER_FLAG_PUBLIC_MASK;
  316. Timer->Dpc = Dpc;
  317. KepInsertTimer(ProcessorBlock, Queue, Timer);
  318. //
  319. // Release the lock and return to the old run level.
  320. //
  321. KeReleaseSpinLock(Lock);
  322. KeLowerRunLevel(OldRunLevel);
  323. return STATUS_SUCCESS;
  324. }
  325. KERNEL_API
  326. KSTATUS
  327. KeCancelTimer (
  328. PKTIMER Timer
  329. )
  330. /*++
  331. Routine Description:
  332. This routine attempts to cancel a queued timer. This routine must be called
  333. at or below dispatch level. This routine will ensure that the DPC
  334. associated with the timer will have either been fully queued or not queued
  335. by the time this function returns, even if the timer was too late to
  336. cancel.
  337. Arguments:
  338. Timer - Supplies a pointer to the timer to cancel.
  339. Return Value:
  340. STATUS_SUCCESS if the timer was successfully cancelled.
  341. STATUS_TOO_LATE if the timer expired before the timer queue could be
  342. accessed.
  343. --*/
  344. {
  345. PKSPIN_LOCK Lock;
  346. RUNLEVEL OldRunLevel;
  347. PPROCESSOR_BLOCK ProcessorBlock;
  348. ULONG ProcessorCount;
  349. ULONG ProcessorNumber;
  350. PKTIMER_QUEUE Queue;
  351. KSTATUS Status;
  352. PKTIMER_DATA TimerData;
  353. ASSERT(KeGetRunLevel() <= RunLevelDispatch);
  354. ProcessorCount = KeGetActiveProcessorCount();
  355. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  356. if (Timer->QueueType == TimerQueueSoft) {
  357. ProcessorBlock = KeGetCurrentProcessorBlock();
  358. ProcessorNumber = -1;
  359. Queue = &KeSoftTimerQueue;
  360. Lock = &KeSoftTimerLock;
  361. KeAcquireSpinLock(Lock);
  362. } else {
  363. //
  364. // Loop chasing the timer around the processor it's on.
  365. //
  366. while (TRUE) {
  367. ProcessorNumber = Timer->Processor;
  368. if (ProcessorNumber >= ProcessorCount) {
  369. KeCrashSystem(CRASH_KTIMER_FAILURE,
  370. KTimerCrashCorrupt,
  371. (UINTN)Timer,
  372. 0,
  373. 0);
  374. }
  375. ProcessorBlock = KeProcessorBlocks[Timer->Processor];
  376. TimerData = ProcessorBlock->TimerData;
  377. Lock = &(TimerData->Lock);
  378. KeAcquireSpinLock(Lock);
  379. if (Timer->Processor == ProcessorNumber) {
  380. break;
  381. }
  382. KeReleaseSpinLock(Lock);
  383. }
  384. Queue = &(TimerData->Queues[Timer->QueueType - 1]);
  385. }
  386. //
  387. // In all cases, unsignal the timer.
  388. //
  389. ObSignalObject(Timer, SignalOptionUnsignal);
  390. //
  391. // Check the flag, and fail if the timer is no longer queued. The fact that
  392. // the lock is held also means it's not in the process of queuing the DPC;
  393. // either the DPC is queued or it isn't going to be.
  394. //
  395. if ((Timer->Flags & KTIMER_FLAG_INTERNAL_QUEUED) == 0) {
  396. Status = STATUS_TOO_LATE;
  397. goto CancelTimerEnd;
  398. }
  399. ASSERT(Timer->Processor == ProcessorNumber);
  400. //
  401. // Remove the timer from the queue and return successfully.
  402. //
  403. KepRemoveTimer(ProcessorBlock, Queue, Timer);
  404. Queue->CancelledTimerCount += 1;
  405. Status = STATUS_SUCCESS;
  406. CancelTimerEnd:
  407. KeReleaseSpinLock(Lock);
  408. KeLowerRunLevel(OldRunLevel);
  409. return Status;
  410. }
  411. KERNEL_API
  412. VOID
  413. KeSignalTimer (
  414. PKTIMER Timer,
  415. SIGNAL_OPTION Option
  416. )
  417. /*++
  418. Routine Description:
  419. This routine sets a timer to the given signal state.
  420. Arguments:
  421. Timer - Supplies a pointer to the timer to signal or unsignal.
  422. Option - Supplies the signaling behavior to apply.
  423. Return Value:
  424. None.
  425. --*/
  426. {
  427. ObSignalObject(Timer, Option);
  428. return;
  429. }
  430. KERNEL_API
  431. SIGNAL_STATE
  432. KeGetTimerState (
  433. PKTIMER Timer
  434. )
  435. /*++
  436. Routine Description:
  437. This routine returns the signal state of a timer.
  438. Arguments:
  439. Timer - Supplies a pointer to the timer to get the state of.
  440. Return Value:
  441. Returns the signal state of the timer.
  442. --*/
  443. {
  444. return Timer->Header.WaitQueue.State;
  445. }
  446. KERNEL_API
  447. ULONGLONG
  448. KeGetTimerDueTime (
  449. PKTIMER Timer
  450. )
  451. /*++
  452. Routine Description:
  453. This routine returns the next due time of the given timer. This could be in
  454. the past. This routine must be called at or below dispatch level.
  455. Arguments:
  456. Timer - Supplies a pointer to the timer to query.
  457. Return Value:
  458. Returns the due time of the timer.
  459. 0 if the timer is not currently queued.
  460. --*/
  461. {
  462. ULONGLONG DueTime;
  463. PKSPIN_LOCK Lock;
  464. RUNLEVEL OldRunLevel;
  465. PPROCESSOR_BLOCK ProcessorBlock;
  466. ULONG ProcessorCount;
  467. ULONG ProcessorNumber;
  468. PKTIMER_DATA TimerData;
  469. if ((Timer->Flags & KTIMER_FLAG_INTERNAL_QUEUED) == 0) {
  470. return 0;
  471. }
  472. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  473. if (Timer->QueueType == TimerQueueSoft) {
  474. Lock = &KeSoftTimerLock;
  475. KeAcquireSpinLock(Lock);
  476. } else {
  477. //
  478. // Loop chasing the timer around the processor it's on.
  479. //
  480. ProcessorCount = KeGetActiveProcessorCount();
  481. while (TRUE) {
  482. ProcessorNumber = Timer->Processor;
  483. if (ProcessorNumber >= ProcessorCount) {
  484. KeCrashSystem(CRASH_KTIMER_FAILURE,
  485. KTimerCrashCorrupt,
  486. (UINTN)Timer,
  487. 0,
  488. 0);
  489. }
  490. ProcessorBlock = KeProcessorBlocks[Timer->Processor];
  491. TimerData = ProcessorBlock->TimerData;
  492. Lock = &(TimerData->Lock);
  493. KeAcquireSpinLock(Lock);
  494. if (Timer->Processor == ProcessorNumber) {
  495. break;
  496. }
  497. KeReleaseSpinLock(Lock);
  498. }
  499. }
  500. //
  501. // Recheck the flag now that the queue is locked.
  502. //
  503. if ((Timer->Flags & KTIMER_FLAG_INTERNAL_QUEUED) == 0) {
  504. DueTime = 0;
  505. goto TimerGetRemainingTimerEnd;
  506. }
  507. DueTime = Timer->DueTime;
  508. TimerGetRemainingTimerEnd:
  509. KeReleaseSpinLock(Lock);
  510. KeLowerRunLevel(OldRunLevel);
  511. return DueTime;
  512. }
  513. KERNEL_API
  514. ULONGLONG
  515. KeConvertMicrosecondsToTimeTicks (
  516. ULONGLONG Microseconds
  517. )
  518. /*++
  519. Routine Description:
  520. This routine converts the given number of microseconds into time counter
  521. ticks.
  522. Arguments:
  523. Microseconds - Supplies the microsecond count.
  524. Return Value:
  525. Returns the number of time ticks that correspond to the given number of
  526. microseconds.
  527. --*/
  528. {
  529. ULONGLONG CounterFrequency;
  530. ULONGLONG Result;
  531. CounterFrequency = HlQueryTimeCounterFrequency();
  532. //
  533. // If the value is above a certain threshold, do the division first to
  534. // avoid potential rollovers.
  535. //
  536. if (Microseconds > TIME_COUNTER_MICROSECOND_CUTOFF) {
  537. Result = (Microseconds / MICROSECONDS_PER_SECOND) * CounterFrequency;
  538. } else {
  539. Result = Microseconds * CounterFrequency / MICROSECONDS_PER_SECOND;
  540. }
  541. return Result;
  542. }
  543. PKTIMER_DATA
  544. KepCreateTimerData (
  545. VOID
  546. )
  547. /*++
  548. Routine Description:
  549. This routine is called upon system initialization to create a timer
  550. management context for a new processor.
  551. Arguments:
  552. None.
  553. Return Value:
  554. Returns a pointer to the timer data on success.
  555. NULL on resource allocation failure.
  556. --*/
  557. {
  558. PKTIMER_DATA Data;
  559. PKTIMER_QUEUE Queue;
  560. UINTN QueueIndex;
  561. //
  562. // Cheat a little and initialize the global soft timer queue if this is
  563. // processor 0.
  564. //
  565. if (KeGetCurrentProcessorNumber() == 0) {
  566. RtlRedBlackTreeInitialize(&(KeSoftTimerQueue.Tree),
  567. 0,
  568. KepCompareTimerTreeNodes);
  569. KeSoftTimerQueue.NextDueTime = -1ULL;
  570. KeInitializeSpinLock(&KeSoftTimerLock);
  571. KeTimerDirectory = ObCreateObject(ObjectDirectory,
  572. NULL,
  573. "Timer",
  574. sizeof("Timer"),
  575. sizeof(OBJECT_HEADER),
  576. NULL,
  577. OBJECT_FLAG_USE_NAME_DIRECTLY,
  578. KE_ALLOCATION_TAG);
  579. if (KeTimerDirectory == NULL) {
  580. return NULL;
  581. }
  582. }
  583. Data = MmAllocateNonPagedPool(sizeof(KTIMER_DATA), KE_ALLOCATION_TAG);
  584. if (Data == NULL) {
  585. return NULL;
  586. }
  587. RtlZeroMemory(Data, sizeof(KTIMER_DATA));
  588. KeInitializeSpinLock(&(Data->Lock));
  589. for (QueueIndex = TimerQueueSoftWake;
  590. QueueIndex < TimerQueueCount;
  591. QueueIndex += 1) {
  592. Queue = &(Data->Queues[QueueIndex - 1]);
  593. RtlRedBlackTreeInitialize(&(Queue->Tree), 0, KepCompareTimerTreeNodes);
  594. Queue->NextDueTime = -1ULL;
  595. }
  596. Data->NextDueTime = -1ULL;
  597. return Data;
  598. }
  599. VOID
  600. KepDestroyTimerData (
  601. PKTIMER_DATA Data
  602. )
  603. /*++
  604. Routine Description:
  605. This routine tears down a processor's timer management context.
  606. Arguments:
  607. Data - Supplies a pointer to the data to destroy.
  608. Return Value:
  609. None.
  610. --*/
  611. {
  612. MmFreeNonPagedPool(Data);
  613. return;
  614. }
  615. VOID
  616. KepDispatchTimers (
  617. ULONGLONG CurrentTime
  618. )
  619. /*++
  620. Routine Description:
  621. This routine is called at regular intervals to check for and expire timers
  622. whose time has come. This routine must only be called internally, and must
  623. be called at dispatch level.
  624. Arguments:
  625. Queue - Supplies a pointer to the timer queue for the current processor.
  626. CurrentTime - Supplies the current time counter value. Any timers with this
  627. due time or earlier will be expired.
  628. Return Value:
  629. None.
  630. --*/
  631. {
  632. ULONGLONG MissedCycles;
  633. PPROCESSOR_BLOCK ProcessorBlock;
  634. PKTIMER_QUEUE Queue;
  635. INTN QueueIndex;
  636. SIGNAL_OPTION SignalOption;
  637. PKTIMER Timer;
  638. PKTIMER_DATA TimerData;
  639. ASSERT(KeGetRunLevel() == RunLevelDispatch);
  640. ProcessorBlock = KeGetCurrentProcessorBlock();
  641. TimerData = ProcessorBlock->TimerData;
  642. //
  643. // If no timers are expired, just return. The soft timer queue read could
  644. // tear on 32-bit systems, but it doesn't matter. Even if the torn read
  645. // causes the condition to incorrectly become true (and return without
  646. // expiring), the soft timers will be expired on the next go-round.
  647. //
  648. if ((CurrentTime < TimerData->NextDueTime) &&
  649. (CurrentTime < KeSoftTimerQueue.NextDueTime)) {
  650. return;
  651. }
  652. KeAcquireSpinLock(&(TimerData->Lock));
  653. //
  654. // Iterate backwards so that hard timers, who care most about their
  655. // deadlines, run first.
  656. //
  657. for (QueueIndex = TimerQueueCount - 1; QueueIndex >= 0; QueueIndex -= 1) {
  658. //
  659. // The soft queue is global. Make an effort to grab the lock, but only
  660. // try once. Failure means another processor is already servicing those
  661. // timers (great, no work required here), or another processor is in
  662. // there queuing or cancelling. If that's the case, the soft timer
  663. // queue missed its chance this round, better luck next time.
  664. //
  665. if (QueueIndex == TimerQueueSoft) {
  666. Queue = &KeSoftTimerQueue;
  667. if ((CurrentTime < KeSoftTimerQueue.NextDueTime) ||
  668. (KeTryToAcquireSpinLock(&KeSoftTimerLock) == FALSE)) {
  669. continue;
  670. }
  671. } else {
  672. Queue = &(TimerData->Queues[QueueIndex - 1]);
  673. }
  674. while (CurrentTime >= Queue->NextDueTime) {
  675. Timer = Queue->NextTimer;
  676. KepRemoveTimer(ProcessorBlock, Queue, Timer);
  677. Queue->ExpiredTimerCount += 1;
  678. //
  679. // If the timer is periodic, adjust the due time and reinsert.
  680. // Make sure to adjust the due time to a point in the future.
  681. //
  682. if (Timer->Period != 0) {
  683. //
  684. // In the common case, the timer won't have missed any cycles,
  685. // and so the period can simply be added, avoiding a divide.
  686. //
  687. if (Timer->DueTime + Timer->Period > CurrentTime) {
  688. Timer->DueTime += Timer->Period;
  689. } else {
  690. MissedCycles = (CurrentTime - Timer->DueTime) /
  691. Timer->Period;
  692. Timer->DueTime += (MissedCycles + 1) * Timer->Period;
  693. }
  694. KepInsertTimer(ProcessorBlock, Queue, Timer);
  695. SignalOption = SignalOptionPulse;
  696. //
  697. // If the timer is one-shot, leave it removed, and signal
  698. // permanently.
  699. //
  700. } else {
  701. SignalOption = SignalOptionSignalAll;
  702. }
  703. //
  704. // Signal the timer, and if there's a DPC there, queue that up.
  705. //
  706. ObSignalObject(Timer, SignalOption);
  707. if (Timer->Dpc != NULL) {
  708. KeQueueDpc(Timer->Dpc);
  709. }
  710. }
  711. //
  712. // Release the global lock acquired if this is the soft queue.
  713. //
  714. if (QueueIndex == TimerQueueSoft) {
  715. KeReleaseSpinLock(&KeSoftTimerLock);
  716. }
  717. }
  718. KeReleaseSpinLock(&(TimerData->Lock));
  719. return;
  720. }
  721. ULONGLONG
  722. KepGetNextTimerDeadline (
  723. PPROCESSOR_BLOCK Processor,
  724. PBOOL Hard
  725. )
  726. /*++
  727. Routine Description:
  728. This routine returns the next waking deadline of timers on the given
  729. processor. This routine must be called at or above dispatch level.
  730. Arguments:
  731. Processor - Supplies a pointer to the processor.
  732. Hard - Supplies a pointer where a boolean will be returned indicating if
  733. this is a hard deadline or a soft deadline.
  734. Return Value:
  735. Returns the next waking timer deadline.
  736. -1 if there are no waking timers.
  737. --*/
  738. {
  739. ULONGLONG Deadline;
  740. ULONGLONG HardDeadline;
  741. ULONGLONG SoftDeadline;
  742. PKTIMER_DATA TimerData;
  743. TimerData = Processor->TimerData;
  744. SoftDeadline = TimerData->Queues[TimerQueueSoftWake - 1].NextDueTime;
  745. HardDeadline = TimerData->Queues[TimerQueueHard - 1].NextDueTime;
  746. if (SoftDeadline == -1ULL) {
  747. Deadline = HardDeadline;
  748. *Hard = TRUE;
  749. //
  750. // The soft-wake time needs to be far enough before the hard deadline such
  751. // that even if the soft-wake time slips a whole clock cycle, as it might,
  752. // the hard deadline won't be missed. If there's a chance the hard deadline
  753. // might be missed, just return the hard deadline.
  754. //
  755. } else if (SoftDeadline + KeClockRate <= HardDeadline) {
  756. *Hard = FALSE;
  757. Deadline = SoftDeadline;
  758. } else {
  759. *Hard = TRUE;
  760. Deadline = HardDeadline;
  761. }
  762. if ((Deadline == -1ULL) || (KeDisableDynamicTick != FALSE)) {
  763. *Hard = FALSE;
  764. }
  765. return Deadline;
  766. }
  767. //
  768. // --------------------------------------------------------- Internal Functions
  769. //
  770. VOID
  771. KepInsertTimer (
  772. PPROCESSOR_BLOCK ProcessorBlock,
  773. PKTIMER_QUEUE Queue,
  774. PKTIMER Timer
  775. )
  776. /*++
  777. Routine Description:
  778. This routine inserts a timer from into a timer queue. This routine assumes
  779. the timer data lock is already held.
  780. Arguments:
  781. ProcessorBlock - Supplies a pointer to the processor block to add the
  782. timer to.
  783. Queue - Supplies a pointer to the timer queue.
  784. Timer - Supplies a pointer to the timer.
  785. Return Value:
  786. None.
  787. --*/
  788. {
  789. PKTIMER_DATA TimerData;
  790. TimerData = ProcessorBlock->TimerData;
  791. //
  792. // Crash the system if the timer is already queued.
  793. //
  794. if ((Timer->Flags & KTIMER_FLAG_INTERNAL_QUEUED) != 0) {
  795. KeCrashSystem(CRASH_KTIMER_FAILURE,
  796. KTimerCrashDoubleQueue,
  797. (UINTN)Timer,
  798. 0,
  799. 0);
  800. }
  801. Timer->Flags |= KTIMER_FLAG_INTERNAL_QUEUED;
  802. if (Timer->QueueType == TimerQueueHard) {
  803. if (KeDisableDynamicTick == FALSE) {
  804. ProcessorBlock->Clock.AnyHard = TRUE;
  805. }
  806. }
  807. //
  808. // Add the timer to the tree.
  809. //
  810. Queue->QueuedTimerCount += 1;
  811. RtlRedBlackTreeInsert(&(Queue->Tree), &(Timer->TreeNode));
  812. //
  813. // Maintain the next pointer of the queue for quick queries.
  814. //
  815. if ((Queue->NextTimer == NULL) ||
  816. (Timer->DueTime < Queue->NextTimer->DueTime)) {
  817. Queue->NextTimer = Timer;
  818. Queue->NextDueTime = Timer->DueTime;
  819. if (Timer->QueueType != TimerQueueSoft) {
  820. //
  821. // Maintain the next timer globally.
  822. //
  823. if ((TimerData->NextTimer == NULL) ||
  824. (Timer->DueTime < TimerData->NextDueTime)) {
  825. TimerData->NextTimer = Timer;
  826. TimerData->NextDueTime = Timer->DueTime;
  827. }
  828. //
  829. // Tell the clock scheduler about all new winning hard and soft
  830. // wake timers. New soft wake timers need to poke the clock because
  831. // the clock might be off right now.
  832. //
  833. KepUpdateClockDeadline();
  834. }
  835. }
  836. return;
  837. }
  838. VOID
  839. KepRemoveTimer (
  840. PPROCESSOR_BLOCK ProcessorBlock,
  841. PKTIMER_QUEUE Queue,
  842. PKTIMER Timer
  843. )
  844. /*++
  845. Routine Description:
  846. This routine removes a timer from a timer queue. This routine assumes the
  847. timer data lock is already held.
  848. Arguments:
  849. ProcessorBlock - Supplies a pointer to the processor block the timer is on.
  850. Queue - Supplies a pointer to the timer queue.
  851. Timer - Supplies a pointer to the timer.
  852. Return Value:
  853. None.
  854. --*/
  855. {
  856. PRED_BLACK_TREE_NODE NextNode;
  857. PKTIMER NextTimer;
  858. PKTIMER_DATA TimerData;
  859. TimerData = ProcessorBlock->TimerData;
  860. if ((Timer->Flags & KTIMER_FLAG_INTERNAL_QUEUED) == 0) {
  861. KeCrashSystem(CRASH_KTIMER_FAILURE,
  862. KTimerCrashUnqueuedTimerFoundInQueue,
  863. (UINTN)Timer,
  864. (UINTN)TimerData,
  865. 0);
  866. }
  867. RtlRedBlackTreeRemove(&(Queue->Tree), &(Timer->TreeNode));
  868. Timer->Flags &= ~KTIMER_FLAG_INTERNAL_QUEUED;
  869. //
  870. // Maintain the next timer for the queue.
  871. //
  872. if (Timer == Queue->NextTimer) {
  873. NextNode = RtlRedBlackTreeGetNextNode(&(Queue->Tree),
  874. FALSE,
  875. &(Timer->TreeNode));
  876. if (NextNode != NULL) {
  877. NextTimer = RED_BLACK_TREE_VALUE(NextNode, KTIMER, TreeNode);
  878. Queue->NextDueTime = NextTimer->DueTime;
  879. //
  880. // Tell the clock scheduler about the next hard or soft-wake timer.
  881. // The soft-wake timer case is necessary if the clock is now off.
  882. //
  883. if (Timer->QueueType != TimerQueueSoft) {
  884. KepUpdateClockDeadline();
  885. }
  886. } else {
  887. NextTimer = NULL;
  888. Queue->NextDueTime = -1ULL;
  889. if (Timer->QueueType == TimerQueueHard) {
  890. ProcessorBlock->Clock.AnyHard = FALSE;
  891. }
  892. }
  893. Queue->NextTimer = NextTimer;
  894. //
  895. // If this was also the winner globally, find the next winner.
  896. //
  897. if (Timer == TimerData->NextTimer) {
  898. //
  899. // Soft timers are global and should never be listed as a specific
  900. // processor's next deadline.
  901. //
  902. ASSERT(Timer->QueueType != TimerQueueSoft);
  903. //
  904. // Figure out the next global timer.
  905. //
  906. Queue = &(TimerData->Queues[TimerQueueSoftWake - 1]);
  907. TimerData->NextTimer = Queue->NextTimer;
  908. TimerData->NextDueTime = Queue->NextDueTime;
  909. Queue = &(TimerData->Queues[TimerQueueHard - 1]);
  910. if ((TimerData->NextTimer == NULL) ||
  911. (Queue->NextDueTime < TimerData->NextDueTime)) {
  912. TimerData->NextTimer = Queue->NextTimer;
  913. TimerData->NextDueTime = Queue->NextDueTime;
  914. }
  915. }
  916. } else {
  917. //
  918. // A timer cannot be the winner globally but not the winner of its own
  919. // queue.
  920. //
  921. ASSERT((Timer->QueueType == TimerQueueSoft) ||
  922. (Timer != TimerData->NextTimer));
  923. }
  924. return;
  925. }
  926. COMPARISON_RESULT
  927. KepCompareTimerTreeNodes (
  928. PRED_BLACK_TREE Tree,
  929. PRED_BLACK_TREE_NODE FirstNode,
  930. PRED_BLACK_TREE_NODE SecondNode
  931. )
  932. /*++
  933. Routine Description:
  934. This routine compares two kernel timer Red-Black tree nodes.
  935. Arguments:
  936. Tree - Supplies a pointer to the tree being traversed.
  937. FirstNode - Supplies a pointer to the left side of the comparison.
  938. SecondNode - Supplies a pointer to the second side of the comparison.
  939. Return Value:
  940. Same if the two nodes have the same value.
  941. Ascending if the first node is less than the second node.
  942. Descending if the second node is less than the first node.
  943. --*/
  944. {
  945. PKTIMER FirstTimer;
  946. PKTIMER SecondTimer;
  947. FirstTimer = RED_BLACK_TREE_VALUE(FirstNode, KTIMER, TreeNode);
  948. SecondTimer = RED_BLACK_TREE_VALUE(SecondNode, KTIMER, TreeNode);
  949. if (FirstTimer->DueTime < SecondTimer->DueTime) {
  950. return ComparisonResultAscending;
  951. } else if (FirstTimer->DueTime > SecondTimer->DueTime) {
  952. return ComparisonResultDescending;
  953. }
  954. ASSERT(FirstTimer->DueTime == SecondTimer->DueTime);
  955. return ComparisonResultSame;
  956. }