BOOLEAN FASTCALL KiInsertTreeTimer(IN PKTIMER Timer, IN LARGE_INTEGER Interval) { BOOLEAN Inserted = FALSE; ULONG Hand = 0; PKSPIN_LOCK_QUEUE LockQueue; DPRINT("KiInsertTreeTimer(): Timer %p, Interval: %I64d\n", Timer, Interval.QuadPart); /* Setup the timer's due time */ if (KiComputeDueTime(Timer, Interval, &Hand)) { /* Acquire the lock */ LockQueue = KiAcquireTimerLock(Hand); /* Insert the timer */ if (KiInsertTimerTable(Timer, Hand)) { /* It was already there, remove it */ KiRemoveEntryTimer(Timer); Timer->Header.Inserted = FALSE; } else { /* Otherwise, we're now inserted */ Inserted = TRUE; } /* Release the lock */ KiReleaseTimerLock(LockQueue); } /* Release the lock and return insert status */ return Inserted; }
LOGICAL FASTCALL KiInsertTreeTimer ( IN PRKTIMER Timer, IN LARGE_INTEGER Interval ) /*++ Routine Description: This function inserts a timer object in the timer queue. N.B. This routine assumes that the dispatcher data lock has been acquired. Arguments: Timer - Supplies a pointer to a dispatcher object of type timer. Interval - Supplies the absolute or relative time at which the time is to expire. Return Value: If the timer is inserted in the timer tree, than a value of TRUE is returned. Otherwise, a value of FALSE is returned. --*/ { LARGE_INTEGER CurrentTime; LARGE_INTEGER SystemTime; LARGE_INTEGER TimeDifference; // // Clear the signal state of timer if the timer period is zero and set // the inserted state to TRUE. // Timer->Header.Inserted = TRUE; Timer->Header.Absolute = FALSE; if (Timer->Period == 0) { Timer->Header.SignalState = FALSE; } // // If the specified interval is not a relative time (i.e., is an absolute // time), then convert it to relative time. // if (Interval.HighPart >= 0) { KiQuerySystemTime(&SystemTime); TimeDifference.QuadPart = SystemTime.QuadPart - Interval.QuadPart; // // If the resultant relative time is greater than or equal to zero, // then the timer has already expired. // if (TimeDifference.HighPart >= 0) { Timer->Header.SignalState = TRUE; Timer->Header.Inserted = FALSE; return FALSE; } Interval = TimeDifference; Timer->Header.Absolute = TRUE; } // // Get the current interrupt time, insert the timer in the timer table, // and return the inserted state. // KiQueryInterruptTime(&CurrentTime); return KiInsertTimerTable(Interval, CurrentTime, Timer); }
LOGICAL FASTCALL KiReinsertTreeTimer ( IN PRKTIMER Timer, IN ULARGE_INTEGER DueTime ) /*++ Routine Description: This function reinserts a timer object in the timer queue. N.B. This routine assumes that the dispatcher data lock has been acquired. Arguments: Timer - Supplies a pointer to a dispatcher object of type timer. DueTime - Supplies the absolute time the timer is to expire. Return Value: If the timer is inserted in the timer tree, than a value of TRUE is returned. Otherwise, a value of FALSE is returned. --*/ { LARGE_INTEGER CurrentTime; LARGE_INTEGER Interval; // // Clear the signal state of timer if the timer period is zero and set // the inserted state to TRUE. // Timer->Header.Inserted = TRUE; if (Timer->Period == 0) { Timer->Header.SignalState = FALSE; } // // Compute the interval between the current time and the due time. // If the resultant relative time is greater than or equal to zero, // then the timer has already expired. // KiQueryInterruptTime(&CurrentTime); Interval.QuadPart = CurrentTime.QuadPart - DueTime.QuadPart; if (Interval.QuadPart >= 0) { Timer->Header.SignalState = TRUE; Timer->Header.Inserted = FALSE; return FALSE; } // // Insert the timer in the timer table and return the inserted state. // return KiInsertTimerTable(Interval, CurrentTime, Timer); }
VOID KeSetSystemTime ( IN PLARGE_INTEGER NewTime, OUT PLARGE_INTEGER OldTime, IN BOOLEAN AdjustInterruptTime, IN PLARGE_INTEGER HalTimeToSet OPTIONAL ) /*++ Routine Description: This function sets the system time to the specified value and updates timer queue entries to reflect the difference between the old system time and the new system time. Arguments: NewTime - Supplies a pointer to a variable that specifies the new system time. OldTime - Supplies a pointer to a variable that will receive the previous system time. AdjustInterruptTime - If TRUE the amount of time being adjusted is also applied to InterruptTime and TickCount. HalTimeToSet - Supplies an optional time that if specified is to be used to set the time in the realtime clock. Return Value: None. --*/ { LIST_ENTRY AbsoluteListHead; LIST_ENTRY ExpiredListHead; ULONG Hand; ULONG Index; PLIST_ENTRY ListHead; PKSPIN_LOCK_QUEUE LockQueue; PLIST_ENTRY NextEntry; KIRQL OldIrql1; KIRQL OldIrql2; LARGE_INTEGER TimeDelta; TIME_FIELDS TimeFields; PKTIMER Timer; ASSERT((NewTime->HighPart & 0xf0000000) == 0); ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); // // If a realtime clock value is specified, then convert the time value // to time fields. // if (ARGUMENT_PRESENT(HalTimeToSet)) { RtlTimeToTimeFields(HalTimeToSet, &TimeFields); } // // Set affinity to the processor that keeps the system time, raise IRQL // to dispatcher level and lock the dispatcher database, then raise IRQL // to HIGH_LEVEL to synchronize with the clock interrupt routine. // KeSetSystemAffinityThread((KAFFINITY)1); KiLockDispatcherDatabase(&OldIrql1); KeRaiseIrql(HIGH_LEVEL, &OldIrql2); // // Save the previous system time, set the new system time, and set // the realtime clock, if a time value is specified. // KiQuerySystemTime(OldTime); #if defined(_AMD64_) SharedUserData->SystemTime.High2Time = NewTime->HighPart; *((volatile ULONG64 *)&SharedUserData->SystemTime) = NewTime->QuadPart; #else SharedUserData->SystemTime.High2Time = NewTime->HighPart; SharedUserData->SystemTime.LowPart = NewTime->LowPart; SharedUserData->SystemTime.High1Time = NewTime->HighPart; #endif if (ARGUMENT_PRESENT(HalTimeToSet)) { ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields); } // // Compute the difference between the previous system time and the new // system time. // TimeDelta.QuadPart = NewTime->QuadPart - OldTime->QuadPart; // // Update the boot time to reflect the delta. This keeps time based // on boot time constant // KeBootTime.QuadPart = KeBootTime.QuadPart + TimeDelta.QuadPart; // // Track the overall bias applied to the boot time. // KeBootTimeBias = KeBootTimeBias + TimeDelta.QuadPart; // // Lower IRQL to dispatch level and if needed adjust the physical // system interrupt time. // KeLowerIrql(OldIrql2); if (AdjustInterruptTime != FALSE) { AdjustInterruptTime = KeAdjustInterruptTime(TimeDelta.QuadPart); } // // If the physical interrupt time of the system was not adjusted, then // recompute any absolute timers in the system for the new system time. // if (AdjustInterruptTime == FALSE) { // // Acquire the timer table lock, remove all absolute timers from the // timer queue so their due time can be recomputed, and release the // timer table lock. // InitializeListHead(&AbsoluteListHead); for (Index = 0; Index < TIMER_TABLE_SIZE; Index += 1) { ListHead = &KiTimerTableListHead[Index].Entry; LockQueue = KiAcquireTimerTableLock(Index); NextEntry = ListHead->Flink; while (NextEntry != ListHead) { Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); NextEntry = NextEntry->Flink; if (Timer->Header.Absolute != FALSE) { KiRemoveEntryTimer(Timer); InsertTailList(&AbsoluteListHead, &Timer->TimerListEntry); } } KiReleaseTimerTableLock(LockQueue); } // // Recompute the due time and reinsert all absolute timers in the timer // tree. If a timer has already expired, then insert the timer in the // expired timer list. // InitializeListHead(&ExpiredListHead); while (AbsoluteListHead.Flink != &AbsoluteListHead) { Timer = CONTAINING_RECORD(AbsoluteListHead.Flink, KTIMER, TimerListEntry); RemoveEntryList(&Timer->TimerListEntry); Timer->DueTime.QuadPart -= TimeDelta.QuadPart; Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart); Timer->Header.Hand = (UCHAR)Hand; LockQueue = KiAcquireTimerTableLock(Hand); if (KiInsertTimerTable(Timer, Hand) == TRUE) { KiRemoveEntryTimer(Timer); InsertTailList(&ExpiredListHead, &Timer->TimerListEntry); } KiReleaseTimerTableLock(LockQueue); } // // If any of the attempts to reinsert a timer failed, then timers have // already expired and must be processed. // // N.B. The following function returns with the dispatcher database // unlocked. // KiTimerListExpire(&ExpiredListHead, OldIrql1); } else { KiUnlockDispatcherDatabase(OldIrql1); } // // Set affinity back to its original value. // KeRevertToUserAffinityThread(); return; }
VOID NTAPI KeSetSystemTime(IN PLARGE_INTEGER NewTime, OUT PLARGE_INTEGER OldTime, IN BOOLEAN FixInterruptTime, IN PLARGE_INTEGER HalTime OPTIONAL) { TIME_FIELDS TimeFields; KIRQL OldIrql, OldIrql2; LARGE_INTEGER DeltaTime; PLIST_ENTRY ListHead, NextEntry; PKTIMER Timer; PKSPIN_LOCK_QUEUE LockQueue; LIST_ENTRY TempList, TempList2; ULONG Hand, i; /* Sanity checks */ ASSERT((NewTime->HighPart & 0xF0000000) == 0); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); /* Check if this is for the HAL */ if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields); /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */ KeSetSystemAffinityThread(1); OldIrql = KiAcquireDispatcherLock(); KeRaiseIrql(HIGH_LEVEL, &OldIrql2); /* Query the system time now */ KeQuerySystemTime(OldTime); /* Set the new system time (ordering of these operations is critical) */ SharedUserData->SystemTime.High2Time = NewTime->HighPart; SharedUserData->SystemTime.LowPart = NewTime->LowPart; SharedUserData->SystemTime.High1Time = NewTime->HighPart; /* Check if this was for the HAL and set the RTC time */ if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields); /* Calculate the difference between the new and the old time */ DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart; /* Update system boot time */ KeBootTime.QuadPart += DeltaTime.QuadPart; KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart; /* Lower IRQL back */ KeLowerIrql(OldIrql2); /* Check if we need to adjust interrupt time */ if (FixInterruptTime) ASSERT(FALSE); /* Setup a temporary list of absolute timers */ InitializeListHead(&TempList); /* Loop current timers */ for (i = 0; i < TIMER_TABLE_SIZE; i++) { /* Loop the entries in this table and lock the timers */ ListHead = &KiTimerTableListHead[i].Entry; LockQueue = KiAcquireTimerLock(i); NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the timer */ Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); NextEntry = NextEntry->Flink; /* Is it absolute? */ if (Timer->Header.Absolute) { /* Remove it from the timer list */ KiRemoveEntryTimer(Timer); /* Insert it into our temporary list */ InsertTailList(&TempList, &Timer->TimerListEntry); } } /* Release the lock */ KiReleaseTimerLock(LockQueue); } /* Setup a temporary list of expired timers */ InitializeListHead(&TempList2); /* Loop absolute timers */ while (TempList.Flink != &TempList) { /* Get the timer */ Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry); RemoveEntryList(&Timer->TimerListEntry); /* Update the due time and handle */ Timer->DueTime.QuadPart -= DeltaTime.QuadPart; Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart); Timer->Header.Hand = (UCHAR)Hand; /* Lock the timer and re-insert it */ LockQueue = KiAcquireTimerLock(Hand); if (KiInsertTimerTable(Timer, Hand)) { /* Remove it from the timer list */ KiRemoveEntryTimer(Timer); /* Insert it into our temporary list */ InsertTailList(&TempList2, &Timer->TimerListEntry); } /* Release the lock */ KiReleaseTimerLock(LockQueue); } /* Process expired timers. This releases the dispatcher lock. */ KiTimerListExpire(&TempList2, OldIrql); /* Revert affinity */ KeRevertToUserAffinityThread(); }