mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 08:25:03 +00:00
- 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:
parent
f58996b3e9
commit
5e6fa26231
6 changed files with 453 additions and 424 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
/*++
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue