Author: ion
Date: Thu Jul 13 09:20:43 2006
New Revision: 23038
URL:
http://svn.reactos.org/svn/reactos?rev=23038&view=rev
Log:
- Add ASSERT_QUEUE macro.
- Cleanup queue.c
- Add some ASSERTs
- Properly check for SPecialApcDisable before aborting a wait.
- Fix a bug in KiWaitQueue which was causing us not to remove the queue from the
thread's wait list.
Modified:
trunk/reactos/include/ddk/ntifs.h
trunk/reactos/ntoskrnl/ke/queue.c
Modified: trunk/reactos/include/ddk/ntifs.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/ddk/ntifs.h?rev=23…
==============================================================================
--- trunk/reactos/include/ddk/ntifs.h (original)
+++ trunk/reactos/include/ddk/ntifs.h Thu Jul 13 09:20:43 2006
@@ -1279,6 +1279,8 @@
LIST_ENTRY ThreadListHead;
} KQUEUE, *PKQUEUE, *RESTRICTED_POINTER PRKQUEUE;
+#define ASSERT_QUEUE(Q) ASSERT(((Q)->Header.Type & KOBJECT_TYPE_MASK) ==
QueueObject);
+
typedef struct _MBCB {
CSHORT NodeTypeCode;
CSHORT NodeIsInZone;
Modified: trunk/reactos/ntoskrnl/ke/queue.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/queue.c?rev=23…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/queue.c (original)
+++ trunk/reactos/ntoskrnl/ke/queue.c Thu Jul 13 09:20:43 2006
@@ -1,38 +1,160 @@
/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/queue.c
* PURPOSE: Implements kernel queues
- *
- * PROGRAMMERS: Alex Ionescu (alex(a)relsoft.net)
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
* Gunnar Dalsnes
* Eric Kohl (ekohl(a)rz-online.de)
*/
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
-/* FUNCTIONS *****************************************************************/
-
-LONG STDCALL KiInsertQueue(IN PKQUEUE Queue, IN PLIST_ENTRY Entry, BOOLEAN Head);
-
-/*
- * @implemented
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*
+ * Called when a thread which has a queue entry is entering a wait state
*/
VOID
-STDCALL
+FASTCALL
+KiWakeQueue(IN PKQUEUE Queue)
+{
+ PLIST_ENTRY QueueEntry;
+ PLIST_ENTRY WaitEntry;
+ PKWAIT_BLOCK WaitBlock;
+ PKTHREAD Thread;
+ ASSERT_QUEUE(Queue);
+
+ /* Decrement the number of active threads */
+ Queue->CurrentCount--;
+
+ /* Make sure the counts are OK */
+ if (Queue->CurrentCount < Queue->MaximumCount)
+ {
+ /* Get the Queue Entry */
+ QueueEntry = Queue->EntryListHead.Flink;
+
+ /* Get the Wait Entry */
+ WaitEntry = Queue->Header.WaitListHead.Blink;
+
+ /* Make sure that the Queue entries are not part of empty lists */
+ if ((WaitEntry != &Queue->Header.WaitListHead) &&
+ (QueueEntry != &Queue->EntryListHead))
+ {
+ /* Remove this entry */
+ RemoveEntryList(QueueEntry);
+ QueueEntry->Flink = NULL;
+
+ /* Decrease the Signal State */
+ Queue->Header.SignalState--;
+
+ /* Unwait the Thread */
+ WaitBlock = CONTAINING_RECORD(WaitEntry,
+ KWAIT_BLOCK,
+ WaitListEntry);
+ Thread = WaitBlock->Thread;
+ KiAbortWaitThread(Thread, (NTSTATUS)QueueEntry, IO_NO_INCREMENT);
+ }
+ }
+}
+
+/*
+ * Returns the previous number of entries in the queue
+ */
+LONG
+NTAPI
+KiInsertQueue(IN PKQUEUE Queue,
+ IN PLIST_ENTRY Entry,
+ BOOLEAN Head)
+{
+ ULONG InitialState;
+ PKTHREAD Thread = KeGetCurrentThread();
+ PKWAIT_BLOCK WaitBlock;
+ PLIST_ENTRY WaitEntry;
+ ASSERT_QUEUE(Queue);
+
+ /* Save the old state */
+ InitialState = Queue->Header.SignalState;
+
+ /* Get the Entry */
+ WaitEntry = Queue->Header.WaitListHead.Blink;
+
+ /*
+ * Why the KeGetCurrentThread()->Queue != Queue?
+ * KiInsertQueue might be called from an APC for the current thread.
+ * -Gunnar
+ */
+ if ((Queue->CurrentCount < Queue->MaximumCount) &&
+ (WaitEntry != &Queue->Header.WaitListHead) &&
+ ((Thread->Queue != Queue) ||
+ (Thread->WaitReason != WrQueue)))
+ {
+ /* Remove the wait entry */
+ RemoveEntryList(WaitEntry);
+
+ /* Get the Wait Block and Thread */
+ WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
+ Thread = WaitBlock->Thread;
+
+ /* Remove the queue from the thread's wait list */
+ Thread->WaitStatus = (NTSTATUS)Entry;
+ RemoveEntryList(&Thread->WaitListEntry);
+ Thread->WaitReason = 0;
+
+ /* Increase the active threads and set the status*/
+ Queue->CurrentCount++;
+
+ /* Check if there's a Thread Timer */
+ if (Thread->Timer.Header.Inserted)
+ {
+ /* Cancel the Thread Timer with the no-lock fastpath */
+ Thread->Timer.Header.Inserted = FALSE;
+ RemoveEntryList(&Thread->Timer.TimerListEntry);
+ }
+
+ /* Reschedule the Thread */
+ KiUnblockThread(Thread, NULL, 0);
+ }
+ else
+ {
+ /* Increase the Entries */
+ Queue->Header.SignalState++;
+
+ /* Check which mode we're using */
+ if (Head)
+ {
+ /* Insert in the head */
+ InsertHeadList(&Queue->EntryListHead, Entry);
+ }
+ else
+ {
+ /* Insert at the end */
+ InsertTailList(&Queue->EntryListHead, Entry);
+ }
+ }
+
+ /* Return the previous state */
+ return InitialState;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
KeInitializeQueue(IN PKQUEUE Queue,
IN ULONG Count OPTIONAL)
{
- DPRINT("KeInitializeQueue %x\n", Queue);
-
/* Initialize the Header */
KeInitializeDispatcherHeader(&Queue->Header,
QueueObject,
- sizeof(KQUEUE)/sizeof(ULONG),
+ sizeof(KQUEUE) / sizeof(ULONG),
0);
/* Initialize the Lists */
@@ -48,14 +170,14 @@
* @implemented
*/
LONG
-STDCALL
+NTAPI
KeInsertHeadQueue(IN PKQUEUE Queue,
IN PLIST_ENTRY Entry)
{
LONG PreviousState;
KIRQL OldIrql;
-
- DPRINT("KeInsertHeadQueue %x\n", Queue);
+ ASSERT_QUEUE(Queue);
+ ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
@@ -73,14 +195,15 @@
/*
* @implemented
*/
-LONG STDCALL
+LONG
+NTAPI
KeInsertQueue(IN PKQUEUE Queue,
IN PLIST_ENTRY Entry)
{
LONG PreviousState;
KIRQL OldIrql;
-
- DPRINT("KeInsertQueue %x\n", Queue);
+ ASSERT_QUEUE(Queue);
+ ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
@@ -101,18 +224,19 @@
* Returns number of entries in the queue
*/
LONG
-STDCALL
+NTAPI
KeReadStateQueue(IN PKQUEUE Queue)
{
/* Returns the Signal State */
- return(Queue->Header.SignalState);
+ ASSERT_QUEUE(Queue);
+ return Queue->Header.SignalState;
}
/*
* @implemented
*/
PLIST_ENTRY
-STDCALL
+NTAPI
KeRemoveQueue(IN PKQUEUE Queue,
IN KPROCESSOR_MODE WaitMode,
IN PLARGE_INTEGER Timeout OPTIONAL)
@@ -124,50 +248,49 @@
PKQUEUE PreviousQueue;
PKWAIT_BLOCK WaitBlock;
PKTIMER Timer;
- DPRINT("KeRemoveQueue %x\n", Queue);
+ ASSERT_QUEUE(Queue);
+ ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Check if the Lock is already held */
if (Thread->WaitNext)
{
- DPRINT("Lock is already held\n");
+ /* It is, so next time don't do expect this */
Thread->WaitNext = FALSE;
}
else
{
/* Lock the Dispatcher Database */
- DPRINT("Lock not held, acquiring\n");
OldIrql = KeAcquireDispatcherDatabaseLock();
Thread->WaitIrql = OldIrql;
}
- /* This is needed so that we can set the new queue right here, before additional
processing */
+ /*
+ * This is needed so that we can set the new queue right here,
+ * before additional processing
+ */
PreviousQueue = Thread->Queue;
Thread->Queue = Queue;
/* Check if this is a different queue */
if (Queue != PreviousQueue)
{
- DPRINT("Different Queue\n");
+ /* Get the current entry */
QueueEntry = &Thread->QueueListEntry;
if (PreviousQueue)
{
/* Remove from this list */
- DPRINT("Removing Old Queue\n");
RemoveEntryList(QueueEntry);
/* Wake the queue */
- DPRINT("Activating new thread\n");
KiWakeQueue(PreviousQueue);
}
/* Insert in this new Queue */
- DPRINT("Inserting new Queue!\n");
InsertTailList(&Queue->ThreadListHead, QueueEntry);
}
else
{
/* Same queue, decrement waiting threads */
- DPRINT("Same Queue!\n");
Queue->CurrentCount--;
}
@@ -179,10 +302,6 @@
if ((Queue->CurrentCount < Queue->MaximumCount) &&
(QueueEntry != &Queue->EntryListHead))
{
- /* Remove the Entry and Save it */
- DPRINT("Removing Queue Entry. CurrentCount: %d, Maximum Count:
%d\n",
- Queue->CurrentCount, Queue->MaximumCount);
-
/* Decrease the number of entries */
Queue->Header.SignalState--;
@@ -204,119 +323,110 @@
}
else
{
- /* Do the wait */
- DPRINT("Waiting on Queue Entry. CurrentCount: %d, Maximum Count:
%d\n",
- Queue->CurrentCount, Queue->MaximumCount);
-
/* Use the Thread's Wait Block, it's big enough */
Thread->WaitBlockList = &Thread->WaitBlock[0];
- /* Check if a kernel APC is pending and we were below APC_LEVEL */
+ /* Check if a kernel APC is pending and we're below APC_LEVEL */
if ((Thread->ApcState.KernelApcPending) &&
- (Thread->WaitIrql < APC_LEVEL))
+ !(Thread->SpecialApcDisable) && (Thread->WaitIrql <
APC_LEVEL))
{
/* Increment the count and unlock the dispatcher */
Queue->CurrentCount++;
KeReleaseDispatcherDatabaseLock(Thread->WaitIrql);
- goto SkipWait;
}
-
- /* Fail if there's a User APC Pending */
- if ((WaitMode != KernelMode) &&
(Thread->ApcState.UserApcPending))
+ else
{
- /* Return the status and increase the pending threads */
- QueueEntry = (PLIST_ENTRY)STATUS_USER_APC;
- Queue->CurrentCount++;
-
- /* Nothing to wait on */
- break;
- }
-
- /* Build the Wait Block */
- WaitBlock = &Thread->WaitBlock[0];
- WaitBlock->Object = (PVOID)Queue;
- WaitBlock->WaitKey = STATUS_SUCCESS;
- WaitBlock->WaitType = WaitAny;
- WaitBlock->Thread = Thread;
- Thread->WaitStatus = STATUS_WAIT_0;
-
- /* We need to wait for the object... check if we have a timeout */
- if (Timeout)
- {
- /* If it's zero, then don't do any waiting */
- if (!Timeout->QuadPart)
+ /* Fail if there's a User APC Pending */
+ if ((WaitMode != KernelMode) &&
+ (Thread->ApcState.UserApcPending))
{
- /* Instant Timeout, return the status and increase the pending
threads */
- DPRINT("Queue Wait has timed out\n");
- QueueEntry = (PLIST_ENTRY)STATUS_TIMEOUT;
+ /* Return the status and increase the pending threads */
+ QueueEntry = (PLIST_ENTRY)STATUS_USER_APC;
Queue->CurrentCount++;
-
- /* Nothing to wait on */
break;
}
- /*
- * Set up the Timer. We'll use the internal function so that we can
- * hold on to the dispatcher lock.
- */
- Timer = &Thread->Timer;
- WaitBlock->NextWaitBlock = &Thread->WaitBlock[1];
- WaitBlock = &Thread->WaitBlock[1];
-
- /* Set up the Timer Wait Block */
- WaitBlock->Object = (PVOID)Timer;
+ /* Build the Wait Block */
+ WaitBlock = &Thread->WaitBlock[0];
+ WaitBlock->Object = (PVOID)Queue;
+ WaitBlock->WaitKey = STATUS_SUCCESS;
+ WaitBlock->WaitType = WaitAny;
WaitBlock->Thread = Thread;
- WaitBlock->WaitKey = STATUS_TIMEOUT;
- WaitBlock->WaitType = WaitAny;
-
- /* Link the timer to this Wait Block */
- Timer->Header.WaitListHead.Flink = &WaitBlock->WaitListEntry;
- Timer->Header.WaitListHead.Blink = &WaitBlock->WaitListEntry;
-
- /* Create Timer */
- DPRINT("Creating Timer with timeout %I64d\n", *Timeout);
- KiInsertTimer(Timer, *Timeout);
+ Thread->WaitStatus = STATUS_WAIT_0;
+
+ /* We need to wait for the object... check for a timeout */
+ if (Timeout)
+ {
+ /* Check if it's zero */
+ if (!Timeout->QuadPart)
+ {
+ /* Don't wait. Return and increase pending threads */
+ QueueEntry = (PLIST_ENTRY)STATUS_TIMEOUT;
+ Queue->CurrentCount++;
+ break;
+ }
+
+ /*
+ * Set up the Timer. We'll use the internal function so
+ * that we can hold on to the dispatcher lock.
+ */
+ Timer = &Thread->Timer;
+ WaitBlock->NextWaitBlock = &Thread->WaitBlock[1];
+ WaitBlock = &Thread->WaitBlock[1];
+
+ /* Set up the Timer Wait Block */
+ WaitBlock->Object = (PVOID)Timer;
+ WaitBlock->Thread = Thread;
+ WaitBlock->WaitKey = STATUS_TIMEOUT;
+ WaitBlock->WaitType = WaitAny;
+
+ /* Link the timer to this Wait Block */
+ Timer->Header.WaitListHead.Flink =
+ &WaitBlock->WaitListEntry;
+ Timer->Header.WaitListHead.Blink =
+ &WaitBlock->WaitListEntry;
+
+ /* Create Timer */
+ KiInsertTimer(Timer, *Timeout);
+ }
+
+ /* Close the loop */
+ WaitBlock->NextWaitBlock = &Thread->WaitBlock[0];
+
+ /* Insert the wait block into the Queues's wait list */
+ WaitBlock = &Thread->WaitBlock[0];
+ InsertTailList(&Queue->Header.WaitListHead,
+ &WaitBlock->WaitListEntry);
+
+ /* Setup the wait information */
+ Thread->WaitMode = WaitMode;
+ Thread->WaitReason = WrQueue;
+ Thread->Alertable = FALSE;
+ Thread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
+ Thread->State = Waiting;
+
+ /* Find a new thread to run */
+ Status = KiSwapThread();
+
+ /* Reset the wait reason */
+ Thread->WaitReason = 0;
+
+ /* Check if we were executing an APC */
+ if (Status != STATUS_KERNEL_APC)
+ {
+ /* Done Waiting */
+ return (PLIST_ENTRY)Status;
+ }
+
+ /* Check if we had a timeout */
+ if (Timeout)
+ {
+ /* FIXME: Fixup interval */
+ DPRINT1("FIXME!!!\n");
+ }
}
- /* Close the loop */
- WaitBlock->NextWaitBlock = &Thread->WaitBlock[0];
-
- /* Insert the wait block into the Queues's wait list */
- WaitBlock = &Thread->WaitBlock[0];
- InsertTailList(&Queue->Header.WaitListHead,
- &WaitBlock->WaitListEntry);
-
- /* Setup the wait information */
- Thread->WaitMode = WaitMode;
- Thread->WaitReason = WrQueue;
- Thread->Alertable = FALSE;
- Thread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
- Thread->State = Waiting;
-
- /* Find a new thread to run */
- DPRINT("Swapping threads\n");
- Status = KiSwapThread();
-
- /* Reset the wait reason */
- Thread->WaitReason = 0;
-
- /* Check if we were executing an APC */
- if (Status != STATUS_KERNEL_APC)
- {
- /* Done Waiting */
- DPRINT("Done waking queue. Thread: %x %x!\n",
KeGetCurrentThread(), Thread);
- return (PLIST_ENTRY)Status;
- }
-
- /* Check if we had a timeout */
- if (Timeout)
- {
- /* FIXME: Fixup interval */
- }
-
- /* Acquire again the lock */
-SkipWait:
- DPRINT("Looping again\n");
+ /* Reacquire the lock */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Save the new IRQL and decrease number of waiting threads */
@@ -327,8 +437,6 @@
/* Unlock Database and return */
KeReleaseDispatcherDatabaseLock(Thread->WaitIrql);
- DPRINT("Returning. CurrentCount: %d, Maximum Count: %d\n",
- Queue->CurrentCount, Queue->MaximumCount);
return QueueEntry;
}
@@ -336,15 +444,16 @@
* @implemented
*/
PLIST_ENTRY
-STDCALL
+NTAPI
KeRundownQueue(IN PKQUEUE Queue)
{
PLIST_ENTRY EnumEntry;
PLIST_ENTRY FirstEntry = NULL;
PKTHREAD Thread;
KIRQL OldIrql;
-
- DPRINT("KeRundownQueue(Queue %x)\n", Queue);
+ ASSERT_QUEUE(Queue);
+ ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
+ ASSERT(IsListEmpty(&Queue->Header.WaitListHead));
/* Get the Dispatcher Lock */
OldIrql = KeAcquireDispatcherDatabaseLock();
@@ -374,137 +483,4 @@
return FirstEntry;
}
-/*
- * Called when a thread which has a queue entry is entering a wait state
- */
-VOID
-FASTCALL
-KiWakeQueue(IN PKQUEUE Queue)
-{
- PLIST_ENTRY QueueEntry;
- PLIST_ENTRY WaitEntry;
- PKWAIT_BLOCK WaitBlock;
- PKTHREAD Thread;
-
- /* Decrement the number of active threads */
- DPRINT("KiWakeQueue: %x. Thread: %x\n", Queue, KeGetCurrentThread());
- Queue->CurrentCount--;
-
- /* Make sure the counts are OK */
- if (Queue->CurrentCount < Queue->MaximumCount)
- {
- /* Get the Queue Entry */
- QueueEntry = Queue->EntryListHead.Flink;
-
- /* Get the Wait Entry */
- WaitEntry = Queue->Header.WaitListHead.Blink;
- DPRINT("Queue Count is ok; entries: %p, %p\n", QueueEntry, WaitEntry);
-
- /* Make sure that the Queue entries are not part of empty lists */
- if ((WaitEntry != &Queue->Header.WaitListHead) &&
- (QueueEntry != &Queue->EntryListHead))
- {
- /* Remove this entry */
- DPRINT("Queue in List, removing it\n");
- RemoveEntryList(QueueEntry);
- QueueEntry->Flink = NULL;
-
- /* Decrease the Signal State */
- Queue->Header.SignalState--;
-
- /* Unwait the Thread */
- WaitBlock = CONTAINING_RECORD(WaitEntry,
- KWAIT_BLOCK,
- WaitListEntry);
- Thread = WaitBlock->Thread;
- DPRINT1("Unwaiting Thread: %d\n", Thread->State);
- KiAbortWaitThread(Thread, (NTSTATUS)QueueEntry, IO_NO_INCREMENT);
- }
- }
-}
-
-/*
- * Returns the previous number of entries in the queue
- */
-LONG
-STDCALL
-KiInsertQueue(IN PKQUEUE Queue,
- IN PLIST_ENTRY Entry,
- BOOLEAN Head)
-{
- ULONG InitialState;
- PKTHREAD Thread = KeGetCurrentThread();
- PKWAIT_BLOCK WaitBlock;
- PLIST_ENTRY WaitEntry;
- DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue, Entry);
-
- /* Save the old state */
- InitialState = Queue->Header.SignalState;
-
- /* Get the Entry */
- WaitEntry = Queue->Header.WaitListHead.Blink;
- DPRINT("Initial State, WaitEntry: %d, %x\n", InitialState, WaitEntry);
-
- /*
- * Why the KeGetCurrentThread()->Queue != Queue?
- * KiInsertQueue might be called from an APC for the current thread.
- * -Gunnar
- */
- if ((Queue->CurrentCount < Queue->MaximumCount) &&
- (WaitEntry != &Queue->Header.WaitListHead) &&
- ((Thread->Queue != Queue) || (Thread->WaitReason != WrQueue)))
- {
- /* Remove the wait entry */
- DPRINT("Removing Entry\n");
- RemoveEntryList(WaitEntry);
-
- /* Get the Wait Block and Thread */
- WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
- DPRINT("Got wait block: %x\n", WaitBlock);
- Thread = WaitBlock->Thread;
-
- /* Reset the wait reason */
- Thread->WaitReason = 0;
-
- /* Increase the active threads and set the status*/
- Queue->CurrentCount++;
- Thread->WaitStatus = (NTSTATUS)Entry;
-
- /* Check if there's a Thread Timer */
- 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;
- RemoveEntryList(&Thread->Timer.TimerListEntry);
- }
-
- /* Reschedule the Thread */
- DPRINT("Unblocking the Thread\n");
- KiUnblockThread(Thread, (PNTSTATUS)&Entry, 0);
- }
- else
- {
- /* Increase the Entries */
- DPRINT("Adding new Queue Entry: %d %d\n", Head,
Queue->Header.SignalState);
- Queue->Header.SignalState++;
-
- /* Check which mode we're using */
- if (Head)
- {
- /* Insert in the head */
- InsertHeadList(&Queue->EntryListHead, Entry);
- }
- else
- {
- /* Insert at the end */
- InsertTailList(&Queue->EntryListHead, Entry);
- }
- }
-
- /* Return the previous state */
- DPRINT("Returning\n");
- return InitialState;
-}
-
/* EOF */