mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
- Implement KiUnlinkThread to unlink a thread from its wait blocks, handle queue and timer activation/removal.
- Don't play with priorities in KiAbortWaitThread anymore, since we'll soon support Win2003 delayed "adjust increment" functionality, so that the code is not repeated many times. - Rename KiAbortWaitThread to KiUnwaitThread, make it use KiUnlinkThread and delayed adjustment. - Implement KxUnwaitThread and KxUnwaitThreadForEvent, optimized versions of KiWaitTest that can be used in special circumstances (notification events, thread termination, process signalling). - Optimize KeSetEvent by handling signaled notification events without acquiring the dispatcher lock, and by using new inlined routines described above. - Reimplement KeSetEventBoostPriority properly to actually do boosting. - Fixup KeRundownQueue with a more typical/proper LIST_ENTRY loop. - Let me know if you see regressions... svn path=/trunk/; revision=24102
This commit is contained in:
parent
c440454c10
commit
d53352c677
9 changed files with 201 additions and 120 deletions
|
@ -455,6 +455,13 @@ KiDispatcherObjectWake(
|
|||
KPRIORITY increment
|
||||
);
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiUnlinkThread(
|
||||
IN PKTHREAD Thread,
|
||||
IN NTSTATUS WaitStatus
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KeExpireTimers(
|
||||
|
@ -474,7 +481,7 @@ KiTestAlert(VOID);
|
|||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiAbortWaitThread(
|
||||
KiUnwaitThread(
|
||||
IN PKTHREAD Thread,
|
||||
IN NTSTATUS WaitStatus,
|
||||
IN KPRIORITY Increment
|
||||
|
|
|
@ -292,6 +292,98 @@ KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime,
|
|||
} \
|
||||
}
|
||||
|
||||
//
|
||||
// Unwaits a Thread
|
||||
//
|
||||
FORCEINLINE
|
||||
VOID
|
||||
KxUnwaitThread(IN DISPATCHER_HEADER *Object,
|
||||
IN KPRIORITY Increment)
|
||||
{
|
||||
PLIST_ENTRY WaitEntry, WaitList;
|
||||
PKWAIT_BLOCK CurrentWaitBlock;
|
||||
PKTHREAD WaitThread;
|
||||
ULONG WaitKey;
|
||||
|
||||
/* Loop the Wait Entries */
|
||||
WaitList = &Object->WaitListHead;
|
||||
WaitEntry = WaitList->Flink;
|
||||
do
|
||||
{
|
||||
/* Get the current wait block */
|
||||
CurrentWaitBlock = CONTAINING_RECORD(WaitEntry,
|
||||
KWAIT_BLOCK,
|
||||
WaitListEntry);
|
||||
|
||||
/* Get the waiting thread */
|
||||
WaitThread = CurrentWaitBlock->Thread;
|
||||
|
||||
/* Check the current Wait Mode */
|
||||
if (CurrentWaitBlock->WaitType == WaitAny)
|
||||
{
|
||||
/* Use the actual wait key */
|
||||
WaitKey = CurrentWaitBlock->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 CurrentWaitBlock;
|
||||
PKTHREAD WaitThread;
|
||||
|
||||
/* Loop the Wait Entries */
|
||||
WaitList = &Event->Header.WaitListHead;
|
||||
WaitEntry = WaitList->Flink;
|
||||
do
|
||||
{
|
||||
/* Get the current wait block */
|
||||
CurrentWaitBlock = CONTAINING_RECORD(WaitEntry,
|
||||
KWAIT_BLOCK,
|
||||
WaitListEntry);
|
||||
|
||||
/* Get the waiting thread */
|
||||
WaitThread = CurrentWaitBlock->Thread;
|
||||
|
||||
/* Check the current Wait Mode */
|
||||
if (CurrentWaitBlock->WaitType == WaitAny)
|
||||
{
|
||||
/* Un-signal it */
|
||||
Event->Header.SignalState = 0;
|
||||
|
||||
/* Un-signal the event and unwait the thread */
|
||||
KiUnwaitThread(WaitThread, CurrentWaitBlock->WaitKey, Increment);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unwait the thread with STATUS_KERNEL_APC */
|
||||
KiUnwaitThread(WaitThread, STATUS_KERNEL_APC, Increment);
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
WaitEntry = WaitList->Flink;
|
||||
} while (WaitEntry != WaitList);
|
||||
}
|
||||
|
||||
//
|
||||
// Spinlock Acquisition at IRQL >= DISPATCH_LEVEL
|
||||
//
|
||||
|
|
|
@ -239,7 +239,7 @@ KiInsertQueueApc(IN PKAPC Apc,
|
|||
|
||||
/* Wake up the thread */
|
||||
Unwait:
|
||||
KiAbortWaitThread(Thread, Status, PriorityBoost);
|
||||
KiUnwaitThread(Thread, Status, PriorityBoost);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -978,3 +978,4 @@ KeAreAllApcsDisabled(VOID)
|
|||
(KeGetCurrentIrql() >= APC_LEVEL)) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -166,19 +166,29 @@ KeSetEvent(IN PKEVENT Event,
|
|||
ASSERT_EVENT(Event);
|
||||
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
||||
|
||||
/*
|
||||
* Check if this is an signaled notification event without an upcoming wait.
|
||||
* In this case, we can immediately return TRUE, without locking.
|
||||
*/
|
||||
if ((Event->Header.Type == NotificationEvent) &&
|
||||
(Event->Header.SignalState == 1) &&
|
||||
!(Wait))
|
||||
{
|
||||
/* Return the signal state (TRUE/Signalled) */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Lock the Dispathcer Database */
|
||||
OldIrql = KiAcquireDispatcherLock();
|
||||
|
||||
/* Save the Previous State */
|
||||
PreviousState = Event->Header.SignalState;
|
||||
|
||||
/* Check if we have stuff in the Wait Queue */
|
||||
if (IsListEmpty(&Event->Header.WaitListHead))
|
||||
{
|
||||
/* Set the Event to Signaled */
|
||||
Event->Header.SignalState = 1;
|
||||
}
|
||||
else
|
||||
/* Set the Event to Signaled */
|
||||
Event->Header.SignalState = 1;
|
||||
|
||||
/* Check if the event just became signaled now, and it has waiters */
|
||||
if (!(PreviousState) && !(IsListEmpty(&Event->Header.WaitListHead)))
|
||||
{
|
||||
/* Get the Wait Block */
|
||||
WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
|
||||
|
@ -186,22 +196,15 @@ KeSetEvent(IN PKEVENT Event,
|
|||
WaitListEntry);
|
||||
|
||||
/* Check the type of event */
|
||||
if ((Event->Header.Type == NotificationEvent) || (WaitBlock->WaitType == WaitAll))
|
||||
if (Event->Header.Type == NotificationEvent)
|
||||
{
|
||||
/* Check if it wasn't signaled */
|
||||
if (!PreviousState)
|
||||
{
|
||||
/* We must do a full wait satisfaction */
|
||||
Event->Header.SignalState = 1;
|
||||
KiWaitTest(&Event->Header, Increment);
|
||||
}
|
||||
/* Unwait the thread */
|
||||
KxUnwaitThread(&Event->Header, Increment);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We can satisfy wait simply by waking the thread */
|
||||
KiAbortWaitThread(WaitBlock->Thread,
|
||||
WaitBlock->WaitKey,
|
||||
Increment);
|
||||
/* Otherwise unwait the thread and unsignal the event */
|
||||
KxUnwaitThreadForEvent(Event, Increment);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,38 +232,60 @@ KeSetEvent(IN PKEVENT Event,
|
|||
VOID
|
||||
NTAPI
|
||||
KeSetEventBoostPriority(IN PKEVENT Event,
|
||||
IN PKTHREAD *Thread OPTIONAL)
|
||||
IN PKTHREAD *WaitingThread OPTIONAL)
|
||||
{
|
||||
PKTHREAD WaitingThread;
|
||||
KIRQL OldIrql;
|
||||
PKWAIT_BLOCK WaitBlock;
|
||||
PKTHREAD Thread = KeGetCurrentThread(), WaitThread;
|
||||
ASSERT_EVENT(Event);
|
||||
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
||||
|
||||
//
|
||||
// FIXME: This is half-broken, there's no boosting!
|
||||
//
|
||||
|
||||
/* Acquire Dispatcher Database Lock */
|
||||
OldIrql = KiAcquireDispatcherLock();
|
||||
|
||||
/* If our wait list is empty, then signal the event and return */
|
||||
/* Check if the list is empty */
|
||||
if (IsListEmpty(&Event->Header.WaitListHead))
|
||||
{
|
||||
/* Set the Event to Signaled */
|
||||
Event->Header.SignalState = 1;
|
||||
|
||||
/* Return */
|
||||
KiReleaseDispatcherLock(OldIrql);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the Wait Block */
|
||||
WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
|
||||
KWAIT_BLOCK,
|
||||
WaitListEntry);
|
||||
|
||||
/* Check if this is a WaitAll */
|
||||
if (WaitBlock->WaitType == WaitAll)
|
||||
{
|
||||
/* Set the Event to Signaled */
|
||||
Event->Header.SignalState = 1;
|
||||
|
||||
/* Unwait the thread and unsignal the event */
|
||||
KxUnwaitThreadForEvent(Event, EVENT_INCREMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the waiting thread */
|
||||
WaitingThread = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
|
||||
KWAIT_BLOCK,
|
||||
WaitListEntry)->Thread;
|
||||
/* Return waiting thread to caller */
|
||||
WaitThread = WaitBlock->Thread;
|
||||
if (WaitingThread) *WaitingThread = WaitThread;
|
||||
|
||||
/* Return it to caller if requested */
|
||||
if (Thread) *Thread = WaitingThread;
|
||||
/* Calculate new priority */
|
||||
Thread->Priority = KiComputeNewPriority(Thread);
|
||||
|
||||
/* Reset the Quantum and Unwait the Thread */
|
||||
WaitingThread->Quantum = WaitingThread->QuantumReset;
|
||||
KiAbortWaitThread(WaitingThread, STATUS_SUCCESS, EVENT_INCREMENT);
|
||||
/* Unlink the waiting thread */
|
||||
KiUnlinkThread(WaitThread, STATUS_WAIT_0);
|
||||
|
||||
/* Request priority boosting */
|
||||
WaitThread->AdjustIncrement = Thread->Priority;
|
||||
WaitThread->AdjustReason = 2;
|
||||
|
||||
/* Ready the thread */
|
||||
KiReadyThread(WaitThread);
|
||||
}
|
||||
|
||||
/* Release the Dispatcher Database Lock */
|
||||
|
|
|
@ -142,7 +142,7 @@ KeSignalGateBoostPriority(IN PKGATE Gate)
|
|||
if (WaitThread->Queue) WaitThread->Queue->CurrentCount++;
|
||||
|
||||
/* FIXME: This isn't really correct!!! */
|
||||
KiAbortWaitThread(WaitThread, WaitStatus, EVENT_INCREMENT);
|
||||
KiUnwaitThread(WaitThread, WaitStatus, EVENT_INCREMENT);
|
||||
}
|
||||
|
||||
/* Exit the dispatcher */
|
||||
|
|
|
@ -208,8 +208,8 @@ KeSetProcess(IN PKPROCESS Process,
|
|||
if (!(OldState) &&
|
||||
!(IsListEmpty(&Process->Header.WaitListHead)))
|
||||
{
|
||||
/* Satisfy waits */
|
||||
KiWaitTest((PVOID)Process, Increment);
|
||||
/* Unwait the threads */
|
||||
KxUnwaitThread(&Process->Header, Increment);
|
||||
}
|
||||
|
||||
/* Release Dispatcher Database */
|
||||
|
|
|
@ -57,7 +57,7 @@ KiWakeQueue(IN PKQUEUE Queue)
|
|||
KWAIT_BLOCK,
|
||||
WaitListEntry);
|
||||
Thread = WaitBlock->Thread;
|
||||
KiAbortWaitThread(Thread, (NTSTATUS)QueueEntry, IO_NO_INCREMENT);
|
||||
KiUnwaitThread(Thread, (NTSTATUS)QueueEntry, IO_NO_INCREMENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -401,7 +401,7 @@ KeRemoveQueue(IN PKQUEUE Queue,
|
|||
if (!KiInsertTimer(Timer, *Timeout))
|
||||
{
|
||||
/* FIXME */
|
||||
DPRINT1("If you see thie message contact Alex ASAP\n");
|
||||
DPRINT1("If you see this message contact Alex ASAP\n");
|
||||
KEBUGCHECK(0);
|
||||
}
|
||||
|
||||
|
@ -469,7 +469,7 @@ PLIST_ENTRY
|
|||
NTAPI
|
||||
KeRundownQueue(IN PKQUEUE Queue)
|
||||
{
|
||||
PLIST_ENTRY EnumEntry;
|
||||
PLIST_ENTRY ListHead, NextEntry;
|
||||
PLIST_ENTRY FirstEntry = NULL;
|
||||
PKTHREAD Thread;
|
||||
KIRQL OldIrql;
|
||||
|
@ -488,16 +488,21 @@ KeRundownQueue(IN PKQUEUE Queue)
|
|||
}
|
||||
|
||||
/* Unlink threads and clear their Thread->Queue */
|
||||
while (!IsListEmpty(&Queue->ThreadListHead))
|
||||
ListHead = &Queue->ThreadListHead;
|
||||
NextEntry = ListHead->Flink;
|
||||
while (ListHead != NextEntry)
|
||||
{
|
||||
/* Get the Entry and Remove it */
|
||||
EnumEntry = RemoveHeadList(&Queue->ThreadListHead);
|
||||
|
||||
/* Get the Entry's Thread */
|
||||
Thread = CONTAINING_RECORD(EnumEntry, KTHREAD, QueueListEntry);
|
||||
Thread = CONTAINING_RECORD(NextEntry, KTHREAD, QueueListEntry);
|
||||
|
||||
/* Kill its Queue */
|
||||
Thread->Queue = NULL;
|
||||
|
||||
/* Remove this entry */
|
||||
RemoveEntryList(NextEntry);
|
||||
|
||||
/* Get the next entry */
|
||||
NextEntry = NextEntry->Flink;
|
||||
}
|
||||
|
||||
/* Release the lock and return */
|
||||
|
|
|
@ -100,7 +100,7 @@ KeAlertResumeThread(IN PKTHREAD Thread)
|
|||
if ((Thread->State == Waiting) && (Thread->Alertable))
|
||||
{
|
||||
/* Abort the wait */
|
||||
KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
|
||||
KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -157,7 +157,7 @@ KeAlertThread(IN PKTHREAD Thread,
|
|||
(Thread->Alertable))
|
||||
{
|
||||
/* Abort the wait to alert the thread */
|
||||
KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
|
||||
KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1311,10 +1311,10 @@ KeTerminateThread(IN KPRIORITY Increment)
|
|||
|
||||
/* Signal the thread */
|
||||
Thread->DispatcherHeader.SignalState = TRUE;
|
||||
if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE)
|
||||
if (!IsListEmpty(&Thread->DispatcherHeader.WaitListHead))
|
||||
{
|
||||
/* Satisfy waits */
|
||||
KiWaitTest((PVOID)Thread, Increment);
|
||||
/* Unwait the threads */
|
||||
KxUnwaitThread(&Thread->DispatcherHeader, Increment);
|
||||
}
|
||||
|
||||
/* Remove the thread from the list */
|
||||
|
|
|
@ -13,10 +13,6 @@
|
|||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* GLOBALS ******************************************************************/
|
||||
|
||||
KSPIN_LOCK DispatcherDatabaseLock;
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
VOID
|
||||
|
@ -110,7 +106,7 @@ KiWaitTest(IN PVOID ObjectPointer,
|
|||
}
|
||||
|
||||
/* All waits satisfied, unwait the thread */
|
||||
KiAbortWaitThread(WaitThread, CurrentWaitBlock->WaitKey, Increment);
|
||||
KiUnwaitThread(WaitThread, CurrentWaitBlock->WaitKey, Increment);
|
||||
|
||||
SkipUnwait:
|
||||
/* Next entry */
|
||||
|
@ -118,16 +114,13 @@ SkipUnwait:
|
|||
}
|
||||
}
|
||||
|
||||
/* Must be called with the dispatcher lock held */
|
||||
VOID
|
||||
FASTCALL
|
||||
KiAbortWaitThread(IN PKTHREAD Thread,
|
||||
IN NTSTATUS WaitStatus,
|
||||
IN KPRIORITY Increment)
|
||||
KiUnlinkThread(IN PKTHREAD Thread,
|
||||
IN NTSTATUS WaitStatus)
|
||||
{
|
||||
PKWAIT_BLOCK WaitBlock;
|
||||
PKTIMER Timer;
|
||||
LONG NewPriority;
|
||||
|
||||
/* Update wait status */
|
||||
Thread->WaitStatus |= WaitStatus;
|
||||
|
@ -158,64 +151,22 @@ KiAbortWaitThread(IN PKTHREAD Thread,
|
|||
|
||||
/* Increment the Queue's active threads */
|
||||
if (Thread->Queue) Thread->Queue->CurrentCount++;
|
||||
}
|
||||
|
||||
/* Check if this is a non-RT thread */
|
||||
if (Thread->Priority < LOW_REALTIME_PRIORITY)
|
||||
{
|
||||
/* Check if boosting is enabled and we can boost */
|
||||
if (!(Thread->DisableBoost) && !(Thread->PriorityDecrement))
|
||||
{
|
||||
/* We can boost, so calculate the new priority */
|
||||
NewPriority = Thread->BasePriority + Increment;
|
||||
if (NewPriority > Thread->Priority)
|
||||
{
|
||||
/* Make sure the new priority wouldn't push the thread to RT */
|
||||
if (NewPriority >= LOW_REALTIME_PRIORITY)
|
||||
{
|
||||
/* Set it just before the RT zone */
|
||||
Thread->Priority = LOW_REALTIME_PRIORITY - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, set our calculated priority */
|
||||
Thread->Priority = NewPriority;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Must be called with the dispatcher lock held */
|
||||
VOID
|
||||
FASTCALL
|
||||
KiUnwaitThread(IN PKTHREAD Thread,
|
||||
IN NTSTATUS WaitStatus,
|
||||
IN KPRIORITY Increment)
|
||||
{
|
||||
/* Unlink the thread */
|
||||
KiUnlinkThread(Thread, WaitStatus);
|
||||
|
||||
/* Check if this is a high-priority thread */
|
||||
if (Thread->BasePriority >= 14)
|
||||
{
|
||||
/* It is, simply reset the quantum */
|
||||
Thread->Quantum = Thread->QuantumReset;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, decrease quantum */
|
||||
Thread->Quantum--;
|
||||
if (Thread->Quantum <= 0)
|
||||
{
|
||||
/* We've went below 0, reset it */
|
||||
Thread->Quantum = Thread->QuantumReset;
|
||||
|
||||
/* Apply per-quantum priority decrement */
|
||||
Thread->Priority -= (Thread->PriorityDecrement + 1);
|
||||
if (Thread->Priority < Thread->BasePriority)
|
||||
{
|
||||
/* We've went too low, reset it */
|
||||
Thread->Priority = Thread->BasePriority;
|
||||
}
|
||||
|
||||
/* Delete per-quantum decrement */
|
||||
Thread->PriorityDecrement = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For real time threads, just reset the quantum */
|
||||
Thread->Quantum = Thread->QuantumReset;
|
||||
}
|
||||
/* Tell the scheduler do to the increment when it readies the thread */
|
||||
ASSERT(Increment >= 0);
|
||||
Thread->AdjustIncrement = (SCHAR)Increment;
|
||||
Thread->AdjustReason = 1;
|
||||
|
||||
/* Reschedule the Thread */
|
||||
KiReadyThread(Thread);
|
||||
|
@ -794,7 +745,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
|
|||
WaitBlock->Object = CurrentObject;
|
||||
WaitBlock->Thread = CurrentThread;
|
||||
WaitBlock->WaitKey = (USHORT)WaitIndex;
|
||||
WaitBlock->WaitType = (USHORT)WaitType;
|
||||
WaitBlock->WaitType = (UCHAR)WaitType;
|
||||
WaitBlock->NextWaitBlock = WaitBlock + 1;
|
||||
|
||||
/* Move to the next Wait Block */
|
||||
|
|
Loading…
Reference in a new issue