- Optimized the dispatcher lock. It is now gone on non-SMP systems and IRQL is raised or lowered instead.

- Made inlined functions in ke/wait.c macros, because they weren't being inlined.
- Created separate cases for satisfying mutant, non-mutant and generic objects, to optimize wait satisfaction.
- Fixed some places which werne't setting the dispatcher header's size member correctly.
- Fixed formatting in ke/wait.c
- Fixed a case in KiCheckAlertability: we also need to check if the thread is alerted in Kernel-Mode, even if the wait mode given was user and user-mode is not alerted.
- Fixed signaling checks across the wait code and removed KiCheckIfObjectSignaled. We must not consider the mutant as signaled if SignalState is = 1.
- Fix code to check if the wait blocks' status is STATUS_TIMEOUT, because we do not need to check for signal state in that case.
- Removed the exports for internal dispatcher lock routines.


** Thanks to Waxdragon for stress-testing this for an hour :)

svn path=/trunk/; revision=20568
This commit is contained in:
Alex Ionescu 2006-01-05 04:26:55 +00:00
parent f58996b3e9
commit 5e6fa26231
6 changed files with 453 additions and 424 deletions

View file

@ -44,30 +44,173 @@ extern ULONG_PTR KERNEL_BASE;
/* MACROS *************************************************************************/
#define KeEnterCriticalRegion() \
{ \
PKTHREAD _Thread = KeGetCurrentThread(); \
if (_Thread) _Thread->KernelApcDisable--; \
/*
* On UP machines, we don't actually have a spinlock, we merely raise
* IRQL to DPC level.
*/
#ifndef CONFIG_SMP
#define KeInitializeDispatcher()
#define KeAcquireDispatcherDatabaseLock() KeRaiseIrqlToDpcLevel();
#define KeAcquireDispatcherDatabaseLockAtDpcLevel()
#define KeReleaseDispatcherDatabaseLockFromDpcLevel()
#else
#define KeInitializeDispatcher() KeInitializeSpinLock(&DispatcherDatabaseLock);
#define KeAcquireDispatcherDatabaseLock() KfAcquireSpinLock(&DispatcherDatabaseLock);
#define KeAcquireDispatcherDatabaseLockAtDpcLevel() \
KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock);
#define KeReleaseDispatcherDatabaseLockFromDpcLevel() \
KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock);
#endif
/* The following macro initializes a dispatcher object's header */
#define KeInitializeDispatcherHeader(Header, t, s, State) \
{ \
(Header)->Type = t; \
(Header)->Absolute = 0; \
(Header)->Inserted = 0; \
(Header)->Size = s; \
(Header)->SignalState = State; \
InitializeListHead(&((Header)->WaitListHead)); \
}
#define KeLeaveCriticalRegion() \
{ \
PKTHREAD _Thread = KeGetCurrentThread(); \
if((_Thread) && (++_Thread->KernelApcDisable == 0)) \
{ \
if (!IsListEmpty(&_Thread->ApcState.ApcListHead[KernelMode]) && \
(_Thread->SpecialApcDisable == 0)) \
{ \
KiCheckForKernelApcDelivery(); \
} \
} \
/* The following macro 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 -= (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, \
&(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--; \
} \
}
/* The following macro 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 -= (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, \
&(Object)->MutantListEntry); \
} \
}
/* The following macro satisfies the wait of any nonmutant dispatcher object */
#define KiSatisfyNonMutantWait(Object, Thread) \
{ \
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--; \
} \
}
/* The following macro satisfies multiple objects in a wait state */
#define KiSatisifyMultipleObjectWaits(FirstBlock) \
{ \
PKWAIT_BLOCK WaitBlock = FirstBlock; \
PKTHREAD WaitThread = WaitBlock->Thread; \
\
/* Loop through all the Wait Blocks, and wake each Object */ \
do \
{ \
/* Make sure it hasn't timed out */ \
if (WaitBlock->WaitKey != STATUS_TIMEOUT) \
{ \
/* Wake the Object */ \
KiSatisfyObjectWait((PKMUTANT)WaitBlock->Object, WaitThread); \
} \
\
/* Move to the next block */ \
WaitBlock = WaitBlock->NextWaitBlock; \
} while (WaitBlock != FirstBlock); \
}
extern KSPIN_LOCK DispatcherDatabaseLock;
#define KeEnterCriticalRegion() \
{ \
PKTHREAD _Thread = KeGetCurrentThread(); \
if (_Thread) _Thread->KernelApcDisable--; \
}
#define KeLeaveCriticalRegion() \
{ \
PKTHREAD _Thread = KeGetCurrentThread(); \
if((_Thread) && (++_Thread->KernelApcDisable == 0)) \
{ \
if (!IsListEmpty(&_Thread->ApcState.ApcListHead[KernelMode]) && \
(_Thread->SpecialApcDisable == 0)) \
{ \
KiCheckForKernelApcDelivery(); \
} \
} \
}
#define KEBUGCHECKWITHTF(a,b,c,d,e,f) \
DbgPrint("KeBugCheckWithTf at %s:%i\n",__FILE__,__LINE__), KeBugCheckWithTf(a,b,c,d,e,f)
#define MAXIMUM_PROCESSORS 32
DbgPrint("KeBugCheckWithTf at %s:%i\n",__FILE__,__LINE__), \
KeBugCheckWithTf(a,b,c,d,e,f)
/* INTERNAL KERNEL FUNCTIONS ************************************************/
@ -243,26 +386,10 @@ KiExpireTimers(
PVOID SystemArgument2
);
KIRQL
__inline
FASTCALL
KeAcquireDispatcherDatabaseLock(VOID);
VOID
__inline
FASTCALL
KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID);
VOID
__inline
FASTCALL
KeReleaseDispatcherDatabaseLock(KIRQL Irql);
VOID
__inline
FASTCALL
KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID);
VOID
STDCALL
KeInitializeThread(
@ -312,16 +439,6 @@ KeExpireTimers(
PVOID Arg3
);
VOID
__inline
FASTCALL
KeInitializeDispatcherHeader(
DISPATCHER_HEADER* Header,
ULONG Type,
ULONG Size,
ULONG SignalState
);
VOID
NTAPI
KeDumpStackFrames(PULONG Frame);
@ -362,14 +479,6 @@ KiInsertTimer(
LARGE_INTEGER DueTime
);
VOID
__inline
FASTCALL
KiSatisfyObjectWait(
PDISPATCHER_HEADER Object,
PKTHREAD Thread
);
BOOLEAN
__inline
FASTCALL
@ -378,15 +487,10 @@ KiIsObjectSignaled(
PKTHREAD Thread
);
VOID
__inline
FASTCALL
KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock);
VOID
FASTCALL
KiWaitTest(
PDISPATCHER_HEADER Object,
PVOID Object,
KPRIORITY Increment
);
@ -506,11 +610,6 @@ VOID
NTAPI
KeInitDispatcher(VOID);
VOID
__inline
FASTCALL
KeInitializeDispatcher(VOID);
VOID
NTAPI
KiInitializeSystemClock(VOID);

View file

@ -21,6 +21,8 @@
/* GLOBALS ****************************************************************/
.extern _DispatcherDatabaseLock
/* FUNCTIONS ****************************************************************/
/*++
@ -244,7 +246,10 @@ SameProcess:
pop [ebx+KPCR_EXCEPTION_LIST]
/* Return */
call @KeReleaseDispatcherDatabaseLockFromDpcLevel@0
//#ifdef CONFIG_SMP
mov ecx, _DispatcherDatabaseLock
call @KefReleaseSpinLockFromDpcLevel@4
//#endif
ret
/*++

View file

@ -819,7 +819,7 @@ KeInitializeThread(PKPROCESS Process,
DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread, Process);
KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
ThreadObject,
sizeof(KTHREAD),
sizeof(KTHREAD) / sizeof(LONG),
FALSE);
DPRINT("Thread Header Created. SystemRoutine: %x, StartRoutine: %x with Context: %x\n",

View file

@ -2,7 +2,7 @@
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ke/wait.c
* PURPOSE: Manages dispatch level wait-related code
* PURPOSE: Manages waiting for Dispatcher Objects
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* Gunnar Dalsnes
*/
@ -16,7 +16,7 @@
/* GLOBALS ******************************************************************/
static KSPIN_LOCK DispatcherDatabaseLock;
KSPIN_LOCK DispatcherDatabaseLock;
/* Tells us if the Timer or Event is a Syncronization or Notification Object */
#define TIMER_OR_EVENT_TYPE 0x7L
@ -30,38 +30,58 @@ BOOLEAN
__inline
FASTCALL
KiCheckAlertability(BOOLEAN Alertable,
PKTHREAD CurrentThread,
PKTHREAD Thread,
KPROCESSOR_MODE WaitMode,
PNTSTATUS Status)
{
/* At this point, we have to do a wait, so make sure we can make the thread Alertable if requested */
if (Alertable) {
/*
* At this point, we have to do a wait, so make sure we can make
* the thread Alertable if requested.
*/
if (Alertable)
{
/* If the Thread is Alerted, set the Wait Status accordingly */
if (CurrentThread->Alerted[(int)WaitMode]) {
CurrentThread->Alerted[(int)WaitMode] = FALSE;
DPRINT("Thread was Alerted\n");
if (Thread->Alerted[(int)WaitMode])
{
Thread->Alerted[(int)WaitMode] = FALSE;
DPRINT("Thread was Alerted in the specified Mode\n");
*Status = STATUS_ALERTED;
return TRUE;
/* If there are User APCs Pending, then we can't really be alertable */
} else if ((!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])) &&
(WaitMode != KernelMode)) {
}
else if ((WaitMode != KernelMode) &&
(!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
{
/* If there are User APCs Pending, then we can't really be alertable */
DPRINT("APCs are Pending\n");
CurrentThread->ApcState.UserApcPending = TRUE;
Thread->ApcState.UserApcPending = TRUE;
*Status = STATUS_USER_APC;
return TRUE;
}
/* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */
} else if ((CurrentThread->ApcState.UserApcPending) && (WaitMode != KernelMode)) {
DPRINT("APCs are Pending\n");
*Status = STATUS_USER_APC;
else if (Thread->Alerted[KernelMode])
{
/*
* The thread is not alerted in the mode given, but it is alerted
* in kernel-mode.
*/
Thread->Alerted[KernelMode] = FALSE;
DPRINT("Thread was Alerted in Kernel-Mode\n");
*Status = STATUS_ALERTED;
return TRUE;
}
}
else if ((WaitMode != KernelMode) &&
(Thread->ApcState.UserApcPending))
{
/*
* If there are User APCs Pending and we are waiting in usermode,
* then we must notify the caller
*/
DPRINT("APCs are Pending\n");
*Status = STATUS_USER_APC;
return TRUE;
}
/* Stay in the loop */
return FALSE;
}
@ -90,14 +110,14 @@ KeDelayExecutionThread(KPROCESSOR_MODE WaitMode,
DPRINT("Entering KeDelayExecutionThread\n");
/* Check if the lock is already held */
if (CurrentThread->WaitNext) {
if (CurrentThread->WaitNext)
{
/* Lock is held, disable Wait Next */
DPRINT("Lock is held\n");
CurrentThread->WaitNext = FALSE;
} else {
}
else
{
/* Lock not held, acquire it */
DPRINT("Lock is not held, acquiring\n");
CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
@ -107,11 +127,10 @@ KeDelayExecutionThread(KPROCESSOR_MODE WaitMode,
TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
/* Start Wait Loop */
do {
/* We are going to wait no matter what (that's the point), so test Alertability */
if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status))
break;
do
{
/* Chceck if we can do an alertable wait, if requested */
if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status)) break;
/* Set Timer */
ThreadTimer = &CurrentThread->Timer;
@ -129,30 +148,31 @@ KeDelayExecutionThread(KPROCESSOR_MODE WaitMode,
InsertTailList(&ThreadTimer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry);
/* Insert the Timer into the Timer Lists and enable it */
if (!KiInsertTimer(ThreadTimer, *Interval)) {
if (!KiInsertTimer(ThreadTimer, *Interval))
{
/* FIXME: The timer already expired, we should find a new ready thread */
Status = STATUS_SUCCESS;
break;
}
/* Handle Kernel Queues */
if (CurrentThread->Queue) {
if (CurrentThread->Queue)
{
DPRINT("Waking Queue\n");
KiWakeQueue(CurrentThread->Queue);
}
/* Block the Thread */
DPRINT("Blocking the Thread: %d, %d, %x\n", Alertable, WaitMode, KeGetCurrentThread());
DPRINT("Blocking the Thread: %d, %d, %x\n",
Alertable, WaitMode, KeGetCurrentThread());
KiBlockThread(&Status,
Alertable,
WaitMode,
DelayExecution);
/* Check if we were executing an APC or if we timed out */
if (Status != STATUS_KERNEL_APC) {
if (Status != STATUS_KERNEL_APC)
{
/* This is a good thing */
if (Status == STATUS_TIMEOUT) Status = STATUS_SUCCESS;
@ -160,13 +180,14 @@ KeDelayExecutionThread(KPROCESSOR_MODE WaitMode,
return Status;
}
DPRINT("Looping Again\n");
DPRINT("Looping Again\n"); // FIXME: Need to modify interval
CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
} while (TRUE);
}
while (TRUE);
/* Release the Lock, we are done */
DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n", KeGetCurrentThread(), Status);
DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n",
KeGetCurrentThread(), Status);
KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
return Status;
}
@ -194,33 +215,32 @@ KeWaitForSingleObject(PVOID Object,
BOOLEAN Alertable,
PLARGE_INTEGER Timeout)
{
PDISPATCHER_HEADER CurrentObject;
PKMUTANT CurrentObject;
PKWAIT_BLOCK WaitBlock;
PKWAIT_BLOCK TimerWaitBlock;
PKTIMER ThreadTimer;
PKTHREAD CurrentThread = KeGetCurrentThread();
NTSTATUS Status;
NTSTATUS WaitStatus;
DPRINT("Entering KeWaitForSingleObject\n");
/* Check if the lock is already held */
if (CurrentThread->WaitNext) {
if (CurrentThread->WaitNext)
{
/* Lock is held, disable Wait Next */
DPRINT("Lock is held\n");
CurrentThread->WaitNext = FALSE;
} else {
}
else
{
/* Lock not held, acquire it */
DPRINT("Lock is not held, acquiring\n");
CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
}
/* Start the actual Loop */
do {
do
{
/* Get the current Wait Status */
WaitStatus = CurrentThread->WaitStatus;
@ -228,30 +248,38 @@ KeWaitForSingleObject(PVOID Object,
CurrentThread->WaitBlockList = WaitBlock = &CurrentThread->WaitBlock[0];
/* Get the Current Object */
CurrentObject = (PDISPATCHER_HEADER)Object;
/* Check if the Object is Signaled */
if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
/* Just unwait this guy and exit */
if (CurrentObject->SignalState != (LONG)MINLONG) {
/* It has a normal signal state, so unwait it and return */
KiSatisfyObjectWait(CurrentObject, CurrentThread);
Status = STATUS_WAIT_0;
goto DontWait;
} else {
/* Is this a Mutant? */
if (CurrentObject->Type == MutantObject) {
CurrentObject = (PKMUTANT)Object;
/* Check if it's a mutant */
if (CurrentObject->Header.Type == MutantObject)
{
/* Check its signal state or if we own it */
if ((CurrentObject->Header.SignalState > 0) ||
(CurrentThread == CurrentObject->OwnerThread))
{
/* Just unwait this guy and exit */
if (CurrentObject->Header.SignalState != (LONG)MINLONG)
{
/* It has a normal signal state, so unwait it and return */
KiSatisfyMutantWait(CurrentObject, CurrentThread);
Status = STATUS_WAIT_0;
goto DontWait;
}
else
{
/* According to wasm.ru, we must raise this exception (tested and true) */
KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
}
}
}
else if (CurrentObject->Header.SignalState > 0)
{
/* Another satisfied object */
KiSatisfyNonMutantWait(CurrentObject, CurrentThread);
Status = STATUS_WAIT_0;
goto DontWait;
}
/* Set up the Wait Block */
WaitBlock->Object = CurrentObject;
@ -261,18 +289,17 @@ KeWaitForSingleObject(PVOID Object,
WaitBlock->NextWaitBlock = WaitBlock;
/* Make sure we can satisfy the Alertable request */
if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status))
break;
if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status)) break;
/* Set the Wait Status */
CurrentThread->WaitStatus = Status;
/* Enable the Timeout Timer if there was any specified */
if (Timeout != NULL) {
/* However if 0 timeout was specified, then we must fail since we need to peform a wait */
if (!Timeout->QuadPart) {
if (Timeout)
{
/* Fail if the timeout interval is actually 0 */
if (!Timeout->QuadPart)
{
/* Return a timeout */
Status = STATUS_TIMEOUT;
goto DontWait;
@ -294,48 +321,53 @@ KeWaitForSingleObject(PVOID Object,
/* Link the timer to this Wait Block */
InitializeListHead(&ThreadTimer->Header.WaitListHead);
InsertTailList(&ThreadTimer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry);
InsertTailList(&ThreadTimer->Header.WaitListHead,
&TimerWaitBlock->WaitListEntry);
/* Insert the Timer into the Timer Lists and enable it */
if (!KiInsertTimer(ThreadTimer, *Timeout)) {
/* Return a timeout if we couldn't insert the timer for some reason */
if (!KiInsertTimer(ThreadTimer, *Timeout))
{
/* Return a timeout if we couldn't insert the timer */
Status = STATUS_TIMEOUT;
goto DontWait;
}
}
/* Link the Object to this Wait Block */
InsertTailList(&CurrentObject->WaitListHead, &WaitBlock->WaitListEntry);
InsertTailList(&CurrentObject->Header.WaitListHead,
&WaitBlock->WaitListEntry);
/* Handle Kernel Queues */
if (CurrentThread->Queue) {
if (CurrentThread->Queue)
{
DPRINT("Waking Queue\n");
KiWakeQueue(CurrentThread->Queue);
}
/* Block the Thread */
DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable, WaitMode, WaitReason, KeGetCurrentThread());
DPRINT("Blocking the Thread: %d, %d, %d, %x\n",
Alertable, WaitMode, WaitReason, KeGetCurrentThread());
KiBlockThread(&Status,
Alertable,
WaitMode,
(UCHAR)WaitReason);
/* Check if we were executing an APC */
if (Status != STATUS_KERNEL_APC) {
if (Status != STATUS_KERNEL_APC)
{
/* Return Status */
return Status;
}
DPRINT("Looping Again\n");
/* Loop again and acquire the dispatcher lock */
DPRINT("Looping Again\n"); // FIXME: Change interval
CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
} while (TRUE);
}
while (TRUE);
/* Release the Lock, we are done */
DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status);
DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n",
KeGetCurrentThread(), Status);
KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
return Status;
@ -344,7 +376,8 @@ DontWait:
KiAdjustQuantumThread(CurrentThread);
/* Release & Return */
DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n. We did not wait.", KeGetCurrentThread(), Status);
DPRINT("Quick-return from KeWaitForMultipleObjects(), %x. Status: %d\n.",
KeGetCurrentThread(), Status);
KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
return Status;
}
@ -362,7 +395,7 @@ KeWaitForMultipleObjects(ULONG Count,
PLARGE_INTEGER Timeout,
PKWAIT_BLOCK WaitBlockArray)
{
PDISPATCHER_HEADER CurrentObject;
PKMUTANT CurrentObject;
PKWAIT_BLOCK WaitBlock;
PKWAIT_BLOCK TimerWaitBlock;
PKTIMER ThreadTimer;
@ -371,51 +404,45 @@ KeWaitForMultipleObjects(ULONG Count,
ULONG WaitIndex;
NTSTATUS Status;
NTSTATUS WaitStatus;
DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
"PsGetCurrentThread() %x, Timeout %x\n", Count, Object, PsGetCurrentThread(), Timeout);
"PsGetCurrentThread() %x, Timeout %x\n",
Count, Object, PsGetCurrentThread(), Timeout);
/* Set the Current Thread */
CurrentThread = KeGetCurrentThread();
/* Check if the lock is already held */
if (CurrentThread->WaitNext) {
if (CurrentThread->WaitNext)
{
/* Lock is held, disable Wait Next */
DPRINT("Lock is held\n");
CurrentThread->WaitNext = FALSE;
} else {
}
else
{
/* Lock not held, acquire it */
DPRINT("Lock is not held, acquiring\n");
CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
}
/* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
if (!WaitBlockArray) {
if (!WaitBlockArray)
{
/* Check in regards to the Thread Object Limit */
if (Count > THREAD_WAIT_OBJECTS) {
KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
}
if (Count > THREAD_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
/* Use the Thread's Wait Block */
WaitBlockArray = &CurrentThread->WaitBlock[0];
} else {
}
else
{
/* Using our own Block Array. Check in regards to System Object Limit */
if (Count > MAXIMUM_WAIT_OBJECTS) {
KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
}
if (Count > MAXIMUM_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
}
/* Start the actual Loop */
do {
do
{
/* Get the current Wait Status */
WaitStatus = CurrentThread->WaitStatus;
@ -426,47 +453,76 @@ KeWaitForMultipleObjects(ULONG Count,
AllObjectsSignaled = TRUE;
/* First, we'll try to satisfy the wait directly */
for (WaitIndex = 0; WaitIndex < Count; WaitIndex++) {
for (WaitIndex = 0; WaitIndex < Count; WaitIndex++)
{
/* Get the Current Object */
CurrentObject = (PDISPATCHER_HEADER)Object[WaitIndex];
/* Check if the Object is Signaled */
if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
/* Check what kind of wait this is */
if (WaitType == WaitAny) {
/* This is a Wait Any, so just unwait this guy and exit */
if (CurrentObject->SignalState != (LONG)MINLONG) {
/* It has a normal signal state, so unwait it and return */
KiSatisfyObjectWait(CurrentObject, CurrentThread);
Status = STATUS_WAIT_0 | WaitIndex;
goto DontWait;
} else {
/* Is this a Mutant? */
if (CurrentObject->Type == MutantObject) {
CurrentObject = (PKMUTANT)Object[WaitIndex];
/* Check the type of wait */
if (WaitType == WaitAny)
{
/* Check if the Object is a mutant */
if (CurrentObject->Header.Type == MutantObject)
{
/* Check if it's signaled */
if ((CurrentObject->Header.SignalState > 0) ||
(CurrentThread == CurrentObject->OwnerThread))
{
/* This is a Wait Any, so just unwait this and exit */
if (CurrentObject->Header.SignalState != (LONG)MINLONG)
{
/* Normal signal state, so unwait it and return */
KiSatisfyMutantWait(CurrentObject, CurrentThread);
Status = STATUS_WAIT_0 | WaitIndex;
goto DontWait;
}
else
{
/* According to wasm.ru, we must raise this exception (tested and true) */
KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
}
}
}
} else {
/* One of the objects isn't signaled... if this is a WaitAll, we will fail later */
AllObjectsSignaled = FALSE;
else if (CurrentObject->Header.SignalState > 0)
{
/* Another signaled object, unwait and return */
KiSatisfyNonMutantWait(CurrentObject, CurrentThread);
Status = WaitIndex;
goto DontWait;
}
}
else
{
/* Check if we're dealing with a mutant again */
if (CurrentObject->Header.Type == MutantObject)
{
/* Check if it has an invalid count */
if ((CurrentThread == CurrentObject->OwnerThread) &&
(CurrentObject->Header.SignalState == MINLONG))
{
/* Raise an exception */
KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
}
else if ((CurrentObject->Header.SignalState <= 0) &&
(CurrentThread != CurrentObject->OwnerThread))
{
/* We don't own it, can't satisfy the wait */
AllObjectsSignaled = FALSE;
}
}
else if (CurrentObject->Header.SignalState <= 0)
{
/* Not signaled, can't satisfy */
AllObjectsSignaled = FALSE;
}
}
/* Set up a Wait Block for this Object */
WaitBlock->Object = CurrentObject;
WaitBlock->Thread = CurrentThread;
WaitBlock->WaitKey = (USHORT)(STATUS_WAIT_0 + WaitIndex);
WaitBlock->WaitKey = (USHORT)WaitIndex;
WaitBlock->WaitType = (USHORT)WaitType;
WaitBlock->NextWaitBlock = WaitBlock + 1;
@ -479,8 +535,8 @@ KeWaitForMultipleObjects(ULONG Count,
WaitBlock->NextWaitBlock = WaitBlockArray;
/* Check if this is a Wait All and all the objects are signaled */
if ((WaitType == WaitAll) && (AllObjectsSignaled)) {
if ((WaitType == WaitAll) && (AllObjectsSignaled))
{
/* Return to the Root Wait Block */
WaitBlock = CurrentThread->WaitBlockList;
@ -491,18 +547,17 @@ KeWaitForMultipleObjects(ULONG Count,
}
/* Make sure we can satisfy the Alertable request */
if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status))
break;
if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status)) break;
/* Set the Wait Status */
CurrentThread->WaitStatus = Status;
/* Enable the Timeout Timer if there was any specified */
if (Timeout != NULL) {
/* However if 0 timeout was specified, then we must fail since we need to peform a wait */
if (!Timeout->QuadPart) {
if (Timeout)
{
/* Make sure the timeout interval isn't actually 0 */
if (!Timeout->QuadPart)
{
/* Return a timeout */
Status = STATUS_TIMEOUT;
goto DontWait;
@ -526,9 +581,9 @@ KeWaitForMultipleObjects(ULONG Count,
InitializeListHead(&ThreadTimer->Header.WaitListHead);
/* Insert the Timer into the Timer Lists and enable it */
if (!KiInsertTimer(ThreadTimer, *Timeout)) {
/* Return a timeout if we couldn't insert the timer for some reason */
if (!KiInsertTimer(ThreadTimer, *Timeout))
{
/* Return a timeout if we couldn't insert the timer */
Status = STATUS_TIMEOUT;
goto DontWait;
}
@ -536,28 +591,30 @@ KeWaitForMultipleObjects(ULONG Count,
/* Insert into Object's Wait List*/
WaitBlock = CurrentThread->WaitBlockList;
do {
do
{
/* Get the Current Object */
CurrentObject = WaitBlock->Object;
/* Link the Object to this Wait Block */
InsertTailList(&CurrentObject->WaitListHead, &WaitBlock->WaitListEntry);
InsertTailList(&CurrentObject->Header.WaitListHead,
&WaitBlock->WaitListEntry);
/* Move to the next Wait Block */
WaitBlock = WaitBlock->NextWaitBlock;
} while (WaitBlock != WaitBlockArray);
}
while (WaitBlock != WaitBlockArray);
/* Handle Kernel Queues */
if (CurrentThread->Queue) {
if (CurrentThread->Queue)
{
DPRINT("Waking Queue\n");
KiWakeQueue(CurrentThread->Queue);
}
/* Block the Thread */
DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable, WaitMode,
WaitReason, KeGetCurrentThread());
DPRINT("Blocking the Thread: %d, %d, %d, %x\n",
Alertable, WaitMode, WaitReason, KeGetCurrentThread());
KiBlockThread(&Status,
Alertable,
WaitMode,
@ -565,16 +622,17 @@ KeWaitForMultipleObjects(ULONG Count,
/* Check if we were executing an APC */
DPRINT("Thread is back\n");
if (Status != STATUS_KERNEL_APC) {
if (Status != STATUS_KERNEL_APC)
{
/* Return Status */
return Status;
}
DPRINT("Looping Again\n");
/* Loop again and re-acquire the dispatcher lock */
DPRINT("Looping Again\n"); // FIXME: Fix-up the interval */
CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
} while (TRUE);
}
while (TRUE);
/* Release the Lock, we are done */
DPRINT("Returning, %x. Status: %d\n", KeGetCurrentThread(), Status);
@ -586,7 +644,7 @@ DontWait:
KiAdjustQuantumThread(CurrentThread);
/* Release & Return */
DPRINT("Returning, %x. Status: %d\n. We did not wait.",
DPRINT("Returning, %x. Status: %d\n. We did not wait.",
KeGetCurrentThread(), Status);
KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
return Status;
@ -594,54 +652,7 @@ DontWait:
VOID
FASTCALL
KiSatisfyObjectWait(PDISPATCHER_HEADER Object,
PKTHREAD Thread)
{
/* Special case for Mutants */
if (Object->Type == MutantObject) {
/* Decrease the Signal State */
Object->SignalState--;
/* Check if it's now non-signaled */
if (Object->SignalState == 0) {
/* Set the Owner Thread */
((PKMUTANT)Object)->OwnerThread = Thread;
/* Disable APCs if needed */
Thread->KernelApcDisable -= ((PKMUTANT)Object)->ApcDisable;
/* Check if it's abandoned */
if (((PKMUTANT)Object)->Abandoned) {
/* Unabandon it */
((PKMUTANT)Object)->Abandoned = FALSE;
/* Return Status */
Thread->WaitStatus = STATUS_ABANDONED;
}
/* Insert it into the Mutant List */
InsertHeadList(&Thread->MutantListHead, &((PKMUTANT)Object)->MutantListEntry);
}
} else if ((Object->Type & TIMER_OR_EVENT_TYPE) == EventSynchronizationObject) {
/* These guys (Syncronization Timers and Events) just get un-signaled */
Object->SignalState = 0;
} else if (Object->Type == SemaphoreObject) {
/* These ones can have multiple signalings, so we only decrease it */
Object->SignalState--;
}
}
VOID
FASTCALL
KiWaitTest(PDISPATCHER_HEADER Object,
KiWaitTest(PVOID ObjectPointer,
KPRIORITY Increment)
{
PLIST_ENTRY WaitEntry;
@ -649,41 +660,55 @@ KiWaitTest(PDISPATCHER_HEADER Object,
PKWAIT_BLOCK CurrentWaitBlock;
PKWAIT_BLOCK NextWaitBlock;
PKTHREAD WaitThread;
PKMUTANT FirstObject = ObjectPointer, Object;
/* Loop the Wait Entries */
DPRINT("KiWaitTest for Object: %x\n", Object);
WaitList = &Object->WaitListHead;
DPRINT("KiWaitTest for Object: %x\n", FirstObject);
WaitList = &FirstObject->Header.WaitListHead;
WaitEntry = WaitList->Flink;
while ((WaitEntry != WaitList) && (Object->SignalState > 0)) {
while ((FirstObject->Header.SignalState > 0) && (WaitEntry != WaitList))
{
/* Get the current wait block */
CurrentWaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
CurrentWaitBlock = CONTAINING_RECORD(WaitEntry,
KWAIT_BLOCK,
WaitListEntry);
WaitThread = CurrentWaitBlock->Thread;
/* Check the current Wait Mode */
if (CurrentWaitBlock->WaitType == WaitAny) {
if (CurrentWaitBlock->WaitType == WaitAny)
{
/* Easy case, satisfy only this wait */
DPRINT("Satisfiying a Wait any\n");
WaitEntry = WaitEntry->Blink;
KiSatisfyObjectWait(Object, WaitThread);
} else {
KiSatisfyObjectWait(FirstObject, WaitThread);
}
else
{
/* Everything must be satisfied */
DPRINT("Checking for a Wait All\n");
NextWaitBlock = CurrentWaitBlock->NextWaitBlock;
/* Loop first to make sure they are valid */
while (NextWaitBlock != CurrentWaitBlock) {
while (NextWaitBlock != CurrentWaitBlock)
{
/* Check if the object is signaled */
DPRINT("Checking: %x %d\n", NextWaitBlock->Object, Object->SignalState);
if (!KiIsObjectSignaled(NextWaitBlock->Object, WaitThread)) {
/* It's not, move to the next one */
DPRINT("One of the object is non-signaled, sorry.\n");
goto SkipUnwait;
Object = NextWaitBlock->Object;
DPRINT("Checking: %p %d\n",
Object, Object->Header.SignalState);
if (NextWaitBlock->WaitKey != STATUS_TIMEOUT)
{
/* Check if this is a mutant */
if ((Object->Header.Type == MutantObject) &&
(Object->Header.SignalState <= 0) &&
(WaitThread == Object->OwnerThread))
{
/* It's a signaled mutant */
}
else if (Object->Header.SignalState <= 0)
{
/* Skip the unwaiting */
goto SkipUnwait;
}
}
/* Go to the next Wait block */
@ -718,16 +743,17 @@ KiAbortWaitThread(PKTHREAD Thread,
PKWAIT_BLOCK WaitBlock;
/* If we are blocked, we must be waiting on something also */
DPRINT("KiAbortWaitThread: %x, Status: %x, %x \n", Thread, WaitStatus, Thread->WaitBlockList);
ASSERT((Thread->State == Waiting) == (Thread->WaitBlockList != NULL));
DPRINT("KiAbortWaitThread: %x, Status: %x, %x \n",
Thread, WaitStatus, Thread->WaitBlockList);
/* Remove the Wait Blocks from the list */
DPRINT("Removing waits\n");
WaitBlock = Thread->WaitBlockList;
do {
do
{
/* Remove it */
DPRINT("Removing Waitblock: %x, %x\n", WaitBlock, WaitBlock->NextWaitBlock);
DPRINT("Removing Waitblock: %x, %x\n",
WaitBlock, WaitBlock->NextWaitBlock);
RemoveEntryList(&WaitBlock->WaitListEntry);
/* Go to the next one */
@ -735,8 +761,8 @@ KiAbortWaitThread(PKTHREAD Thread,
} while (WaitBlock != Thread->WaitBlockList);
/* Check if there's a Thread Timer */
if (Thread->Timer.Header.Inserted) {
if (Thread->Timer.Header.Inserted)
{
/* Cancel the Thread Timer with the no-lock fastpath */
DPRINT("Removing the Thread's Timer\n");
Thread->Timer.Header.Inserted = FALSE;
@ -744,8 +770,8 @@ KiAbortWaitThread(PKTHREAD Thread,
}
/* Increment the Queue's active threads */
if (Thread->Queue) {
if (Thread->Queue)
{
DPRINT("Incrementing Queue's active threads\n");
Thread->Queue->CurrentCount++;
}
@ -770,123 +796,28 @@ KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
NULL);
}
BOOLEAN
__inline
FASTCALL
KiIsObjectSignaled(PDISPATCHER_HEADER Object,
PKTHREAD Thread)
{
/* Mutants are...well...mutants! */
if (Object->Type == MutantObject) {
/*
* Because Cutler hates mutants, they are actually signaled if the Signal State is <= 0
* Well, only if they are recursivly acquired (i.e if we own it right now).
* Of course, they are also signaled if their signal state is 1.
*/
if ((Object->SignalState <= 0 && ((PKMUTANT)Object)->OwnerThread == Thread) ||
(Object->SignalState == 1)) {
/* Signaled Mutant */
return (TRUE);
} else {
/* Unsignaled Mutant */
return (FALSE);
}
}
/* Any other object is not a mutated freak, so let's use logic */
return (!Object->SignalState <= 0);
}
VOID
__inline
FASTCALL
KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock)
{
PKWAIT_BLOCK FirstBlock = WaitBlock;
PKTHREAD WaitThread = WaitBlock->Thread;
/* Loop through all the Wait Blocks, and wake each Object */
do {
/* Wake the Object */
KiSatisfyObjectWait(WaitBlock->Object, WaitThread);
WaitBlock = WaitBlock->NextWaitBlock;
} while (WaitBlock != FirstBlock);
}
VOID
__inline
FASTCALL
KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header,
ULONG Type,
ULONG Size,
ULONG SignalState)
{
Header->Type = (UCHAR)Type;
Header->Absolute = 0;
Header->Inserted = 0;
Header->Size = (UCHAR)Size;
Header->SignalState = SignalState;
InitializeListHead(&(Header->WaitListHead));
}
KIRQL
__inline
FASTCALL
KeAcquireDispatcherDatabaseLock(VOID)
{
KIRQL OldIrql;
KeAcquireSpinLock (&DispatcherDatabaseLock, &OldIrql);
return OldIrql;
}
VOID
__inline
FASTCALL
KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID)
{
KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock);
}
VOID
__inline
FASTCALL
KeInitializeDispatcher(VOID)
{
/* Initialize the Dispatcher Lock */
KeInitializeSpinLock(&DispatcherDatabaseLock);
}
VOID
__inline
FASTCALL
KeReleaseDispatcherDatabaseLock(KIRQL OldIrql)
{
/* If it's the idle thread, dispatch */
if (!KeIsExecutingDpc() && OldIrql < DISPATCH_LEVEL && KeGetCurrentThread() != NULL &&
KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread) {
if (!(KeIsExecutingDpc()) &&
(OldIrql < DISPATCH_LEVEL) &&
(KeGetCurrentThread()) &&
(KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread))
{
KiDispatchThreadNoLock(Ready);
KeLowerIrql(OldIrql);
} else {
}
else
{
/* Just release the spin lock */
#ifdef CONFIG_SMP
KeReleaseSpinLock(&DispatcherDatabaseLock, OldIrql);
#else
KeLowerIrql(OldIrql);
#endif
}
}
VOID
__inline
FASTCALL
KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID)
{
KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock);
}
/* EOF */

View file

@ -84,7 +84,6 @@ ExAllocateCacheAwareRundownProtection@8
ExFreeCacheAwareRundownProtection@4
ExInitializeRundownProtectionCacheAware@8
ExSizeOfRundownProtectionCacheAware@0
ExAcquireResourceExclusive@8
ExAcquireResourceExclusiveLite@8
ExAcquireResourceSharedLite@8
ExAcquireSharedStarveExclusive@8
@ -99,7 +98,6 @@ ExConvertExclusiveToSharedLite@4
ExCreateCallback@16
ExDeleteNPagedLookasideList@4
ExDeletePagedLookasideList@4
ExDeleteResource@4
ExDeleteResourceLite@4
ExDesktopObjectType DATA
ExDisableResourceBoostLite@4
@ -117,7 +115,6 @@ ExGetPreviousMode@0
ExGetSharedWaiterCount@4
ExInitializeNPagedLookasideList@28
ExInitializePagedLookasideList@28
ExInitializeResource@4
ExInitializeResourceLite@4
ExInitializeZone@16
ExInterlockedAddLargeInteger@16
@ -153,7 +150,6 @@ ExReinitializeResourceLite@4
@ExiReleaseFastMutex@4=@ExReleaseFastMutex@4
@ExReleaseFastMutexUnsafe@4
@ExReleaseFastMutexUnsafeAndLeaveCriticalRegion@4
ExReleaseResourceForThread@8
ExReleaseResourceForThreadLite@8
@ExReleaseResourceLite@4
ExSemaphoreObjectType DATA
@ -522,7 +518,6 @@ Ke386SetIoAccessMap@8
@KeAcquireGuardedMutex@4
@KeAcquireGuardedMutexUnsafe@4
KeAcquireSpinLockAtDpcLevel@4
@KeAcquireDispatcherDatabaseLockAtDpcLevel@0
@KeAcquireInStackQueuedSpinLockAtDpcLevel@8
KeAcquireInterruptSpinLock@4
KeAddSystemServiceTable@20
@ -606,7 +601,6 @@ KeReadStateSemaphore@4
KeReadStateTimer@4
KeRegisterBugCheckCallback@20
KeRegisterBugCheckReasonCallback@16
@KeReleaseDispatcherDatabaseLockFromDpcLevel@0
@KeReleaseGuardedMutexUnsafe@4
@KeReleaseGuardedMutex@4
@KeReleaseInStackQueuedSpinLockFromDpcLevel@4

View file

@ -204,7 +204,7 @@ PsInitProcessManagment(VOID)
InitializeListHead(&PsIdleProcess->ActiveProcessLinks);
KeInitializeDispatcherHeader(&PsIdleProcess->Pcb.Header,
ProcessObject,
sizeof(EPROCESS),
sizeof(EPROCESS) / sizeof(LONG),
FALSE);
PsIdleProcess->Pcb.DirectoryTableBase.QuadPart = (ULONG_PTR)MmGetPageDirectory();
strcpy(PsIdleProcess->ImageFileName, "Idle");
@ -246,7 +246,7 @@ PsInitProcessManagment(VOID)
InitializeListHead(&PsInitialSystemProcess->Pcb.ThreadListHead);
KeInitializeDispatcherHeader(&PsInitialSystemProcess->Pcb.Header,
ProcessObject,
sizeof(EPROCESS),
sizeof(EPROCESS) / sizeof(LONG),
FALSE);
KProcess = &PsInitialSystemProcess->Pcb;
PspInheritQuota(PsInitialSystemProcess, NULL);