- 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 :)
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S
Modified: trunk/reactos/ntoskrnl/ke/kthread.c
Modified: trunk/reactos/ntoskrnl/ke/wait.c
Modified: trunk/reactos/ntoskrnl/ntoskrnl.def
Modified: trunk/reactos/ntoskrnl/ps/psmgr.c
_____
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
--- trunk/reactos/ntoskrnl/include/internal/ke.h 2006-01-05
01:49:00 UTC (rev 20567)
+++ trunk/reactos/ntoskrnl/include/internal/ke.h 2006-01-05
04:26:55 UTC (rev 20568)
@@ -44,31 +44,174 @@
/* 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--;
\
+ }
\
}
-#define KEBUGCHECKWITHTF(a,b,c,d,e,f) \
- DbgPrint("KeBugCheckWithTf at %s:%i\n",__FILE__,__LINE__),
KeBugCheckWithTf(a,b,c,d,e,f)
+/* 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);
\
+ }
\
+}
-#define MAXIMUM_PROCESSORS 32
+/* 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)
+
/* INTERNAL KERNEL FUNCTIONS
************************************************/
/* threadsch.c
********************************************************************/
@@ -243,27 +386,11 @@
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(
struct _KPROCESS* Process,
@@ -313,16 +440,6 @@
);
VOID
-__inline
-FASTCALL
-KeInitializeDispatcherHeader(
- DISPATCHER_HEADER* Header,
- ULONG Type,
- ULONG Size,
- ULONG SignalState
-);
-
-VOID
NTAPI
KeDumpStackFrames(PULONG Frame);
@@ -362,14 +479,6 @@
LARGE_INTEGER DueTime
);
-VOID
-__inline
-FASTCALL
-KiSatisfyObjectWait(
- PDISPATCHER_HEADER Object,
- PKTHREAD Thread
-);
-
BOOLEAN
__inline
FASTCALL
@@ -379,14 +488,9 @@
);
VOID
-__inline
FASTCALL
-KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock);
-
-VOID
-FASTCALL
KiWaitTest(
- PDISPATCHER_HEADER Object,
+ PVOID Object,
KPRIORITY Increment
);
@@ -507,11 +611,6 @@
KeInitDispatcher(VOID);
VOID
-__inline
-FASTCALL
-KeInitializeDispatcher(VOID);
-
-VOID
NTAPI
KiInitializeSystemClock(VOID);
_____
Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S
--- trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S 2006-01-05 01:49:00 UTC
(rev 20567)
+++ trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S 2006-01-05 04:26:55 UTC
(rev 20568)
@@ -21,6 +21,8 @@
/* GLOBALS
****************************************************************/
+.extern _DispatcherDatabaseLock
+
/* FUNCTIONS
****************************************************************/
/*++
@@ -244,7 +246,10 @@
pop [ebx+KPCR_EXCEPTION_LIST]
/* Return */
- call @KeReleaseDispatcherDatabaseLockFromDpcLevel@0
+//#ifdef CONFIG_SMP
+ mov ecx, _DispatcherDatabaseLock
+ call @KefReleaseSpinLockFromDpcLevel@4
+//#endif
ret
/*++
_____
Modified: trunk/reactos/ntoskrnl/ke/kthread.c
--- trunk/reactos/ntoskrnl/ke/kthread.c 2006-01-05 01:49:00 UTC (rev
20567)
+++ trunk/reactos/ntoskrnl/ke/kthread.c 2006-01-05 04:26:55 UTC (rev
20568)
@@ -819,7 +819,7 @@
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",
_____
Modified: trunk/reactos/ntoskrnl/ke/wait.c
--- trunk/reactos/ntoskrnl/ke/wait.c 2006-01-05 01:49:00 UTC (rev
20567)
+++ trunk/reactos/ntoskrnl/ke/wait.c 2006-01-05 04:26:55 UTC (rev
20568)
@@ -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(a)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 @@
__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 @@
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,12 +127,11 @@
TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
/* Start Wait Loop */
- do {
+ do
+ {
+ /* Chceck if we can do an alertable wait, if requested */
+ if (KiCheckAlertability(Alertable, CurrentThread, WaitMode,
&Status)) break;
- /* We are going to wait no matter what (that's the point), so
test Alertability */
- if (KiCheckAlertability(Alertable, CurrentThread, WaitMode,
&Status))
- break;
-
/* Set Timer */
ThreadTimer = &CurrentThread->Timer;
@@ -129,30 +148,31 @@
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 @@
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 @@
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 @@
CurrentThread->WaitBlockList = WaitBlock =
&CurrentThread->WaitBlock[0];
/* Get the Current Object */
- CurrentObject = (PDISPATCHER_HEADER)Object;
+ CurrentObject = (PKMUTANT)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) {
-
+ /* 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 @@
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 @@
/* 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 @@
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 @@
PLARGE_INTEGER Timeout,
PKWAIT_BLOCK WaitBlockArray)
{
- PDISPATCHER_HEADER CurrentObject;
+ PKMUTANT CurrentObject;
PKWAIT_BLOCK WaitBlock;
PKWAIT_BLOCK TimerWaitBlock;
PKTIMER ThreadTimer;
@@ -371,51 +404,45 @@
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) {
+ if (Count > THREAD_WAIT_OBJECTS)
KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
- 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 @@
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];
+ CurrentObject = (PKMUTANT)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) {
-
+ /* 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 @@
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 @@
}
/* 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 @@
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 @@
/* 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,17 +622,18 @@
/* 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;
}
[truncated at 1000 lines; 408 more skipped]
- fix build on dbg=0. Thanks to Andrew
Modified: trunk/reactos/ntoskrnl/ex/pushlock.c
_____
Modified: trunk/reactos/ntoskrnl/ex/pushlock.c
--- trunk/reactos/ntoskrnl/ex/pushlock.c 2006-01-04 23:48:15 UTC
(rev 20565)
+++ trunk/reactos/ntoskrnl/ex/pushlock.c 2006-01-05 00:56:44 UTC
(rev 20566)
@@ -164,8 +164,10 @@
/* Sanity check */
ASSERT(!WaitBlock->Signaled);
+#ifdef DBG
/* We are about to get signaled */
WaitBlock->Signaled = TRUE;
+#endif
/* Set the Wait Bit in the Wait Block */
if (!InterlockedBitTestAndReset(&WaitBlock->Flags, 1))