Add lock to kernel timer functions

This commit is contained in:
ergo720 2019-01-08 11:03:47 +01:00
parent bd0eced253
commit 4f86a5a26f
2 changed files with 43 additions and 5 deletions

View File

@ -105,11 +105,16 @@ VOID xboxkrnl::KiClockIsr(unsigned int ScalingFactor)
// Update the tick counter
KeTickCount += ScalingFactor;
// Check if a timer has expired
Hand = KeTickCount & (TIMER_TABLE_SIZE - 1);
if (KiTimerTableListHead[Hand].Entry.Flink != &KiTimerTableListHead[Hand].Entry &&
InterruptTime.QuadPart >= KiTimerTableListHead[Hand].Time.QuadPart) {
KeInsertQueueDpc(&KiTimerExpireDpc, (PVOID)&KeTickCount, 0);
// Because this function must be fast to continuously update the kernel clocks, if somebody else is currently
// holding the lock, we won't wait and instead skip the check of the timers for this cycle
if (TimerMtx.try_lock()) {
// Check if a timer has expired
Hand = KeTickCount & (TIMER_TABLE_SIZE - 1);
if (KiTimerTableListHead[Hand].Entry.Flink != &KiTimerTableListHead[Hand].Entry &&
InterruptTime.QuadPart >= KiTimerTableListHead[Hand].Time.QuadPart) {
KeInsertQueueDpc(&KiTimerExpireDpc, (PVOID)&KeTickCount, 0);
}
TimerMtx.unlock();
}
KfLowerIrql(OldIrql);
@ -120,12 +125,15 @@ VOID xboxkrnl::KxInsertTimer(
IN xboxkrnl::ULONG Hand
)
{
TimerMtx.lock();
/* Try to insert the timer */
if (KiInsertTimerTable(Timer, Hand))
{
/* Complete it */
KiCompleteTimer(Timer, Hand);
}
TimerMtx.unlock();
}
VOID FASTCALL xboxkrnl::KiCompleteTimer(
@ -136,6 +144,8 @@ VOID FASTCALL xboxkrnl::KiCompleteTimer(
LIST_ENTRY ListHead;
BOOLEAN RequestInterrupt = FALSE;
TimerMtx.lock();
/* Remove it from the timer list */
KiRemoveEntryTimer(Timer, Hand);
@ -154,6 +164,7 @@ VOID FASTCALL xboxkrnl::KiCompleteTimer(
if (RequestInterrupt) {
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
TimerMtx.unlock();
}
VOID xboxkrnl::KiRemoveEntryTimer(
@ -164,6 +175,8 @@ VOID xboxkrnl::KiRemoveEntryTimer(
ULONG Hand;
PKTIMER_TABLE_ENTRY TableEntry;
TimerMtx.lock();
/* Remove the timer from the timer list and check if it's empty */
if (RemoveEntryList(&Timer->TimerListEntry))
{
@ -179,6 +192,7 @@ VOID xboxkrnl::KiRemoveEntryTimer(
/* Clear the list entries so we can tell the timer is gone */
Timer->TimerListEntry.Flink = NULL;
Timer->TimerListEntry.Blink = NULL;
TimerMtx.unlock();
}
VOID xboxkrnl::KxRemoveTreeTimer(
@ -188,6 +202,8 @@ VOID xboxkrnl::KxRemoveTreeTimer(
ULONG Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
PKTIMER_TABLE_ENTRY TimerEntry;
TimerMtx.lock();
/* Set the timer as non-inserted */
Timer->Header.Inserted = FALSE;
@ -202,6 +218,7 @@ VOID xboxkrnl::KxRemoveTreeTimer(
TimerEntry->Time.u.HighPart = 0xFFFFFFFF;
}
}
TimerMtx.unlock();
}
xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTimerTable(
@ -217,6 +234,8 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTimerTable(
DBG_PRINTF("%s: inserting Timer %p, Hand: %lu\n", __func__, Timer, Hand);
TimerMtx.lock();
/* Check if the period is zero */
if (!Timer->Period) {
Timer->Header.SignalState = FALSE;
@ -253,6 +272,7 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTimerTable(
Expired = TRUE;
}
}
TimerMtx.unlock();
/* Return expired state */
return Expired;
@ -266,6 +286,8 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer(
BOOLEAN Inserted = FALSE;
ULONG Hand = 0;
TimerMtx.lock();
/* Setup the timer's due time */
if (KiComputeDueTime(Timer, Interval, &Hand))
{
@ -282,6 +304,7 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiInsertTreeTimer(
Inserted = TRUE;
}
}
TimerMtx.unlock();
return Inserted;
}
@ -300,6 +323,8 @@ xboxkrnl::BOOLEAN xboxkrnl::KiComputeDueTime(
{
LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime;
TimerMtx.lock();
/* Convert to relative time if needed */
Timer->Header.Absolute = FALSE;
if (DueTime.u.HighPart >= 0)
@ -319,6 +344,8 @@ xboxkrnl::BOOLEAN xboxkrnl::KiComputeDueTime(
Timer->Header.SignalState = TRUE;
Timer->DueTime.QuadPart = 0;
*Hand = 0;
TimerMtx.unlock();
return FALSE;
}
@ -335,6 +362,8 @@ xboxkrnl::BOOLEAN xboxkrnl::KiComputeDueTime(
/* Get the handle */
*Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
Timer->Header.Inserted = TRUE;
TimerMtx.unlock();
return TRUE;
}
@ -347,6 +376,8 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiSignalTimer(
ULONG Period = Timer->Period;
LARGE_INTEGER Interval, SystemTime;
TimerMtx.lock();
/* Set default values */
Timer->Header.Inserted = FALSE;
Timer->Header.SignalState = TRUE;
@ -386,6 +417,8 @@ xboxkrnl::BOOLEAN FASTCALL xboxkrnl::KiSignalTimer(
RequestInterrupt = TRUE;
}
TimerMtx.unlock();
/* Return whether we need to request a DPC interrupt or not */
return RequestInterrupt;
}

View File

@ -33,6 +33,8 @@
// ******************************************************************
#pragma once
#include <mutex>
namespace xboxkrnl
{
typedef struct _KTIMER_TABLE_ENTRY
@ -43,6 +45,9 @@ namespace xboxkrnl
const ULONG CLOCK_TIME_INCREMENT = 0x2710;
LIST_ENTRY KiWaitInListHead;
// Actually, this lock isn't required, but because raising the irql to dpc level doesn't really prevent thread switching at the
// moment, we need it for now to prevent concurrent access to the timer table
std::recursive_mutex TimerMtx;
VOID KiInitSystem();