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=230... ============================================================================== --- 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=230... ============================================================================== --- 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@relsoft.net) + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Gunnar Dalsnes * Eric Kohl (ekohl@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 */