diff --git a/reactos/ntoskrnl/ke/apc.c b/reactos/ntoskrnl/ke/apc.c index 36c0965d5c4..a495ed74c61 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -124,7 +124,7 @@ KeInsertQueueApc (PKAPC Apc, PLIST_ENTRY ApcListEntry; PKAPC QueuedApc; - ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); DPRINT ("KeInsertQueueApc(Apc %x, SystemArgument1 %x, " "SystemArgument2 %x)\n",Apc,SystemArgument1, SystemArgument2); @@ -134,7 +134,9 @@ KeInsertQueueApc (PKAPC Apc, /* Get the Thread specified in the APC */ Thread = Apc->Thread; - /* Make sure the thread allows APC Queues */ + /* Make sure the thread allows APC Queues. + * The thread is not apc queueable, for instance, when it's (about to be) terminated. + */ if (Thread->ApcQueueable == FALSE) { DPRINT("Thread doesn't allow APC Queues\n"); KeReleaseDispatcherDatabaseLock(OldIrql); @@ -194,18 +196,20 @@ KeInsertQueueApc (PKAPC Apc, /* FIXME: Use IPI */ DPRINT ("Requesting APC Interrupt for Running Thread \n"); HalRequestSoftwareInterrupt(APC_LEVEL); - } else if ((Thread->WaitIrql < APC_LEVEL) && (Apc->NormalRoutine == NULL)) { + } else if ((Thread->State == THREAD_STATE_BLOCKED) && + (Thread->WaitIrql < APC_LEVEL) && + (Apc->NormalRoutine == NULL)) + { DPRINT ("Waking up Thread for Kernel-Mode APC Delivery \n"); - KeRemoveAllWaitsThread(CONTAINING_RECORD(Thread, ETHREAD, Tcb), - STATUS_KERNEL_APC, - TRUE); + KiAbortWaitThread(Thread, STATUS_KERNEL_APC); } - } else if ((Thread->WaitMode == UserMode) && (Thread->Alertable)) { + } else if ((Thread->State == THREAD_STATE_BLOCKED) && + (Thread->WaitMode == UserMode) && + (Thread->Alertable)) + { DPRINT ("Waking up Thread for User-Mode APC Delivery \n"); Thread->ApcState.UserApcPending = TRUE; - KeRemoveAllWaitsThread(CONTAINING_RECORD(Thread, ETHREAD, Tcb), - STATUS_USER_APC, - TRUE); + KiAbortWaitThread(Thread, STATUS_USER_APC); } /* Return Sucess if we are here */ @@ -227,7 +231,7 @@ KeRemoveQueueApc (PKAPC Apc) KIRQL OldIrql; PKTHREAD Thread = Apc->Thread; - ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc); OldIrql = KeAcquireDispatcherDatabaseLock(); @@ -270,7 +274,7 @@ KeTestAlertThread(IN KPROCESSOR_MODE AlertMode) PKTHREAD Thread = KeGetCurrentThread(); BOOLEAN OldState; - ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); OldIrql = KeAcquireDispatcherDatabaseLock(); KiAcquireSpinLock(&Thread->ApcQueueLock); @@ -295,7 +299,7 @@ KeTestAlertThread(IN KPROCESSOR_MODE AlertMode) */ VOID STDCALL -KiDeliverApc(KPROCESSOR_MODE PreviousMode, +KiDeliverApc(KPROCESSOR_MODE DeliveryMode, PVOID Reserved, PKTRAP_FRAME TrapFrame) /* @@ -317,6 +321,8 @@ KiDeliverApc(KPROCESSOR_MODE PreviousMode, PKNORMAL_ROUTINE NormalRoutine; PVOID SystemArgument1; PVOID SystemArgument2; + + ASSERT_IRQL_EQUAL(APC_LEVEL); /* Lock the APC Queue and Raise IRQL to Synch */ KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); @@ -339,7 +345,7 @@ KiDeliverApc(KPROCESSOR_MODE PreviousMode, SystemArgument2 = Apc->SystemArgument2; /* Special APC */ - if (NormalRoutine == NULL) { + if (NormalRoutine == NULL) { /* Remove the APC from the list */ Apc->Inserted = FALSE; RemoveEntryList(ApcListEntry); @@ -360,6 +366,15 @@ KiDeliverApc(KPROCESSOR_MODE PreviousMode, } else { /* Normal Kernel APC */ if (Thread->ApcState.KernelApcInProgress || Thread->KernelApcDisable) { + + /* + * DeliveryMode must be KernelMode in this case, since one may not + * return to umode while being inside a critical section or while + * a regular kmode apc is running (the latter should be impossible btw). + * -Gunnar + */ + ASSERT(DeliveryMode == KernelMode); + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); return; } @@ -399,7 +414,7 @@ KiDeliverApc(KPROCESSOR_MODE PreviousMode, /* Now we do the User APCs */ if ((!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) && - (PreviousMode == UserMode) && + (DeliveryMode == UserMode) && (Thread->ApcState.UserApcPending == TRUE)) { /* It's not pending anymore */ @@ -418,6 +433,8 @@ KiDeliverApc(KPROCESSOR_MODE PreviousMode, /* Remove the APC from Queue, restore IRQL and call the APC */ RemoveEntryList(ApcListEntry); + Apc->Inserted = FALSE; + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); DPRINT("Calling the Kernel Routine for for a User APC: %x\n", Apc); KernelRoutine(Apc, diff --git a/reactos/ntoskrnl/ke/critical.c b/reactos/ntoskrnl/ke/critical.c index 674919bbba1..a785597ef77 100644 --- a/reactos/ntoskrnl/ke/critical.c +++ b/reactos/ntoskrnl/ke/critical.c @@ -1,4 +1,4 @@ -/* $Id: critical.c,v 1.10 2004/08/15 16:39:05 chorns Exp $ +/* $Id: critical.c,v 1.11 2004/11/21 18:33:54 gdalsnes Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -22,8 +22,13 @@ */ VOID STDCALL KeEnterCriticalRegion (VOID) { + PKTHREAD Thread = KeGetCurrentThread(); + DPRINT("KeEnterCriticalRegion()\n"); - KeGetCurrentThread()->KernelApcDisable--; + + if (!Thread) return; /* <-Early in the boot process the current thread is obseved to be NULL */ + + Thread->KernelApcDisable--; } /* @@ -34,6 +39,8 @@ VOID STDCALL KeLeaveCriticalRegion (VOID) PKTHREAD Thread = KeGetCurrentThread(); DPRINT("KeLeaveCriticalRegion()\n"); + + if (!Thread) return; /* <-Early in the boot process the current thread is obseved to be NULL */ /* Reference: http://www.ntfsd.org/archive/ntfsd0104/msg0203.html */ if(++Thread->KernelApcDisable == 0) diff --git a/reactos/ntoskrnl/ke/event.c b/reactos/ntoskrnl/ke/event.c index c3d7eed0b95..8f536fd39c4 100644 --- a/reactos/ntoskrnl/ke/event.c +++ b/reactos/ntoskrnl/ke/event.c @@ -67,6 +67,9 @@ LONG STDCALL KeReadStateEvent (PKEVENT Event) */ LONG STDCALL KeResetEvent (PKEVENT Event) { + /* FIXME: must use interlocked func. everywhere! (wait.c) + * or use dispather lock instead + * -Gunnar */ return(InterlockedExchange(&(Event->Header.SignalState),0)); } @@ -86,7 +89,7 @@ LONG STDCALL KeSetEvent (PKEVENT Event, ret = InterlockedExchange(&(Event->Header.SignalState),1); - KeDispatcherObjectWake((DISPATCHER_HEADER *)Event); + KiDispatcherObjectWake((DISPATCHER_HEADER *)Event); if (Wait == FALSE) { @@ -115,7 +118,7 @@ NTSTATUS STDCALL KePulseEvent (PKEVENT Event, DPRINT("KePulseEvent(Event %x, Wait %x)\n",Event,Wait); OldIrql = KeAcquireDispatcherDatabaseLock(); ret = InterlockedExchange(&(Event->Header.SignalState),1); - KeDispatcherObjectWake((DISPATCHER_HEADER *)Event); + KiDispatcherObjectWake((DISPATCHER_HEADER *)Event); InterlockedExchange(&(Event->Header.SignalState),0); if (Wait == FALSE) @@ -143,7 +146,10 @@ KeSetEventBoostPriority( ) { PKTHREAD WaitingThread; + KIRQL OldIrql; + OldIrql = KeAcquireDispatcherDatabaseLock(); + /* Get Thread that is currently waiting. First get the Wait Block, then the Thread */ WaitingThread = CONTAINING_RECORD(Event->Header.WaitListHead.Flink, KWAIT_BLOCK, WaitListEntry)->Thread; @@ -152,7 +158,9 @@ KeSetEventBoostPriority( /* Reset the Quantum and Unwait the Thread */ WaitingThread->Quantum = WaitingThread->ApcState.Process->ThreadQuantum; - KeRemoveAllWaitsThread((PETHREAD)WaitingThread, STATUS_SUCCESS, TRUE); + KiAbortWaitThread(WaitingThread, STATUS_SUCCESS); + + KeReleaseDispatcherDatabaseLock(OldIrql); } /* EOF */ diff --git a/reactos/ntoskrnl/ke/mutex.c b/reactos/ntoskrnl/ke/mutex.c index 4ee6ecd25ab..539638a8dc3 100644 --- a/reactos/ntoskrnl/ke/mutex.c +++ b/reactos/ntoskrnl/ke/mutex.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: mutex.c,v 1.18 2004/10/22 20:30:48 ekohl Exp $ +/* $Id: mutex.c,v 1.19 2004/11/21 18:33:54 gdalsnes Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/mutex.c @@ -82,7 +82,7 @@ KeReleaseMutex(IN PKMUTEX Mutex, Mutex->OwnerThread = NULL; if (Mutex->MutantListEntry.Flink && Mutex->MutantListEntry.Blink) RemoveEntryList(&Mutex->MutantListEntry); - KeDispatcherObjectWake(&Mutex->Header); + KiDispatcherObjectWake(&Mutex->Header); } if (Wait == FALSE) @@ -191,7 +191,7 @@ KeReleaseMutant(IN PKMUTANT Mutant, Mutant->OwnerThread = NULL; if (Mutant->MutantListEntry.Flink && Mutant->MutantListEntry.Blink) RemoveEntryList(&Mutant->MutantListEntry); - KeDispatcherObjectWake(&Mutant->Header); + KiDispatcherObjectWake(&Mutant->Header); } if (Wait == FALSE) diff --git a/reactos/ntoskrnl/ke/queue.c b/reactos/ntoskrnl/ke/queue.c index adef5aa9729..6a16417f4d2 100644 --- a/reactos/ntoskrnl/ke/queue.c +++ b/reactos/ntoskrnl/ke/queue.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: queue.c,v 1.11 2004/08/15 16:39:05 chorns Exp $ +/* $Id: queue.c,v 1.12 2004/11/21 18:33:54 gdalsnes Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/queue.c @@ -34,6 +34,7 @@ /* FUNCTIONS *****************************************************************/ + /* * @implemented */ @@ -54,6 +55,8 @@ KeInitializeQueue(IN PKQUEUE Queue, /* * @implemented + * + * Returns number of entries in the queue */ LONG STDCALL KeReadStateQueue(IN PKQUEUE Queue) @@ -61,7 +64,9 @@ KeReadStateQueue(IN PKQUEUE Queue) return(Queue->Header.SignalState); } - +/* + * Returns the previous number of entries in the queue + */ LONG STDCALL KiInsertQueue( IN PKQUEUE Queue, @@ -70,15 +75,11 @@ KiInsertQueue( ) { ULONG InitialState; - KIRQL OldIrql; DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue, Entry); - OldIrql = KeAcquireDispatcherDatabaseLock (); - InitialState = Queue->Header.SignalState; - Queue->Header.SignalState++; - + if (Head) { InsertHeadList(&Queue->EntryListHead, Entry); @@ -87,13 +88,21 @@ KiInsertQueue( { InsertTailList(&Queue->EntryListHead, Entry); } - - if (Queue->CurrentCount < Queue->MaximumCount && InitialState == 0) + + //inc. num entries in queue + Queue->Header.SignalState++; + + /* Why the KeGetCurrentThread()->Queue != Queue? + * KiInsertQueue might be called from an APC for the current thread. + * -Gunnar + */ + if (Queue->CurrentCount < Queue->MaximumCount && + !IsListEmpty(&Queue->Header.WaitListHead) && + KeGetCurrentThread()->Queue != Queue) { - KeDispatcherObjectWake(&Queue->Header); + KiDispatcherObjectWake(&Queue->Header); } - KeReleaseDispatcherDatabaseLock(OldIrql); return InitialState; } @@ -106,7 +115,14 @@ LONG STDCALL KeInsertHeadQueue(IN PKQUEUE Queue, IN PLIST_ENTRY Entry) { - return KiInsertQueue(Queue,Entry,TRUE); + LONG Result; + KIRQL OldIrql; + + OldIrql = KeAcquireDispatcherDatabaseLock(); + Result = KiInsertQueue(Queue,Entry,TRUE); + KeReleaseDispatcherDatabaseLock(OldIrql); + + return Result; } @@ -117,7 +133,14 @@ LONG STDCALL KeInsertQueue(IN PKQUEUE Queue, IN PLIST_ENTRY Entry) { - return KiInsertQueue(Queue,Entry,FALSE); + LONG Result; + KIRQL OldIrql; + + OldIrql = KeAcquireDispatcherDatabaseLock(); + Result = KiInsertQueue(Queue,Entry,FALSE); + KeReleaseDispatcherDatabaseLock(OldIrql); + + return Result; } @@ -129,6 +152,7 @@ KeRemoveQueue(IN PKQUEUE Queue, IN KPROCESSOR_MODE WaitMode, IN PLARGE_INTEGER Timeout OPTIONAL) { + PLIST_ENTRY ListEntry; NTSTATUS Status; PKTHREAD Thread = KeGetCurrentThread(); @@ -136,50 +160,75 @@ KeRemoveQueue(IN PKQUEUE Queue, OldIrql = KeAcquireDispatcherDatabaseLock (); - //assiciate new thread with queue? if (Thread->Queue != Queue) { - //remove association from other queue - if (!IsListEmpty(&Thread->QueueListEntry)) + /* + * INVESTIGATE: What is the Thread->QueueListEntry used for? It's linked it into the + * Queue->ThreadListHead when the thread registers with the queue and unlinked when + * the thread registers with a new queue. The Thread->Queue already tells us what + * queue the thread is registered with. + * -Gunnar + */ + + //unregister thread from previous queue (if any) + if (Thread->Queue) { RemoveEntryList(&Thread->QueueListEntry); + Thread->Queue->CurrentCount--; + + if (Thread->Queue->CurrentCount < Thread->Queue->MaximumCount && + !IsListEmpty(&Thread->Queue->EntryListHead)) + { + KiDispatcherObjectWake(&Thread->Queue->Header); + } } - //associate with this queue - InsertHeadList(&Queue->ThreadListHead, &Thread->QueueListEntry); - Queue->CurrentCount++; + // register thread with this queue + InsertTailList(&Queue->ThreadListHead, &Thread->QueueListEntry); Thread->Queue = Queue; } + else /* if (Thread->Queue == Queue) */ + { + //dec. num running threads + Queue->CurrentCount--; + } - if (Queue->CurrentCount <= Queue->MaximumCount && !IsListEmpty(&Queue->EntryListHead)) + + + + while (TRUE) { - ListEntry = RemoveHeadList(&Queue->EntryListHead); - Queue->Header.SignalState--; - KeReleaseDispatcherDatabaseLock (OldIrql); - return ListEntry; + if (Queue->CurrentCount < Queue->MaximumCount && !IsListEmpty(&Queue->EntryListHead)) + { + ListEntry = RemoveHeadList(&Queue->EntryListHead); + //dec. num entries in queue + Queue->Header.SignalState--; + //inc. num running threads + Queue->CurrentCount++; + + KeReleaseDispatcherDatabaseLock(OldIrql); + return ListEntry; + } + else + { + //inform KeWaitXxx that we are holding disp. lock + Thread->WaitNext = TRUE; + Thread->WaitIrql = OldIrql; + + Status = KeWaitForSingleObject(Queue, + WrQueue, + WaitMode, + TRUE, //bAlertable + Timeout); + + if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC) + { + return (PVOID)Status; + } + + OldIrql = KeAcquireDispatcherDatabaseLock (); + } } - - //need to wait for it... - KeReleaseDispatcherDatabaseLock (OldIrql); - - Status = KeWaitForSingleObject(Queue, - WrQueue, - WaitMode, - TRUE,//Alertable, - Timeout); - - if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC) - { - return (PVOID)Status; - } - else - { - OldIrql = KeAcquireDispatcherDatabaseLock (); - ListEntry = RemoveHeadList(&Queue->EntryListHead); - KeReleaseDispatcherDatabaseLock (OldIrql); - return ListEntry; - } - } @@ -195,23 +244,31 @@ KeRundownQueue(IN PKQUEUE Queue) DPRINT("KeRundownQueue(Queue %x)\n", Queue); - //FIXME: should we wake thread waiting on a queue? - + /* I'm just guessing how this should work:-/ + * -Gunnar + */ + OldIrql = KeAcquireDispatcherDatabaseLock (); - // Clear Queue and QueueListEntry members of all threads associated with this queue + //no thread must wait on queue at rundown + ASSERT(IsListEmpty(&Queue->Header.WaitListHead)); + + // unlink threads and clear their Thread->Queue while (!IsListEmpty(&Queue->ThreadListHead)) { EnumEntry = RemoveHeadList(&Queue->ThreadListHead); - InitializeListHead(EnumEntry); Thread = CONTAINING_RECORD(EnumEntry, KTHREAD, QueueListEntry); Thread->Queue = NULL; } - if (!IsListEmpty(&Queue->EntryListHead)) - EnumEntry = Queue->EntryListHead.Flink; - else + if (IsListEmpty(&Queue->EntryListHead)) + { EnumEntry = NULL; + } + else + { + EnumEntry = Queue->EntryListHead.Flink; + } KeReleaseDispatcherDatabaseLock (OldIrql); diff --git a/reactos/ntoskrnl/ke/sem.c b/reactos/ntoskrnl/ke/sem.c index af9eab89518..1ed2eb9935d 100644 --- a/reactos/ntoskrnl/ke/sem.c +++ b/reactos/ntoskrnl/ke/sem.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: sem.c,v 1.15 2004/08/15 16:39:05 chorns Exp $ +/* $Id: sem.c,v 1.16 2004/11/21 18:33:54 gdalsnes Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/sem.c @@ -105,7 +105,7 @@ KeReleaseSemaphore (PKSEMAPHORE Semaphore, Semaphore->Header.SignalState += Adjustment; if (InitialState == 0) { - KeDispatcherObjectWake(&Semaphore->Header); + KiDispatcherObjectWake(&Semaphore->Header); } if (Wait == FALSE) diff --git a/reactos/ntoskrnl/ke/timer.c b/reactos/ntoskrnl/ke/timer.c index ee66fb69047..bda7253b41d 100644 --- a/reactos/ntoskrnl/ke/timer.c +++ b/reactos/ntoskrnl/ke/timer.c @@ -1,4 +1,4 @@ -/* $Id: timer.c,v 1.89 2004/11/21 06:51:18 ion Exp $ +/* $Id: timer.c,v 1.90 2004/11/21 18:33:54 gdalsnes Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -526,11 +526,11 @@ HandleExpiredTimer(PKTIMER Timer) DPRINT("Finished dpc routine\n"); } - ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + ASSERT_IRQL_EQUAL(DISPATCH_LEVEL); KeAcquireDispatcherDatabaseLockAtDpcLevel(); Timer->Header.SignalState = TRUE; - KeDispatcherObjectWake(&Timer->Header); + KiDispatcherObjectWake(&Timer->Header); KeReleaseDispatcherDatabaseLockFromDpcLevel(); if (Timer->Period != 0) @@ -571,7 +571,7 @@ KeExpireTimers(PKDPC Dpc, DPRINT("KeExpireTimers()\n"); - ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + ASSERT_IRQL_EQUAL(DISPATCH_LEVEL); InitializeListHead(&TimerList); diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index 770bd960091..027b8874b44 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -110,6 +110,8 @@ KiSideEffectsBeforeWake(DISPATCHER_HEADER * hdr, break; case InternalQueueType: + break; + case InternalSemaphoreType: hdr->SignalState--; break; @@ -193,33 +195,31 @@ KiIsObjectSignalled(DISPATCHER_HEADER * hdr, } } -VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus, BOOL Unblock) +/* Must be called with the dispatcher lock held */ +BOOLEAN KiAbortWaitThread(PKTHREAD Thread, NTSTATUS WaitStatus) { - PKWAIT_BLOCK WaitBlock, PrevWaitBlock; - BOOLEAN WasWaiting = FALSE; + PKWAIT_BLOCK WaitBlock; + BOOLEAN WasWaiting; - WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList; - if (WaitBlock != NULL) - { - WasWaiting = TRUE; - } - while (WaitBlock != NULL) - { - if (WaitBlock->WaitListEntry.Flink != NULL && WaitBlock->WaitListEntry.Blink != NULL) - { - RemoveEntryList (&WaitBlock->WaitListEntry); - WaitBlock->WaitListEntry.Flink = WaitBlock->WaitListEntry.Blink = NULL; - } - PrevWaitBlock = WaitBlock; - WaitBlock = WaitBlock->NextWaitBlock; - PrevWaitBlock->NextWaitBlock = NULL; - } - Thread->Tcb.WaitBlockList = NULL; + /* if we are blocked, we must be waiting on something also */ + ASSERT((Thread->State == THREAD_STATE_BLOCKED) == (Thread->WaitBlockList != NULL)); - if (WasWaiting && Unblock) - { - PsUnblockThread(Thread, &WaitStatus); - } + WaitBlock = (PKWAIT_BLOCK)Thread->WaitBlockList; + WasWaiting = (WaitBlock != NULL); + + while (WaitBlock) + { + RemoveEntryList(&WaitBlock->WaitListEntry); + WaitBlock = WaitBlock->NextWaitBlock; + } + + Thread->WaitBlockList = NULL; + + if (WasWaiting) + { + PsUnblockThread((PETHREAD)Thread, &WaitStatus); + } + return WasWaiting; } static BOOLEAN @@ -260,11 +260,7 @@ KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER * hdr, DPRINT("WaitAny: Remove all wait blocks.\n"); for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock) { - if (Waiter->WaitListEntry.Flink != NULL && Waiter->WaitListEntry.Blink != NULL) - { - RemoveEntryList(&Waiter->WaitListEntry); - Waiter->WaitListEntry.Flink = Waiter->WaitListEntry.Blink = NULL; - } + RemoveEntryList(&Waiter->WaitListEntry); } WaiterHead->Thread->WaitBlockList = NULL; @@ -273,7 +269,7 @@ KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER * hdr, * If a WakeAll KiSideEffectsBeforeWake(hdr,.. will be called several times, * but thats ok since WakeAll objects has no sideeffects. */ - Abandoned = KiSideEffectsBeforeWake(hdr, WaiterHead->Thread) ? TRUE : Abandoned; + Abandoned |= KiSideEffectsBeforeWake(hdr, WaiterHead->Thread); } else { @@ -299,16 +295,11 @@ KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER * hdr, { for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock) { - if (Waiter->WaitListEntry.Flink != NULL && Waiter->WaitListEntry.Blink != NULL) - { - RemoveEntryList(&Waiter->WaitListEntry); - Waiter->WaitListEntry.Flink = Waiter->WaitListEntry.Blink = NULL; - } + RemoveEntryList(&Waiter->WaitListEntry); if (Waiter->WaitType == WaitAll) { - Abandoned = KiSideEffectsBeforeWake(Waiter->Object, Waiter->Thread) - ? TRUE : Abandoned; + Abandoned |= KiSideEffectsBeforeWake(Waiter->Object, Waiter->Thread); } //no WaitAny objects can possibly be signaled since we are here @@ -339,7 +330,7 @@ KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER * hdr, } -BOOLEAN KeDispatcherObjectWake(DISPATCHER_HEADER* hdr) +BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr) /* * FUNCTION: Wake threads waiting on a dispatcher object * NOTE: The exact semantics of waking are dependant on the type of object @@ -366,6 +357,8 @@ BOOLEAN KeDispatcherObjectWake(DISPATCHER_HEADER* hdr) return(KeDispatcherObjectWakeOne(hdr)); case InternalQueueType: + return(KeDispatcherObjectWakeOne(hdr)); + case InternalSemaphoreType: DPRINT("hdr->SignalState %d\n", hdr->SignalState); if(hdr->SignalState>0) @@ -483,7 +476,6 @@ KeWaitForMultipleObjects(ULONG Count, ULONG CountSignaled; ULONG i; NTSTATUS Status; - KIRQL WaitIrql; KIRQL OldIrql; BOOLEAN Abandoned; @@ -493,7 +485,6 @@ KeWaitForMultipleObjects(ULONG Count, ASSERT(0 < Count && Count <= EX_MAXIMUM_WAIT_OBJECTS); CurrentThread = KeGetCurrentThread(); - WaitIrql = KeGetCurrentIrql(); /* * Work out where we are going to put the wait blocks @@ -516,6 +507,8 @@ KeWaitForMultipleObjects(ULONG Count, } } + + /* * Set up the timeout if required */ @@ -528,9 +521,8 @@ KeWaitForMultipleObjects(ULONG Count, { if (CurrentThread->WaitNext) { + CurrentThread->WaitNext = FALSE; OldIrql = CurrentThread->WaitIrql; - CurrentThread->WaitNext = 0; - CurrentThread->WaitIrql = PASSIVE_LEVEL; } else { @@ -711,28 +703,33 @@ KeWaitForMultipleObjects(ULONG Count, &CurrentThread->WaitBlock[3].WaitListEntry); } - //io completion - if (CurrentThread->Queue) + //kernel queues + if (CurrentThread->Queue && WaitReason != WrQueue) { - CurrentThread->Queue->CurrentCount--; - if (WaitReason != WrQueue && CurrentThread->Queue->CurrentCount < CurrentThread->Queue->MaximumCount && + DPRINT("queue: sleep on something else\n"); + CurrentThread->Queue->CurrentCount--; + + //wake another thread + if (CurrentThread->Queue->CurrentCount < CurrentThread->Queue->MaximumCount && !IsListEmpty(&CurrentThread->Queue->EntryListHead)) { - KeDispatcherObjectWake(&CurrentThread->Queue->Header); + KiDispatcherObjectWake(&CurrentThread->Queue->Header); } } - PsBlockThread(&Status, Alertable, WaitMode, TRUE, WaitIrql, (UCHAR)WaitReason); + PsBlockThread(&Status, Alertable, WaitMode, TRUE, OldIrql, (UCHAR)WaitReason); - //io completion - if (CurrentThread->Queue) + //kernel queues + //FIXME: dispatcher lock not held here! + if (CurrentThread->Queue && WaitReason != WrQueue) { + DPRINT("queue: wake from something else\n"); CurrentThread->Queue->CurrentCount++; } - - - } - while (Status == STATUS_KERNEL_APC); + + + } while (Status == STATUS_KERNEL_APC); + if (Timeout != NULL) {