diff --git a/reactos/ntoskrnl/KrnlFun.c b/reactos/ntoskrnl/KrnlFun.c index 5f27d66c918..3288f8b742e 100644 --- a/reactos/ntoskrnl/KrnlFun.c +++ b/reactos/ntoskrnl/KrnlFun.c @@ -8,9 +8,6 @@ // Do NOT ask when it will be fixed. // Failure to respect this will *ACHIEVE NOTHING*. // -// Ke2: -// - Dispatcher Rewrite (DPCs-Timers-Waits). -// // Hal: // - Use APC and DPC Interrupt Dispatchers. // - CMOS Initialization and CMOS Spinlock. @@ -26,14 +23,15 @@ // REACTOS GUIDANCE PLAN // ________________________________________________________________________________________________________ // / \ -// | OB, PS, LPC, DBGK, IO => Almost entirely fixed interaction with Ke/Ex. | | +// | OB, PS, LPC, DBGK, EX => "Code complete". No expected changes until 0.5.0 | | // | SE => Not looked at. Interaction with Ps/Io is minimal and currently hacked away. Preserve. |J| -// | EX => Needs re-visiting (in trunk). Do callbacks/push locks for interaction with Ps. |A| +// | INIT => Boot sequence still needs work in terms of interaction with Ke and CPU features. |A| // | KD/KDBG => Laptop has special version of ROS without these components. Commit in branch. |N| -// | INIT => Boot sequence still needs work in terms of interaction with Ke and CPU features. | | -// | || || || || || || || || || || || || |F| -// | \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ |E| -// | HAL => Needs APC/DPC/IRQL implementation fixed ASAP in terms of interaction with Ke. |B| +// | HAL => Needs APC/DPC/IRQL implementation fixed ASAP in terms of interaction with Ke. | | +// | || || || || || || || || || || || || | | +// | \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ |F| +// | KE => Enable new thread scheduler and ensure it works. |E| +// | KD => Implement KD64 6.0, compatible with WinDBG |B| // | FSTUB => Needs IoAssignDriveLetters fixed ASAP but not critical to Ke/Ex. Interacts with Io. | | // | || || || || || || || || || || || || |M| // | \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ |A| @@ -41,7 +39,7 @@ // | || || || || || || || || || || || || | | // | || || || || || || || || || || || || |A| // | \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ |P| -// | KE => Timer Rewrite + Thread Scheduler Rewrite. |R| +// | PNPMGR => TBD |R| // | || || || || || || || || || || || || |I| // | || || || || || || || || || || || || |L| // | || || || || || || || || || || || || | | diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 9e213f6f327..3d079faa3ea 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -55,6 +55,15 @@ typedef struct _KTIMER_TABLE_ENTRY ULARGE_INTEGER Time; } KTIMER_TABLE_ENTRY, *PKTIMER_TABLE_ENTRY; +#define MAX_TIMER_DPCS 16 + +typedef struct _DPC_QUEUE_ENTRY +{ + PKDPC Dpc; + PKDEFERRED_ROUTINE Routine; + PVOID Context; +} DPC_QUEUE_ENTRY, *PDPC_QUEUE_ENTRY; + typedef PCHAR (NTAPI *PKE_BUGCHECK_UNICODE_TO_ANSI)( IN PUNICODE_STRING Unicode, @@ -122,9 +131,8 @@ extern ULONG KiTimeLimitIsrMicroseconds; extern ULONG KiServiceLimit; extern LIST_ENTRY BugcheckCallbackListHead, BugcheckReasonCallbackListHead; extern KSPIN_LOCK BugCheckCallbackLock; -extern KDPC KiExpireTimerDpc; +extern KDPC KiTimerExpireDpc; extern KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]; -extern LIST_ENTRY KiTimerListHead; extern FAST_MUTEX KiGenericCallDpcMutex; extern LIST_ENTRY KiProfileListHead, KiProfileSourceListHead; extern KSPIN_LOCK KiProfileLock; @@ -258,6 +266,27 @@ CPUID( IN ULONG InfoType ); +BOOLEAN +FASTCALL +KiInsertTimerTable( + IN PKTIMER Timer, + IN ULONG Hand +); + +BOOLEAN +FASTCALL +KiInsertTreeTimer( + IN PKTIMER Timer, + IN LARGE_INTEGER Interval +); + +VOID +FASTCALL +KiCompleteTimer( + IN PKTIMER Timer, + IN PKSPIN_LOCK_QUEUE LockQueue +); + /* gmutex.c ********************************************************************/ VOID @@ -562,13 +591,6 @@ BOOLEAN NTAPI KeDisableThreadApcQueueing(IN PKTHREAD Thread); -BOOLEAN -NTAPI -KiInsertTimer( - PKTIMER Timer, - LARGE_INTEGER DueTime -); - VOID FASTCALL KiWaitTest( @@ -598,6 +620,21 @@ KiInsertQueue( BOOLEAN Head ); +VOID +NTAPI +KiTimerExpiration( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 +); + +ULONG +NTAPI +KiComputeTimerTableIndex( + IN LONGLONG TimeValue +); + ULONG NTAPI KeSetProcess( diff --git a/reactos/ntoskrnl/include/internal/ke_x.h b/reactos/ntoskrnl/include/internal/ke_x.h index 11050ad723a..0a354218c11 100644 --- a/reactos/ntoskrnl/include/internal/ke_x.h +++ b/reactos/ntoskrnl/include/internal/ke_x.h @@ -175,509 +175,6 @@ Ke386SanitizeDr(IN PVOID DrAddress, } \ } -// -// Satisfies the wait of any dispatcher object -// -#define KiSatisfyObjectWait(Object, Thread) \ -{ \ - /* Special case for Mutants */ \ - if ((Object)->Header.Type == MutantObject) \ - { \ - /* Decrease the Signal State */ \ - (Object)->Header.SignalState--; \ - \ - /* Check if it's now non-signaled */ \ - if (!(Object)->Header.SignalState) \ - { \ - /* Set the Owner Thread */ \ - (Object)->OwnerThread = Thread; \ - \ - /* Disable APCs if needed */ \ - Thread->KernelApcDisable = Thread->KernelApcDisable - \ - (Object)->ApcDisable; \ - \ - /* Check if it's abandoned */ \ - if ((Object)->Abandoned) \ - { \ - /* Unabandon it */ \ - (Object)->Abandoned = FALSE; \ - \ - /* Return Status */ \ - Thread->WaitStatus = STATUS_ABANDONED; \ - } \ - \ - /* Insert it into the Mutant List */ \ - InsertHeadList(Thread->MutantListHead.Blink, \ - &(Object)->MutantListEntry); \ - } \ - } \ - else if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ - EventSynchronizationObject) \ - { \ - /* Synchronization Timers and Events just get un-signaled */ \ - (Object)->Header.SignalState = 0; \ - } \ - else if ((Object)->Header.Type == SemaphoreObject) \ - { \ - /* These ones can have multiple states, so we only decrease it */ \ - (Object)->Header.SignalState--; \ - } \ -} - -// -// Satisfies the wait of a mutant dispatcher object -// -#define KiSatisfyMutantWait(Object, Thread) \ -{ \ - /* Decrease the Signal State */ \ - (Object)->Header.SignalState--; \ - \ - /* Check if it's now non-signaled */ \ - if (!(Object)->Header.SignalState) \ - { \ - /* Set the Owner Thread */ \ - (Object)->OwnerThread = Thread; \ - \ - /* Disable APCs if needed */ \ - Thread->KernelApcDisable = Thread->KernelApcDisable - \ - (Object)->ApcDisable; \ - \ - /* Check if it's abandoned */ \ - if ((Object)->Abandoned) \ - { \ - /* Unabandon it */ \ - (Object)->Abandoned = FALSE; \ - \ - /* Return Status */ \ - Thread->WaitStatus = STATUS_ABANDONED; \ - } \ - \ - /* Insert it into the Mutant List */ \ - InsertHeadList(Thread->MutantListHead.Blink, \ - &(Object)->MutantListEntry); \ - } \ -} - -// -// Satisfies the wait of any nonmutant dispatcher object -// -#define KiSatisfyNonMutantWait(Object) \ -{ \ - if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ - EventSynchronizationObject) \ - { \ - /* Synchronization Timers and Events just get un-signaled */ \ - (Object)->Header.SignalState = 0; \ - } \ - else if ((Object)->Header.Type == SemaphoreObject) \ - { \ - /* These ones can have multiple states, so we only decrease it */ \ - (Object)->Header.SignalState--; \ - } \ -} - -// -// Recalculates the due time -// -PLARGE_INTEGER -FORCEINLINE -KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime, - IN PLARGE_INTEGER DueTime, - IN OUT PLARGE_INTEGER NewDueTime) -{ - /* Don't do anything for absolute waits */ - if (OriginalDueTime->QuadPart >= 0) return OriginalDueTime; - - /* Otherwise, query the interrupt time and recalculate */ - NewDueTime->QuadPart = KeQueryInterruptTime(); - NewDueTime->QuadPart -= DueTime->QuadPart; - return NewDueTime; -} - -// -// Determines wether a thread should be added to the wait list -// -FORCEINLINE -BOOLEAN -KiCheckThreadStackSwap(IN PKTHREAD Thread, - IN KPROCESSOR_MODE WaitMode) -{ - /* Check the required conditions */ - if ((WaitMode != KernelMode) && - (Thread->EnableStackSwap) && - (Thread->Priority >= (LOW_REALTIME_PRIORITY + 9))) - { - /* We are go for swap */ - return TRUE; - } - else - { - /* Don't swap the thread */ - return FALSE; - } -} - -// -// Adds a thread to the wait list -// -#define KiAddThreadToWaitList(Thread, Swappable) \ -{ \ - /* Make sure it's swappable */ \ - if (Swappable) \ - { \ - /* Insert it into the PRCB's List */ \ - InsertTailList(&KeGetCurrentPrcb()->WaitListHead, \ - &Thread->WaitListEntry); \ - } \ -} - -// -// Checks if a wait in progress should be interrupted by APCs or an alertable -// state. -// -FORCEINLINE -NTSTATUS -KiCheckAlertability(IN PKTHREAD Thread, - IN BOOLEAN Alertable, - IN KPROCESSOR_MODE WaitMode) -{ - /* Check if the wait is alertable */ - if (Alertable) - { - /* It is, first check if the thread is alerted in this mode */ - if (Thread->Alerted[WaitMode]) - { - /* It is, so bail out of the wait */ - Thread->Alerted[WaitMode] = FALSE; - return STATUS_ALERTED; - } - else if ((WaitMode != KernelMode) && - (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) - { - /* It's isn't, but this is a user wait with queued user APCs */ - Thread->ApcState.UserApcPending = TRUE; - return STATUS_USER_APC; - } - else if (Thread->Alerted[KernelMode]) - { - /* It isn't that either, but we're alered in kernel mode */ - Thread->Alerted[KernelMode] = FALSE; - return STATUS_ALERTED; - } - } - else if ((WaitMode != KernelMode) && (Thread->ApcState.UserApcPending)) - { - /* Not alertable, but this is a user wait with pending user APCs */ - return STATUS_USER_APC; - } - - /* Otherwise, we're fine */ - return STATUS_WAIT_0; -} - -VOID -FORCEINLINE -KxSetTimerForThreadWait(IN PKTIMER Timer, - IN LARGE_INTEGER Interval) -{ - LARGE_INTEGER InterruptTime, SystemTime, TimeDifference; - - /* Check the timer's interval to see if it's absolute */ - Timer->Header.Absolute = FALSE; - if (!Timer->Period) Timer->Header.SignalState = FALSE; - if (Interval.HighPart >= 0) - { - /* Get the system time and calculate the relative time */ - KeQuerySystemTime(&SystemTime); - TimeDifference.QuadPart = SystemTime.QuadPart - Interval.QuadPart; - Timer->Header.Absolute = TRUE; - - /* Check if we've already expired */ - if (TimeDifference.HighPart >= 0) - { - /* Reset everything */ - Timer->DueTime.QuadPart = 0; - Timer->Header.SignalState = TRUE; - return; - } - else - { - /* Update the interval */ - Interval = TimeDifference; - } - } - - /* Calculate the due time */ - InterruptTime.QuadPart = KeQueryInterruptTime(); - Timer->DueTime.QuadPart = InterruptTime.QuadPart - Interval.QuadPart; -} - -#define KxDelayThreadWait() \ - \ - /* Setup the Wait Block */ \ - Thread->WaitBlockList = TimerBlock; \ - \ - /* Setup the timer */ \ - KxSetTimerForThreadWait(Timer, *Interval); \ - \ - /* Save the due time for the caller */ \ - DueTime.QuadPart = Timer->DueTime.QuadPart; \ - \ - /* Link the timer to this Wait Block */ \ - TimerBlock->NextWaitBlock = TimerBlock; \ - Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \ - Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \ - \ - /* Clear wait status */ \ - Thread->WaitStatus = STATUS_SUCCESS; \ - \ - /* Setup wait fields */ \ - Thread->Alertable = Alertable; \ - Thread->WaitReason = DelayExecution; \ - Thread->WaitMode = WaitMode; \ - \ - /* Check if we can swap the thread's stack */ \ - Thread->WaitListEntry.Flink = NULL; \ - Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ - \ - /* Set the wait time */ \ - Thread->WaitTime = KeTickCount.LowPart; - -#define KxMultiThreadWait() \ - /* Link wait block array to the thread */ \ - Thread->WaitBlockList = WaitBlockArray; \ - \ - /* Reset the index */ \ - Index = 0; \ - \ - /* Loop wait blocks */ \ - do \ - { \ - /* Fill out the wait block */ \ - WaitBlock = &WaitBlockArray[Index]; \ - WaitBlock->Object = Object[Index]; \ - WaitBlock->WaitKey = (USHORT)Index; \ - WaitBlock->WaitType = WaitType; \ - WaitBlock->Thread = Thread; \ - \ - /* Link to next block */ \ - WaitBlock->NextWaitBlock = &WaitBlockArray[Index + 1]; \ - Index++; \ - } while (Index < Count); \ - \ - /* Link the last block */ \ - WaitBlock->NextWaitBlock = WaitBlockArray; \ - \ - /* Set default wait status */ \ - Thread->WaitStatus = STATUS_WAIT_0; \ - \ - /* Check if we have a timer */ \ - if (Timeout) \ - { \ - /* Link to the block */ \ - TimerBlock->NextWaitBlock = WaitBlockArray; \ - \ - /* Setup the timer */ \ - KxSetTimerForThreadWait(Timer, *Timeout); \ - \ - /* Save the due time for the caller */ \ - DueTime.QuadPart = Timer->DueTime.QuadPart; \ - \ - /* Initialize the list */ \ - InitializeListHead(&Timer->Header.WaitListHead); \ - } \ - \ - /* Set wait settings */ \ - Thread->Alertable = Alertable; \ - Thread->WaitMode = WaitMode; \ - Thread->WaitReason = WaitReason; \ - \ - /* Check if we can swap the thread's stack */ \ - Thread->WaitListEntry.Flink = NULL; \ - Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ - \ - /* Set the wait time */ \ - Thread->WaitTime = KeTickCount.LowPart; - -#define KxSingleThreadWait() \ - /* Setup the Wait Block */ \ - Thread->WaitBlockList = WaitBlock; \ - WaitBlock->WaitKey = STATUS_SUCCESS; \ - WaitBlock->Object = Object; \ - WaitBlock->WaitType = WaitAny; \ - \ - /* Clear wait status */ \ - Thread->WaitStatus = STATUS_SUCCESS; \ - \ - /* Check if we have a timer */ \ - if (Timeout) \ - { \ - /* Setup the timer */ \ - KxSetTimerForThreadWait(Timer, *Timeout); \ - \ - /* Save the due time for the caller */ \ - DueTime.QuadPart = Timer->DueTime.QuadPart; \ - \ - /* Pointer to timer block */ \ - WaitBlock->NextWaitBlock = TimerBlock; \ - TimerBlock->NextWaitBlock = WaitBlock; \ - \ - /* Link the timer to this Wait Block */ \ - Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \ - Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \ - } \ - else \ - { \ - /* No timer block, just ourselves */ \ - WaitBlock->NextWaitBlock = WaitBlock; \ - } \ - \ - /* Set wait settings */ \ - Thread->Alertable = Alertable; \ - Thread->WaitMode = WaitMode; \ - Thread->WaitReason = WaitReason; \ - \ - /* Check if we can swap the thread's stack */ \ - Thread->WaitListEntry.Flink = NULL; \ - Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ - \ - /* Set the wait time */ \ - Thread->WaitTime = KeTickCount.LowPart; - -#define KxQueueThreadWait() \ - /* Setup the Wait Block */ \ - Thread->WaitBlockList = WaitBlock; \ - WaitBlock->WaitKey = STATUS_SUCCESS; \ - WaitBlock->Object = Queue; \ - WaitBlock->WaitType = WaitAny; \ - WaitBlock->Thread = Thread; \ - \ - /* Clear wait status */ \ - Thread->WaitStatus = STATUS_SUCCESS; \ - \ - /* Check if we have a timer */ \ - if (Timeout) \ - { \ - /* Setup the timer */ \ - KxSetTimerForThreadWait(Timer, *Timeout); \ - \ - /* Save the due time for the caller */ \ - DueTime.QuadPart = Timer->DueTime.QuadPart; \ - \ - /* Pointer to timer block */ \ - WaitBlock->NextWaitBlock = TimerBlock; \ - TimerBlock->NextWaitBlock = WaitBlock; \ - \ - /* Link the timer to this Wait Block */ \ - Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \ - Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \ - } \ - else \ - { \ - /* No timer block, just ourselves */ \ - WaitBlock->NextWaitBlock = WaitBlock; \ - } \ - \ - /* Set wait settings */ \ - Thread->Alertable = FALSE; \ - Thread->WaitMode = WaitMode; \ - Thread->WaitReason = WrQueue; \ - \ - /* Check if we can swap the thread's stack */ \ - Thread->WaitListEntry.Flink = NULL; \ - Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ - \ - /* Set the wait time */ \ - Thread->WaitTime = KeTickCount.LowPart; - -// -// Unwaits a Thread -// -FORCEINLINE -VOID -KxUnwaitThread(IN DISPATCHER_HEADER *Object, - IN KPRIORITY Increment) -{ - PLIST_ENTRY WaitEntry, WaitList; - PKWAIT_BLOCK WaitBlock; - PKTHREAD WaitThread; - ULONG WaitKey; - - /* Loop the Wait Entries */ - WaitList = &Object->WaitListHead; - ASSERT(IsListEmpty(&Object->WaitListHead) == FALSE); - WaitEntry = WaitList->Flink; - do - { - /* Get the current wait block */ - WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); - - /* Get the waiting thread */ - WaitThread = WaitBlock->Thread; - - /* Check the current Wait Mode */ - if (WaitBlock->WaitType == WaitAny) - { - /* Use the actual wait key */ - WaitKey = WaitBlock->WaitKey; - } - else - { - /* Otherwise, use STATUS_KERNEL_APC */ - WaitKey = STATUS_KERNEL_APC; - } - - /* Unwait the thread */ - KiUnwaitThread(WaitThread, WaitKey, Increment); - - /* Next entry */ - WaitEntry = WaitList->Flink; - } while (WaitEntry != WaitList); -} - -// -// Unwaits a Thread waiting on an event -// -FORCEINLINE -VOID -KxUnwaitThreadForEvent(IN PKEVENT Event, - IN KPRIORITY Increment) -{ - PLIST_ENTRY WaitEntry, WaitList; - PKWAIT_BLOCK WaitBlock; - PKTHREAD WaitThread; - - /* Loop the Wait Entries */ - WaitList = &Event->Header.WaitListHead; - ASSERT(IsListEmpty(&Event->Header.WaitListHead) == FALSE); - WaitEntry = WaitList->Flink; - do - { - /* Get the current wait block */ - WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); - - /* Get the waiting thread */ - WaitThread = WaitBlock->Thread; - - /* Check the current Wait Mode */ - if (WaitBlock->WaitType == WaitAny) - { - /* Un-signal it */ - Event->Header.SignalState = 0; - - /* Un-signal the event and unwait the thread */ - KiUnwaitThread(WaitThread, WaitBlock->WaitKey, Increment); - break; - } - - /* Unwait the thread with STATUS_KERNEL_APC */ - KiUnwaitThread(WaitThread, STATUS_KERNEL_APC, Increment); - - /* Next entry */ - WaitEntry = WaitList->Flink; - } while (WaitEntry != WaitList); -} - #ifndef _CONFIG_SMP // // Spinlock Acquire at IRQL >= DISPATCH_LEVEL @@ -1296,6 +793,579 @@ KiReleaseDeviceQueueLock(IN PKLOCK_QUEUE_HANDLE DeviceLock) } } +// +// Satisfies the wait of any dispatcher object +// +#define KiSatisfyObjectWait(Object, Thread) \ +{ \ + /* Special case for Mutants */ \ + if ((Object)->Header.Type == MutantObject) \ + { \ + /* Decrease the Signal State */ \ + (Object)->Header.SignalState--; \ + \ + /* Check if it's now non-signaled */ \ + if (!(Object)->Header.SignalState) \ + { \ + /* Set the Owner Thread */ \ + (Object)->OwnerThread = Thread; \ + \ + /* Disable APCs if needed */ \ + Thread->KernelApcDisable = Thread->KernelApcDisable - \ + (Object)->ApcDisable; \ + \ + /* Check if it's abandoned */ \ + if ((Object)->Abandoned) \ + { \ + /* Unabandon it */ \ + (Object)->Abandoned = FALSE; \ + \ + /* Return Status */ \ + Thread->WaitStatus = STATUS_ABANDONED; \ + } \ + \ + /* Insert it into the Mutant List */ \ + InsertHeadList(Thread->MutantListHead.Blink, \ + &(Object)->MutantListEntry); \ + } \ + } \ + else if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ + EventSynchronizationObject) \ + { \ + /* Synchronization Timers and Events just get un-signaled */ \ + (Object)->Header.SignalState = 0; \ + } \ + else if ((Object)->Header.Type == SemaphoreObject) \ + { \ + /* These ones can have multiple states, so we only decrease it */ \ + (Object)->Header.SignalState--; \ + } \ +} + +// +// Satisfies the wait of a mutant dispatcher object +// +#define KiSatisfyMutantWait(Object, Thread) \ +{ \ + /* Decrease the Signal State */ \ + (Object)->Header.SignalState--; \ + \ + /* Check if it's now non-signaled */ \ + if (!(Object)->Header.SignalState) \ + { \ + /* Set the Owner Thread */ \ + (Object)->OwnerThread = Thread; \ + \ + /* Disable APCs if needed */ \ + Thread->KernelApcDisable = Thread->KernelApcDisable - \ + (Object)->ApcDisable; \ + \ + /* Check if it's abandoned */ \ + if ((Object)->Abandoned) \ + { \ + /* Unabandon it */ \ + (Object)->Abandoned = FALSE; \ + \ + /* Return Status */ \ + Thread->WaitStatus = STATUS_ABANDONED; \ + } \ + \ + /* Insert it into the Mutant List */ \ + InsertHeadList(Thread->MutantListHead.Blink, \ + &(Object)->MutantListEntry); \ + } \ +} + +// +// Satisfies the wait of any nonmutant dispatcher object +// +#define KiSatisfyNonMutantWait(Object) \ +{ \ + if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ + EventSynchronizationObject) \ + { \ + /* Synchronization Timers and Events just get un-signaled */ \ + (Object)->Header.SignalState = 0; \ + } \ + else if ((Object)->Header.Type == SemaphoreObject) \ + { \ + /* These ones can have multiple states, so we only decrease it */ \ + (Object)->Header.SignalState--; \ + } \ +} + +// +// Recalculates the due time +// +PLARGE_INTEGER +FORCEINLINE +KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime, + IN PLARGE_INTEGER DueTime, + IN OUT PLARGE_INTEGER NewDueTime) +{ + /* Don't do anything for absolute waits */ + if (OriginalDueTime->QuadPart >= 0) return OriginalDueTime; + + /* Otherwise, query the interrupt time and recalculate */ + NewDueTime->QuadPart = KeQueryInterruptTime(); + NewDueTime->QuadPart -= DueTime->QuadPart; + return NewDueTime; +} + +// +// Determines whether a thread should be added to the wait list +// +FORCEINLINE +BOOLEAN +KiCheckThreadStackSwap(IN PKTHREAD Thread, + IN KPROCESSOR_MODE WaitMode) +{ + /* Check the required conditions */ + if ((WaitMode != KernelMode) && + (Thread->EnableStackSwap) && + (Thread->Priority >= (LOW_REALTIME_PRIORITY + 9))) + { + /* We are go for swap */ + return TRUE; + } + else + { + /* Don't swap the thread */ + return FALSE; + } +} + +// +// Adds a thread to the wait list +// +#define KiAddThreadToWaitList(Thread, Swappable) \ +{ \ + /* Make sure it's swappable */ \ + if (Swappable) \ + { \ + /* Insert it into the PRCB's List */ \ + InsertTailList(&KeGetCurrentPrcb()->WaitListHead, \ + &Thread->WaitListEntry); \ + } \ +} + +// +// Checks if a wait in progress should be interrupted by APCs or an alertable +// state. +// +FORCEINLINE +NTSTATUS +KiCheckAlertability(IN PKTHREAD Thread, + IN BOOLEAN Alertable, + IN KPROCESSOR_MODE WaitMode) +{ + /* Check if the wait is alertable */ + if (Alertable) + { + /* It is, first check if the thread is alerted in this mode */ + if (Thread->Alerted[WaitMode]) + { + /* It is, so bail out of the wait */ + Thread->Alerted[WaitMode] = FALSE; + return STATUS_ALERTED; + } + else if ((WaitMode != KernelMode) && + (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) + { + /* It's isn't, but this is a user wait with queued user APCs */ + Thread->ApcState.UserApcPending = TRUE; + return STATUS_USER_APC; + } + else if (Thread->Alerted[KernelMode]) + { + /* It isn't that either, but we're alered in kernel mode */ + Thread->Alerted[KernelMode] = FALSE; + return STATUS_ALERTED; + } + } + else if ((WaitMode != KernelMode) && (Thread->ApcState.UserApcPending)) + { + /* Not alertable, but this is a user wait with pending user APCs */ + return STATUS_USER_APC; + } + + /* Otherwise, we're fine */ + return STATUS_WAIT_0; +} + +// +// Called by Wait and Queue code to insert a timer for dispatching. +// Also called by KeSetTimerEx to insert a timer from the caller. +// +VOID +FORCEINLINE +KxInsertTimer(IN PKTIMER Timer, + IN ULONG Hand) +{ + PKSPIN_LOCK_QUEUE LockQueue; + + /* Acquire the lock and release the dispatcher lock */ + LockQueue = KiAcquireTimerLock(Hand); + KiReleaseDispatcherLockFromDpcLevel(); + + /* Try to insert the timer */ + if (KiInsertTimerTable(Timer, Hand)) + { + /* Complete it */ + KiCompleteTimer(Timer, LockQueue); + } + else + { + /* Do nothing, just release the lock */ + KiReleaseTimerLock(LockQueue); + } +} + +// +// Called from Unlink and Queue Insert Code. +// Also called by timer code when canceling an inserted timer. +// Removes a timer from it's tree. +// +VOID +FORCEINLINE +KxRemoveTreeTimer(IN PKTIMER Timer) +{ + ULONG Hand = Timer->Header.Hand; + PKSPIN_LOCK_QUEUE LockQueue; + PKTIMER_TABLE_ENTRY TimerEntry; + + /* Acquire timer lock */ + LockQueue = KiAcquireTimerLock(Hand); + + /* Set the timer as non-inserted */ + Timer->Header.Inserted = FALSE; + + /* Remove it from the timer list */ + if (RemoveEntryList(&Timer->TimerListEntry)) + { + /* Get the entry and check if it's empty */ + TimerEntry = &KiTimerTableListHead[Hand]; + if (IsListEmpty(&TimerEntry->Entry)) + { + /* Clear the time then */ + TimerEntry->Time.HighPart = 0xFFFFFFFF; + } + } + + /* Release the timer lock */ + KiReleaseTimerLock(LockQueue); +} + +VOID +FORCEINLINE +KxSetTimerForThreadWait(IN PKTIMER Timer, + IN LARGE_INTEGER Interval, + OUT PULONG Hand) +{ + ULONGLONG DueTime; + LARGE_INTEGER InterruptTime, SystemTime, TimeDifference; + + /* Check the timer's interval to see if it's absolute */ + Timer->Header.Absolute = FALSE; + if (Interval.HighPart >= 0) + { + /* Get the system time and calculate the relative time */ + KeQuerySystemTime(&SystemTime); + TimeDifference.QuadPart = SystemTime.QuadPart - Interval.QuadPart; + Timer->Header.Absolute = TRUE; + + /* Check if we've already expired */ + if (TimeDifference.HighPart >= 0) + { + /* Reset everything */ + Timer->DueTime.QuadPart = 0; + *Hand = 0; + Timer->Header.Hand = 0; + return; + } + else + { + /* Update the interval */ + Interval = TimeDifference; + } + } + + /* Calculate the due time */ + InterruptTime.QuadPart = KeQueryInterruptTime(); + DueTime = InterruptTime.QuadPart - Interval.QuadPart; + Timer->DueTime.QuadPart = DueTime; + + /* Calculate the timer handle */ + *Hand = KiComputeTimerTableIndex(DueTime); + Timer->Header.Hand = (UCHAR)*Hand; +} + +#define KxDelayThreadWait() \ + \ + /* Setup the Wait Block */ \ + Thread->WaitBlockList = TimerBlock; \ + \ + /* Setup the timer */ \ + KxSetTimerForThreadWait(Timer, *Interval, &Hand); \ + \ + /* Save the due time for the caller */ \ + DueTime.QuadPart = Timer->DueTime.QuadPart; \ + \ + /* Link the timer to this Wait Block */ \ + TimerBlock->NextWaitBlock = TimerBlock; \ + Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \ + Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \ + \ + /* Clear wait status */ \ + Thread->WaitStatus = STATUS_SUCCESS; \ + \ + /* Setup wait fields */ \ + Thread->Alertable = Alertable; \ + Thread->WaitReason = DelayExecution; \ + Thread->WaitMode = WaitMode; \ + \ + /* Check if we can swap the thread's stack */ \ + Thread->WaitListEntry.Flink = NULL; \ + Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ + \ + /* Set the wait time */ \ + Thread->WaitTime = KeTickCount.LowPart; + +#define KxMultiThreadWait() \ + /* Link wait block array to the thread */ \ + Thread->WaitBlockList = WaitBlockArray; \ + \ + /* Reset the index */ \ + Index = 0; \ + \ + /* Loop wait blocks */ \ + do \ + { \ + /* Fill out the wait block */ \ + WaitBlock = &WaitBlockArray[Index]; \ + WaitBlock->Object = Object[Index]; \ + WaitBlock->WaitKey = (USHORT)Index; \ + WaitBlock->WaitType = WaitType; \ + WaitBlock->Thread = Thread; \ + \ + /* Link to next block */ \ + WaitBlock->NextWaitBlock = &WaitBlockArray[Index + 1]; \ + Index++; \ + } while (Index < Count); \ + \ + /* Link the last block */ \ + WaitBlock->NextWaitBlock = WaitBlockArray; \ + \ + /* Set default wait status */ \ + Thread->WaitStatus = STATUS_WAIT_0; \ + \ + /* Check if we have a timer */ \ + if (Timeout) \ + { \ + /* Link to the block */ \ + TimerBlock->NextWaitBlock = WaitBlockArray; \ + \ + /* Setup the timer */ \ + KxSetTimerForThreadWait(Timer, *Timeout, &Hand); \ + \ + /* Save the due time for the caller */ \ + DueTime.QuadPart = Timer->DueTime.QuadPart; \ + \ + /* Initialize the list */ \ + InitializeListHead(&Timer->Header.WaitListHead); \ + } \ + \ + /* Set wait settings */ \ + Thread->Alertable = Alertable; \ + Thread->WaitMode = WaitMode; \ + Thread->WaitReason = WaitReason; \ + \ + /* Check if we can swap the thread's stack */ \ + Thread->WaitListEntry.Flink = NULL; \ + Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ + \ + /* Set the wait time */ \ + Thread->WaitTime = KeTickCount.LowPart; + +#define KxSingleThreadWait() \ + /* Setup the Wait Block */ \ + Thread->WaitBlockList = WaitBlock; \ + WaitBlock->WaitKey = STATUS_SUCCESS; \ + WaitBlock->Object = Object; \ + WaitBlock->WaitType = WaitAny; \ + \ + /* Clear wait status */ \ + Thread->WaitStatus = STATUS_SUCCESS; \ + \ + /* Check if we have a timer */ \ + if (Timeout) \ + { \ + /* Setup the timer */ \ + KxSetTimerForThreadWait(Timer, *Timeout, &Hand); \ + \ + /* Save the due time for the caller */ \ + DueTime.QuadPart = Timer->DueTime.QuadPart; \ + \ + /* Pointer to timer block */ \ + WaitBlock->NextWaitBlock = TimerBlock; \ + TimerBlock->NextWaitBlock = WaitBlock; \ + \ + /* Link the timer to this Wait Block */ \ + Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \ + Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \ + } \ + else \ + { \ + /* No timer block, just ourselves */ \ + WaitBlock->NextWaitBlock = WaitBlock; \ + } \ + \ + /* Set wait settings */ \ + Thread->Alertable = Alertable; \ + Thread->WaitMode = WaitMode; \ + Thread->WaitReason = WaitReason; \ + \ + /* Check if we can swap the thread's stack */ \ + Thread->WaitListEntry.Flink = NULL; \ + Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ + \ + /* Set the wait time */ \ + Thread->WaitTime = KeTickCount.LowPart; + +#define KxQueueThreadWait() \ + /* Setup the Wait Block */ \ + Thread->WaitBlockList = WaitBlock; \ + WaitBlock->WaitKey = STATUS_SUCCESS; \ + WaitBlock->Object = Queue; \ + WaitBlock->WaitType = WaitAny; \ + WaitBlock->Thread = Thread; \ + \ + /* Clear wait status */ \ + Thread->WaitStatus = STATUS_SUCCESS; \ + \ + /* Check if we have a timer */ \ + if (Timeout) \ + { \ + /* Setup the timer */ \ + KxSetTimerForThreadWait(Timer, *Timeout, &Hand); \ + \ + /* Save the due time for the caller */ \ + DueTime.QuadPart = Timer->DueTime.QuadPart; \ + \ + /* Pointer to timer block */ \ + WaitBlock->NextWaitBlock = TimerBlock; \ + TimerBlock->NextWaitBlock = WaitBlock; \ + \ + /* Link the timer to this Wait Block */ \ + Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \ + Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \ + } \ + else \ + { \ + /* No timer block, just ourselves */ \ + WaitBlock->NextWaitBlock = WaitBlock; \ + } \ + \ + /* Set wait settings */ \ + Thread->Alertable = FALSE; \ + Thread->WaitMode = WaitMode; \ + Thread->WaitReason = WrQueue; \ + \ + /* Check if we can swap the thread's stack */ \ + Thread->WaitListEntry.Flink = NULL; \ + Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \ + \ + /* Set the wait time */ \ + Thread->WaitTime = KeTickCount.LowPart; + +// +// Unwaits a Thread +// +FORCEINLINE +VOID +KxUnwaitThread(IN DISPATCHER_HEADER *Object, + IN KPRIORITY Increment) +{ + PLIST_ENTRY WaitEntry, WaitList; + PKWAIT_BLOCK WaitBlock; + PKTHREAD WaitThread; + ULONG WaitKey; + + /* Loop the Wait Entries */ + WaitList = &Object->WaitListHead; + ASSERT(IsListEmpty(&Object->WaitListHead) == FALSE); + WaitEntry = WaitList->Flink; + do + { + /* Get the current wait block */ + WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); + + /* Get the waiting thread */ + WaitThread = WaitBlock->Thread; + + /* Check the current Wait Mode */ + if (WaitBlock->WaitType == WaitAny) + { + /* Use the actual wait key */ + WaitKey = WaitBlock->WaitKey; + } + else + { + /* Otherwise, use STATUS_KERNEL_APC */ + WaitKey = STATUS_KERNEL_APC; + } + + /* Unwait the thread */ + KiUnwaitThread(WaitThread, WaitKey, Increment); + + /* Next entry */ + WaitEntry = WaitList->Flink; + } while (WaitEntry != WaitList); +} + +// +// Unwaits a Thread waiting on an event +// +FORCEINLINE +VOID +KxUnwaitThreadForEvent(IN PKEVENT Event, + IN KPRIORITY Increment) +{ + PLIST_ENTRY WaitEntry, WaitList; + PKWAIT_BLOCK WaitBlock; + PKTHREAD WaitThread; + + /* Loop the Wait Entries */ + WaitList = &Event->Header.WaitListHead; + ASSERT(IsListEmpty(&Event->Header.WaitListHead) == FALSE); + WaitEntry = WaitList->Flink; + do + { + /* Get the current wait block */ + WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); + + /* Get the waiting thread */ + WaitThread = WaitBlock->Thread; + + /* Check the current Wait Mode */ + if (WaitBlock->WaitType == WaitAny) + { + /* Un-signal it */ + Event->Header.SignalState = 0; + + /* Un-signal the event and unwait the thread */ + KiUnwaitThread(WaitThread, WaitBlock->WaitKey, Increment); + break; + } + + /* Unwait the thread with STATUS_KERNEL_APC */ + KiUnwaitThread(WaitThread, STATUS_KERNEL_APC, Increment); + + /* Next entry */ + WaitEntry = WaitList->Flink; + } while (WaitEntry != WaitList); +} + // // This routine queues a thread that is ready on the PRCB's ready lists. // If this thread cannot currently run on this CPU, then the thread is @@ -1468,14 +1538,3 @@ KeGetPreviousMode(VOID) return KeGetCurrentThread()->PreviousMode; } -VOID -FORCEINLINE -KiInsertWaitTimer(IN PKTIMER Timer) -{ - /* Now insert it into the Timer List */ - InsertAscendingList(&KiTimerListHead, - Timer, - KTIMER, - TimerListEntry, - DueTime.QuadPart); -} diff --git a/reactos/ntoskrnl/ke/clock.c b/reactos/ntoskrnl/ke/clock.c index ee739922e6e..5df7bcc1f8e 100644 --- a/reactos/ntoskrnl/ke/clock.c +++ b/reactos/ntoskrnl/ke/clock.c @@ -27,7 +27,7 @@ /* GLOBALS ****************************************************************/ LARGE_INTEGER KeBootTime, KeBootTimeBias; -KDPC KiExpireTimerDpc; +KDPC KiTimerExpireDpc; BOOLEAN KiClockSetupComplete = FALSE; ULONG KiTimeLimitIsrMicroseconds; @@ -37,7 +37,6 @@ ULONG KiTimeLimitIsrMicroseconds; volatile KSYSTEM_TIME KeTickCount = {0}; volatile ULONG KiRawTicks = 0; LONG KiTickOffset = 0; -extern LIST_ENTRY KiTimerListHead; /* * The increment in the system clock every timer tick (in system time units) diff --git a/reactos/ntoskrnl/ke/dpc.c b/reactos/ntoskrnl/ke/dpc.c index e18eb0e418d..6e481eef1ca 100644 --- a/reactos/ntoskrnl/ke/dpc.c +++ b/reactos/ntoskrnl/ke/dpc.c @@ -2,7 +2,7 @@ * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ke/dpc.c - * PURPOSE: Routines for CPU-level support + * PURPOSE: Deferred Procedure Call (DPC) Support * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Philip Susi (phreak@iag.net) * Eric Kohl (ekohl@abo.rhein-zeitung.de) @@ -25,14 +25,231 @@ FAST_MUTEX KiGenericCallDpcMutex; /* PRIVATE FUNCTIONS *********************************************************/ -// -// This routine executes at the end of a thread's quantum. -// If the thread's quantum has expired, then a new thread is attempted -// to be scheduled. -// -// If no candidate thread has been found, the routine will return, otherwise -// it will swap contexts to the next scheduled thread. -// +VOID +NTAPI +KiTimerExpiration(IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + LARGE_INTEGER SystemTime, InterruptTime, Interval; + LONG Limit, Index, i; + ULONG Timers, ActiveTimers, DpcCalls; + PLIST_ENTRY ListHead, NextEntry; + PKTIMER_TABLE_ENTRY TimerEntry; + KIRQL OldIrql; + PKTIMER Timer; + PKDPC TimerDpc; + ULONG Period; + DPC_QUEUE_ENTRY DpcEntry[MAX_TIMER_DPCS]; + PKSPIN_LOCK_QUEUE LockQueue; + + /* Disable interrupts */ + _disable(); + + /* Query system and interrupt time */ + KeQuerySystemTime(&SystemTime); + InterruptTime.QuadPart = KeQueryInterruptTime(); + Limit = KeTickCount.LowPart; + + /* Bring interrupts back */ + _enable(); + + /* Get the index of the timer and normalize it */ + Index = PtrToLong(SystemArgument1); + if ((Limit - Index) >= TIMER_TABLE_SIZE) + { + /* Normalize it */ + Limit = Index + TIMER_TABLE_SIZE - 1; + } + + /* Setup index and actual limit */ + Index--; + Limit &= (TIMER_TABLE_SIZE - 1); + + /* Setup accounting data */ + DpcCalls = 0; + Timers = 24; + ActiveTimers = 4; + + /* Lock the Database and Raise IRQL */ + OldIrql = KiAcquireDispatcherLock(); + + /* Start expiration loop */ + do + { + /* Get the current index */ + Index = (Index + 1) & (TIMER_TABLE_SIZE - 1); + + /* Get list pointers and loop the list */ + ListHead = &KiTimerTableListHead[Index].Entry; + while (ListHead != ListHead->Flink) + { + /* Lock the timer and go to the next entry */ + LockQueue = KiAcquireTimerLock(Index); + NextEntry = ListHead->Flink; + + /* Get the current timer and check its due time */ + Timers--; + Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); + if ((NextEntry != ListHead) && + (Timer->DueTime.QuadPart <= InterruptTime.QuadPart)) + { + /* It's expired, remove it */ + ActiveTimers--; + if (RemoveEntryList(&Timer->TimerListEntry)) + { + /* Get the entry and check if it's empty */ + TimerEntry = &KiTimerTableListHead[Timer->Header.Hand]; + if (IsListEmpty(&TimerEntry->Entry)) + { + /* Clear the time then */ + TimerEntry->Time.HighPart = 0xFFFFFFFF; + } + } + + /* Make it non-inserted, unlock it, and signal it */ + Timer->Header.Inserted = FALSE; + KiReleaseTimerLock(LockQueue); + Timer->Header.SignalState = 1; + + /* Get the DPC and period */ + TimerDpc = Timer->Dpc; + Period = Timer->Period; + + /* Check if there's any waiters */ + if (!IsListEmpty(&Timer->Header.WaitListHead)) + { + /* Check the type of event */ + if (Timer->Header.Type == TimerNotificationObject) + { + /* Unwait the thread */ + KxUnwaitThread(&Timer->Header, IO_NO_INCREMENT); + } + else + { + /* Otherwise unwait the thread and signal the timer */ + KxUnwaitThreadForEvent((PKEVENT)Timer, IO_NO_INCREMENT); + } + } + + /* Check if we have a period */ + if (Period) + { + /* Calculate the interval and insert the timer */ + Interval.QuadPart = Int32x32To64(Period, -10000); + while (!KiInsertTreeTimer(Timer, Interval)); + } + + /* Check if we have a DPC */ + if (TimerDpc) + { + /* Setup the DPC Entry */ + DpcEntry[DpcCalls].Dpc = TimerDpc; + DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine; + DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext; + DpcCalls++; + } + + /* Check if we're done processing */ + if (!(ActiveTimers) || !(Timers)) + { + /* Release the dispatcher while doing DPCs */ + KiReleaseDispatcherLock(DISPATCH_LEVEL); + + /* Start looping all DPC Entries */ + for (i = 0; DpcCalls; DpcCalls--, i++) + { + /* Call the DPC */ + DpcEntry[i].Routine(DpcEntry[i].Dpc, + DpcEntry[i].Context, + UlongToPtr(SystemTime.LowPart), + UlongToPtr(SystemTime.HighPart)); + } + + /* Reset accounting */ + Timers = 24; + ActiveTimers = 4; + + /* Lock the dispatcher database */ + KiAcquireDispatcherLock(); + } + } + else + { + /* Check if the timer list is empty */ + if (NextEntry != ListHead) + { + /* Sanity check */ + ASSERT(KiTimerTableListHead[Index].Time.QuadPart <= + Timer->DueTime.QuadPart); + + /* Update the time */ + _disable(); + KiTimerTableListHead[Index].Time.QuadPart = + Timer->DueTime.QuadPart; + _enable(); + } + + /* Release the lock */ + KiReleaseTimerLock(LockQueue); + + /* Check if we've scanned all the timers we could */ + if (!Timers) + { + /* Release the dispatcher while doing DPCs */ + KiReleaseDispatcherLock(DISPATCH_LEVEL); + + /* Start looping all DPC Entries */ + for (i = 0; DpcCalls; DpcCalls--, i++) + { + /* Call the DPC */ + DpcEntry[i].Routine(DpcEntry[i].Dpc, + DpcEntry[i].Context, + UlongToPtr(SystemTime.LowPart), + UlongToPtr(SystemTime.HighPart)); + } + + /* Reset accounting */ + Timers = 24; + ActiveTimers = 4; + + /* Lock the dispatcher database */ + KiAcquireDispatcherLock(); + } + + /* Done looping */ + break; + } + } + } while (Index != Limit); + + /* Check if we still have DPC entries */ + if (DpcCalls) + { + /* Release the dispatcher while doing DPCs */ + KiReleaseDispatcherLock(DISPATCH_LEVEL); + + /* Start looping all DPC Entries */ + for (i = 0; DpcCalls; DpcCalls--, i++) + { + /* Call the DPC */ + DpcEntry[i].Routine(DpcEntry[i].Dpc, + DpcEntry[i].Context, + UlongToPtr(SystemTime.LowPart), + UlongToPtr(SystemTime.HighPart)); + } + + /* Lower IRQL if we need to */ + if (OldIrql != DISPATCH_LEVEL) KeLowerIrql(OldIrql); + } + else + { + /* Unlock the dispatcher */ + KiReleaseDispatcherLock(OldIrql); + } +} + VOID NTAPI KiQuantumEnd(VOID) @@ -146,6 +363,7 @@ KiRetireDpcList(IN PKPRCB Prcb) PKDPC Dpc; PKDEFERRED_ROUTINE DeferredRoutine; PVOID DeferredContext, SystemArgument1, SystemArgument2; + ULONG_PTR TimerHand; /* Main outer loop */ do @@ -156,8 +374,11 @@ KiRetireDpcList(IN PKPRCB Prcb) /* Check if this is a timer expiration request */ if (Prcb->TimerRequest) { - /* FIXME: Not yet implemented */ - ASSERT(FALSE); + TimerHand = Prcb->TimerHand; + Prcb->TimerRequest = 0; + _enable(); + KiTimerExpiration(NULL, NULL, (PVOID) TimerHand, NULL); + _disable(); } /* Loop while we have entries in the queue */ diff --git a/reactos/ntoskrnl/ke/i386/clock.S b/reactos/ntoskrnl/ke/i386/clock.S index 298d23c61d1..a2c54e93117 100644 --- a/reactos/ntoskrnl/ke/i386/clock.S +++ b/reactos/ntoskrnl/ke/i386/clock.S @@ -13,6 +13,45 @@ /* FUNCTIONS ******************************************************************/ +.globl _KiComputeTimerTableIndex@8 +.func KiComputeTimerTableIndex@8 +_KiComputeTimerTableIndex@8: + + /* Save registers */ + push ebx + + /* Make the first multiplication */ + mov eax, [esp+8] + mul dword ptr [_KiTimeIncrementReciprocal+4] + mov ebx, eax + mov ecx, edx + + /* Make the second multiplication */ + mov eax, [esp+12] + mul dword ptr [_KiTimeIncrementReciprocal] + add ebx, eax + adc ecx, edx + + /* Multiply by the reciprocal */ + mov eax, [esp+8] + mul dword ptr [_KiTimeIncrementReciprocal] + mov eax, [esp+12] + push edx + mul dword ptr [_KiTimeIncrementReciprocal+4] + pop edx + add edx, ebx + adc eax, ecx + + /* Shift the result and generate the index */ + mov cl, [_KiTimeIncrementShiftCount] + shr eax, cl + and eax, TIMER_TABLE_SIZE - 1 + + /* Return */ + pop ebx + ret 8 +.endfunc + .globl _KeUpdateRunTime@4 .func KeUpdateRunTime@4 _KeUpdateRunTime@4: @@ -214,13 +253,50 @@ _KeUpdateSystemTime@0: /* FIXME: HACK */ mov ds:[USER_SHARED_DATA], ecx + /* Get hand index and entry into the table */ + and eax, TIMER_TABLE_SIZE - 1 + shl eax, 4 + + /* Compare the due time */ + cmp esi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME+4] + jb NextHand + ja TimerExpired + cmp edi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME] + jnb TimerExpired + +NextHand: + /* Move to the next hand */ + inc ebx + mov eax, ebx + IncompleteTick: - /* FIXME: NASTY Queue DPC to handle registered timers */ - push 0 - push [esp+KTRAP_FRAME_EIP] - push offset _KiExpireTimerDpc - call _KeInsertQueueDpc@12 + /* Get hand index and entry into the table */ + and eax, TIMER_TABLE_SIZE - 1 + shl eax, 4 + + /* Compare the due time */ + cmp esi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME+4] + jb DebugCheck + ja TimerExpired + cmp edi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME] + jb DebugCheck + +TimerExpired: + + /* Check if expiration is active */ + mov ecx, [fs:KPCR_PRCB] + cmp dword ptr [ecx+KPRCB_TIMER_REQUEST], 0 + jne DebugCheck + + /* It's not, register it */ + mov [ecx+KPRCB_TIMER_REQUEST], esp + mov [ecx+KPRCB_TIMER_HAND], ebx + mov ecx, DISPATCH_LEVEL + call @HalRequestSoftwareInterrupt@4 + +DebugCheck: + /* FIXME: Check for KdDebuggerEnabled */ /* Check if this was a full tick */ cmp dword ptr _KiTickOffset, 0 diff --git a/reactos/ntoskrnl/ke/krnlinit.c b/reactos/ntoskrnl/ke/krnlinit.c index 0b709bc7682..4a3524069f3 100644 --- a/reactos/ntoskrnl/ke/krnlinit.c +++ b/reactos/ntoskrnl/ke/krnlinit.c @@ -67,8 +67,8 @@ KiInitSystem(VOID) KeInitializeSpinLock(&BugCheckCallbackLock); /* Initialize the Timer Expiration DPC */ - KeInitializeDpc(&KiExpireTimerDpc, KiExpireTimers, NULL); - KeSetTargetProcessorDpc(&KiExpireTimerDpc, 0); + KeInitializeDpc(&KiTimerExpireDpc, KiTimerExpiration, NULL); + KeSetTargetProcessorDpc(&KiTimerExpireDpc, 0); /* Initialize Profiling data */ KeInitializeSpinLock(&KiProfileLock); @@ -84,9 +84,6 @@ KiInitSystem(VOID) KiTimerTableListHead[i].Time.LowPart = 0; } - /* Initialize old-style list */ - InitializeListHead(&KiTimerListHead); - /* Initialize the Swap event and all swap lists */ KeInitializeEvent(&KiSwapEvent, SynchronizationEvent, FALSE); InitializeListHead(&KiProcessInSwapListHead); @@ -293,3 +290,5 @@ KeInitSystem(VOID) return TRUE; } + + diff --git a/reactos/ntoskrnl/ke/queue.c b/reactos/ntoskrnl/ke/queue.c index c41141caf20..a2bddee7070 100644 --- a/reactos/ntoskrnl/ke/queue.c +++ b/reactos/ntoskrnl/ke/queue.c @@ -75,6 +75,7 @@ KiInsertQueue(IN PKQUEUE Queue, PKTHREAD Thread = KeGetCurrentThread(); PKWAIT_BLOCK WaitBlock; PLIST_ENTRY WaitEntry; + PKTIMER Timer; ASSERT_QUEUE(Queue); /* Save the old state */ @@ -109,12 +110,8 @@ KiInsertQueue(IN PKQUEUE Queue, Thread->WaitReason = 0; /* Check if there's a Thread Timer */ - if (Thread->Timer.Header.Inserted) - { - /* Cancel the Thread Timer with the no-lock fastpath */ - Thread->Timer.Header.Inserted = FALSE; - RemoveEntryList(&Thread->Timer.TimerListEntry); - } + Timer = &Thread->Timer; + if (Timer->Header.Inserted) KxRemoveTreeTimer(Timer); /* Reschedule the Thread */ KiReadyThread(Thread); @@ -251,6 +248,7 @@ KeRemoveQueue(IN PKQUEUE Queue, BOOLEAN Swappable; PLARGE_INTEGER OriginalDueTime = Timeout; LARGE_INTEGER DueTime, NewDueTime, InterruptTime; + ULONG Hand = 0; ASSERT_QUEUE(Queue); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); @@ -390,7 +388,7 @@ KeRemoveQueue(IN PKQUEUE Queue, if (Timeout) { /* Insert it */ - KiInsertWaitTimer(Timer); + KxInsertTimer(Timer, Hand); } else { diff --git a/reactos/ntoskrnl/ke/timer.c b/reactos/ntoskrnl/ke/timer.c index 160f869cc05..cd32d9d2875 100644 --- a/reactos/ntoskrnl/ke/timer.c +++ b/reactos/ntoskrnl/ke/timer.c @@ -4,188 +4,242 @@ * FILE: ntoskrnl/ke/timer.c * PURPOSE: Handle Kernel Timers (Kernel-part of Executive Timers) * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - * David Welch (welch@mcmail.com) */ -/* INCLUDES ***************************************************************/ +/* INCLUDES ******************************************************************/ #include #define NDEBUG -#include +#include -/* GLOBALS ****************************************************************/ +/* GLOBALS *******************************************************************/ +KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]; LARGE_INTEGER KiTimeIncrementReciprocal; UCHAR KiTimeIncrementShiftCount; -LIST_ENTRY KiTimerListHead; -KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]; -#define SYSTEM_TIME_UNITS_PER_MSEC (10000) -/* PRIVATE FUNCTIONS ******************************************************/ +/* PRIVATE FUNCTIONS *********************************************************/ -VOID -NTAPI -KiRemoveTimer(IN PKTIMER Timer) -{ - /* Remove the timer */ - Timer->Header.Inserted = FALSE; - RemoveEntryList(&Timer->TimerListEntry); -} - -/* - * Note: This function is called with the Dispatcher Lock held. - */ BOOLEAN -NTAPI -KiInsertTimer(IN PKTIMER Timer, - IN LARGE_INTEGER DueTime) +FASTCALL +KiInsertTreeTimer(IN PKTIMER Timer, + IN LARGE_INTEGER Interval) { - LARGE_INTEGER SystemTime; - LARGE_INTEGER DifferenceTime; - ULONGLONG InterruptTime; - - /* Set default data */ - Timer->Header.Inserted = TRUE; - Timer->Header.Absolute = FALSE; - if (!Timer->Period) Timer->Header.SignalState = FALSE; + BOOLEAN Inserted = FALSE; + ULONG Hand = 0; + PKSPIN_LOCK_QUEUE LockQueue; + LONGLONG DueTime; + LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime; + PKTIMER_TABLE_ENTRY TimerEntry; /* Convert to relative time if needed */ - if (DueTime.HighPart >= 0) + Timer->Header.Absolute = FALSE; + if (Interval.HighPart >= 0) { /* Get System Time */ KeQuerySystemTime(&SystemTime); /* Do the conversion */ - DifferenceTime.QuadPart = SystemTime.QuadPart - DueTime.QuadPart; + DifferenceTime.QuadPart = SystemTime.QuadPart - Interval.QuadPart; /* Make sure it hasn't already expired */ + Timer->Header.Absolute = TRUE; if (DifferenceTime.HighPart >= 0) { /* Cancel everything */ Timer->Header.SignalState = TRUE; - Timer->Header.Inserted = FALSE; + Timer->Header.Hand = 0; + Timer->DueTime.QuadPart = 0; return FALSE; } /* Set the time as Absolute */ - Timer->Header.Absolute = TRUE; - DueTime = DifferenceTime; + Interval = DifferenceTime; } /* Get the Interrupt Time */ - InterruptTime = KeQueryInterruptTime(); + InterruptTime.QuadPart = KeQueryInterruptTime(); - /* Set the Final Due Time */ - Timer->DueTime.QuadPart = InterruptTime - DueTime.QuadPart; + /* Recalculate due time */ + DueTime = InterruptTime.QuadPart - Interval.QuadPart; + Timer->DueTime.QuadPart = DueTime; - /* Now insert it into the Timer List */ - InsertAscendingList(&KiTimerListHead, - Timer, - KTIMER, - TimerListEntry, - DueTime.QuadPart); - return TRUE; + /* Get the handle */ + Hand = KiComputeTimerTableIndex(DueTime); + Timer->Header.Hand = (UCHAR)Hand; + Timer->Header.Inserted = TRUE; + + /* Acquire the lock */ + LockQueue = KiAcquireTimerLock(Hand); + + /* Insert the timer */ + if (KiInsertTimerTable(Timer, Hand)) + { + /* It was already there, remove it */ + if (RemoveEntryList(&Timer->TimerListEntry)) + { + /* Get the entry and check if it's empty */ + TimerEntry = &KiTimerTableListHead[Hand]; + if (IsListEmpty(&TimerEntry->Entry)) + { + /* Clear the time then */ + TimerEntry->Time.HighPart = 0xFFFFFFFF; + } + } + } + else + { + /* Otherwise, we're now inserted */ + Inserted = TRUE; + } + + /* Release the lock and return insert status */ + return Inserted; } -/* - * We enter this function at IRQL DISPATCH_LEVEL, and with the - * Dispatcher Lock held! - */ -VOID -NTAPI -KiHandleExpiredTimer(IN PKTIMER Timer) +BOOLEAN +FASTCALL +KiInsertTimerTable(IN PKTIMER Timer, + IN ULONG Hand) { - LARGE_INTEGER DueTime; - - /* Set it as Signaled */ - Timer->Header.SignalState = TRUE; - - /* Check if it has any waiters */ - if (!IsListEmpty(&Timer->Header.WaitListHead)) - { - /* Wake them */ - KiWaitTest(Timer, IO_NO_INCREMENT); - } - - /* If the Timer is periodic, reinsert the timer with the new due time */ - if (Timer->Period) - { - /* Reinsert the Timer */ - DueTime.QuadPart = Timer->Period * -SYSTEM_TIME_UNITS_PER_MSEC; - while (!KiInsertTimer(Timer, DueTime)); - } - - /* Check if the Timer has a DPC */ - if (Timer->Dpc) - { - /* Insert the DPC */ - KeInsertQueueDpc(Timer->Dpc, - NULL, - NULL); - } -} - -VOID -NTAPI -KiExpireTimers(IN PKDPC Dpc, - IN PVOID DeferredContext, - IN PVOID SystemArgument1, - IN PVOID SystemArgument2) -{ - PKTIMER Timer; - ULONGLONG InterruptTime; - LIST_ENTRY ExpiredTimerList; + LARGE_INTEGER InterruptTime; + LONGLONG DueTime = Timer->DueTime.QuadPart; + BOOLEAN Expired = FALSE; PLIST_ENTRY ListHead, NextEntry; - KIRQL OldIrql; + PKTIMER CurrentTimer; - /* Initialize the Expired Timer List */ - InitializeListHead(&ExpiredTimerList); + /* Check if the period is zero */ + if (!Timer->Period) Timer->Header.SignalState = FALSE; - /* Lock the Database and Raise IRQL */ - OldIrql = KiAcquireDispatcherLock(); + /* Sanity check */ + ASSERT(Hand == KiComputeTimerTableIndex(DueTime)); - /* Query Interrupt Times */ - InterruptTime = KeQueryInterruptTime(); - - /* Loop through the Timer List */ - ListHead = &KiTimerListHead; - NextEntry = ListHead->Flink; + /* Loop the timer list backwards */ + ListHead = &KiTimerTableListHead[Hand].Entry; + NextEntry = ListHead->Blink; while (NextEntry != ListHead) { /* Get the timer */ - Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); + CurrentTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); - /* Check if we have to Expire it */ - if (InterruptTime < Timer->DueTime.QuadPart) break; + /* Now check if we can fit it before */ + if ((ULONGLONG)DueTime >= CurrentTimer->DueTime.QuadPart) break; - /* Remove it from the Timer List, add it to the Expired List */ - RemoveEntryList(&Timer->TimerListEntry); - InsertTailList(&ExpiredTimerList, &Timer->TimerListEntry); - NextEntry = ListHead->Flink; + /* Keep looping */ + NextEntry = NextEntry->Blink; } - /* Expire the Timers */ - while (ExpiredTimerList.Flink != &ExpiredTimerList) + /* Looped all the list, insert it here and get the interrupt time again */ + InsertHeadList(NextEntry, &Timer->TimerListEntry); + + /* Check if we didn't find it in the list */ + if (NextEntry == ListHead) { - /* Get the Timer */ - Timer = CONTAINING_RECORD(ExpiredTimerList.Flink, - KTIMER, - TimerListEntry); + /* Set the time */ + KiTimerTableListHead[Hand].Time.QuadPart = DueTime; - /* Remove it */ - /// - // GCC IS A BRAINDEAD PIECE OF SHIT. WILL GIVE 5$ FOR EACH DEV KILLED. - /// - Timer->Header.Inserted = FALSE; - RemoveEntryList(&Timer->TimerListEntry); - //KiRemoveTimer(Timer); - - /* Expire it */ - KiHandleExpiredTimer(Timer); + /* Make sure it hasn't expired already */ + InterruptTime.QuadPart = KeQueryInterruptTime(); + if (DueTime <= InterruptTime.QuadPart) Expired = TRUE; } - /* Release Dispatcher Lock */ - KiReleaseDispatcherLock(OldIrql); + /* Return expired state */ + return Expired; +} + +BOOLEAN +FASTCALL +KiSignalTimer(IN PKTIMER Timer) +{ + BOOLEAN RequestInterrupt = FALSE; + PKDPC Dpc = Timer->Dpc; + ULONG Period = Timer->Period; + LARGE_INTEGER Interval, SystemTime; + + /* Set default values */ + Timer->Header.Inserted = FALSE; + Timer->Header.SignalState = TRUE; + + /* Check if the timer has waiters */ + if (!IsListEmpty(&Timer->Header.WaitListHead)) + { + /* Check the type of event */ + if (Timer->Header.Type == TimerNotificationObject) + { + /* Unwait the thread */ + KxUnwaitThread(&Timer->Header, IO_NO_INCREMENT); + } + else + { + /* Otherwise unwait the thread and signal the timer */ + KxUnwaitThreadForEvent((PKEVENT)Timer, IO_NO_INCREMENT); + } + } + + /* Check if we have a period */ + if (Period) + { + /* Calculate the interval and insert the timer */ + Interval.QuadPart = Int32x32To64(Period, -10000); + while (!KiInsertTreeTimer(Timer, Interval)); + } + + /* Check if we have a DPC */ + if (Dpc) + { + /* Insert it in the queue */ + KeQuerySystemTime(&SystemTime); + KeInsertQueueDpc(Dpc, + ULongToPtr(SystemTime.LowPart), + ULongToPtr(SystemTime.HighPart)); + RequestInterrupt = TRUE; + } + + /* Return whether we need to request a DPC interrupt or not */ + return RequestInterrupt; +} + +VOID +FASTCALL +KiCompleteTimer(IN PKTIMER Timer, + IN PKSPIN_LOCK_QUEUE LockQueue) +{ + LIST_ENTRY ListHead; + PKTIMER_TABLE_ENTRY TimerEntry; + BOOLEAN RequestInterrupt = FALSE; + + /* Remove it from the timer list */ + if (RemoveEntryList(&Timer->TimerListEntry)) + { + /* Get the entry and check if it's empty */ + TimerEntry = &KiTimerTableListHead[Timer->Header.Hand]; + if (IsListEmpty(&TimerEntry->Entry)) + { + /* Clear the time then */ + TimerEntry->Time.HighPart = 0xFFFFFFFF; + } + } + + /* Link the timer list to our stack */ + ListHead.Flink = &Timer->TimerListEntry; + ListHead.Blink = &Timer->TimerListEntry; + Timer->TimerListEntry.Flink = &ListHead; + Timer->TimerListEntry.Blink = &ListHead; + + /* Release the timer lock */ + KiReleaseTimerLock(LockQueue); + + /* Acquire dispatcher lock */ + KiAcquireDispatcherLockAtDpcLevel(); + + /* Signal the timer if it's still on our list */ + if (!IsListEmpty(&ListHead)) RequestInterrupt = KiSignalTimer(Timer); + + /* Release the dispatcher lock */ + KiReleaseDispatcherLockFromDpcLevel(); + + /* Request a DPC if needed */ + if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } /* PUBLIC FUNCTIONS **********************************************************/ @@ -200,25 +254,19 @@ KeCancelTimer(IN OUT PKTIMER Timer) KIRQL OldIrql; BOOLEAN Inserted; ASSERT_TIMER(Timer); - ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); /* Lock the Database and Raise IRQL */ OldIrql = KiAcquireDispatcherLock(); /* Check if it's inserted, and remove it if it is */ Inserted = Timer->Header.Inserted; - if (Inserted) - { - /// - // GCC IS A BRAINDEAD PIECE OF SHIT. WILL GIVE 5$ FOR EACH DEV KILLED. - /// - Timer->Header.Inserted = FALSE; - RemoveEntryList(&Timer->TimerListEntry); - //KiRemoveTimer(Timer); - } + if (Inserted) KxRemoveTreeTimer(Timer); /* Release Dispatcher Lock */ KiReleaseDispatcherLock(OldIrql); + + /* Return the old state */ return Inserted; } @@ -289,62 +337,75 @@ KeSetTimerEx(IN OUT PKTIMER Timer, { KIRQL OldIrql; BOOLEAN Inserted; + ULONG Hand = 0; + LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime; + BOOLEAN RequestInterrupt = FALSE; ASSERT_TIMER(Timer); - ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); /* Lock the Database and Raise IRQL */ OldIrql = KiAcquireDispatcherLock(); /* Check if it's inserted, and remove it if it is */ Inserted = Timer->Header.Inserted; - if (Inserted) - { - /// - // GCC IS A BRAINDEAD PIECE OF SHIT. WILL GIVE 5$ FOR EACH DEV KILLED. - /// - Timer->Header.Inserted = FALSE; - RemoveEntryList(&Timer->TimerListEntry); - //KiRemoveTimer(Timer); - } + if (Inserted) KxRemoveTreeTimer(Timer); /* Set Default Timer Data */ Timer->Dpc = Dpc; Timer->Period = Period; - Timer->Header.SignalState = FALSE; - /* Insert it */ - if (!KiInsertTimer(Timer, DueTime)) + /* Convert to relative time if needed */ + Timer->Header.Absolute = FALSE; + if (DueTime.HighPart >= 0) { - /* Check if it has any waiters */ - if (!IsListEmpty(&Timer->Header.WaitListHead)) + /* Get System Time */ + KeQuerySystemTime(&SystemTime); + + /* Do the conversion */ + DifferenceTime.QuadPart = SystemTime.QuadPart - DueTime.QuadPart; + + /* Make sure it hasn't already expired */ + Timer->Header.Absolute = TRUE; + if (DifferenceTime.HighPart >= 0) { - /* Wake them */ - KiWaitTest(Timer, IO_NO_INCREMENT); + /* Cancel everything */ + Timer->Header.SignalState = TRUE; + Timer->Header.Hand = 0; + Timer->DueTime.QuadPart = 0; + + /* Signal the timer */ + RequestInterrupt = KiSignalTimer(Timer); + + /* Release the dispatcher lock */ + KiReleaseDispatcherLockFromDpcLevel(); + + /* Check if we need to do an interrupt */ + if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } - /* Check if the Timer has a DPC */ - if (Dpc) - { - /* Insert the DPC */ - KeInsertQueueDpc(Timer->Dpc, - NULL, - NULL); - } - - /* Check if the Timer is periodic */ - if (Timer->Period) - { - /* Reinsert the Timer */ - DueTime.QuadPart = Timer->Period * -SYSTEM_TIME_UNITS_PER_MSEC; - while (!KiInsertTimer(Timer, DueTime)); - } + /* Set the time as Absolute */ + DueTime = DifferenceTime; } + /* Get the Interrupt Time */ + InterruptTime.QuadPart = KeQueryInterruptTime(); + + /* Recalculate due time */ + Timer->DueTime.QuadPart = InterruptTime.QuadPart - DueTime.QuadPart; + + /* Get the handle */ + Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart); + Timer->Header.Hand = (UCHAR)Hand; + Timer->Header.Inserted = TRUE; + + /* Insert the timer */ + Timer->Header.SignalState = FALSE; + KxInsertTimer(Timer, Hand); + /* Release Dispatcher Lock */ - KiReleaseDispatcherLock(OldIrql); + KiExitDispatcher(OldIrql); /* Return old state */ return Inserted; } -/* EOF */ diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index 19ec2498323..dabe787ec23 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -77,13 +77,7 @@ KiUnlinkThread(IN PKTHREAD Thread, /* Check if there's a Thread Timer */ Timer = &Thread->Timer; - if (Timer->Header.Inserted) - { - /* Remove the timer */ - Timer->Header.Inserted = FALSE; - RemoveEntryList(&Timer->TimerListEntry); - //KiRemoveTimer(Timer); - } + if (Timer->Header.Inserted) KxRemoveTreeTimer(Timer); /* Increment the Queue's active threads */ if (Thread->Queue) Thread->Queue->CurrentCount++; @@ -219,6 +213,7 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, BOOLEAN Swappable; PLARGE_INTEGER OriginalDueTime; LARGE_INTEGER DueTime, NewDueTime, InterruptTime; + ULONG Hand = 0; /* If this is a user-mode wait of 0 seconds, yield execution */ if (!(Interval->QuadPart) && (WaitMode != KernelMode)) @@ -285,7 +280,7 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, /* Insert the timer and swap the thread */ ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL); KiSetThreadSwapBusy(Thread); - KiInsertWaitTimer(Timer); + KxInsertTimer(Timer, Hand); WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb()); /* Check if were swapped ok */ @@ -350,6 +345,7 @@ KeWaitForSingleObject(IN PVOID Object, BOOLEAN Swappable; LARGE_INTEGER DueTime, NewDueTime, InterruptTime; PLARGE_INTEGER OriginalDueTime = Timeout; + ULONG Hand = 0; /* Check if the lock is already held */ if (!Thread->WaitNext) goto WaitStart; @@ -449,7 +445,7 @@ KeWaitForSingleObject(IN PVOID Object, if (Timeout) { /* Insert it */ - KiInsertWaitTimer(Timer); + KxInsertTimer(Timer, Hand); } else { @@ -515,7 +511,7 @@ KeWaitForMultipleObjects(IN ULONG Count, BOOLEAN Swappable; PLARGE_INTEGER OriginalDueTime = Timeout; LARGE_INTEGER DueTime, NewDueTime, InterruptTime; - ULONG Index; + ULONG Index, Hand = 0; /* Make sure the Wait Count is valid */ if (!WaitBlockArray) @@ -726,7 +722,7 @@ KeWaitForMultipleObjects(IN ULONG Count, if (Timeout) { /* Insert it */ - KiInsertWaitTimer(Timer); + KxInsertTimer(Timer, Hand); } else {