/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS project
- * FILE: ntoskrnl/ke/wait.c
- * PURPOSE: Manages non-busy waiting
- * PROGRAMMER: David Welch (welch@mcmail.com)
- * REVISION HISTORY:
- * 21/07/98: Created
- * 12/1/99: Phillip Susi: Fixed wake code in KeDispatcherObjectWake
- * so that things like KeWaitForXXX() return the correct value
- */
-
-/* NOTES ********************************************************************
- *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
+ * FILE: ntoskrnl/ke/wait.c
+ * PURPOSE: Manages waiting for Dispatcher Objects
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ * Gunnar Dalsnes
*/
/* INCLUDES ******************************************************************/
-#include <ddk/ntddk.h>
-#include <internal/ke.h>
-#include <internal/ps.h>
-#include <internal/ob.h>
-#include <internal/id.h>
-#include <ntos/ntdef.h>
+#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS ******************************************************************/
-static KSPIN_LOCK DispatcherDatabaseLock;
-static BOOLEAN WaitSet = FALSE;
-static KIRQL oldlvl = PASSIVE_LEVEL;
-static PKTHREAD Owner = NULL;
+KSPIN_LOCK DispatcherDatabaseLock;
-/* FUNCTIONS *****************************************************************/
+/* Tells us if the Timer or Event is a Syncronization or Notification Object */
+#define TIMER_OR_EVENT_TYPE 0x7L
-VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header,
- ULONG Type,
- ULONG Size,
- ULONG SignalState)
-{
- Header->Type = Type;
- Header->Absolute = 0;
- Header->Inserted = 0;
- Header->Size = Size;
- Header->SignalState = SignalState;
- InitializeListHead(&(Header->WaitListHead));
-}
+/* One of the Reserved Wait Blocks, this one is for the Thread's Timer */
+#define TIMER_WAIT_BLOCK 0x3L
-VOID KeAcquireDispatcherDatabaseLock(BOOLEAN Wait)
-/*
- * PURPOSE: Acquires the dispatcher database lock for the caller
- */
-{
- DPRINT("KeAcquireDispatcherDatabaseLock(Wait %x)\n",Wait);
- if (WaitSet && Owner == KeGetCurrentThread())
- {
- return;
- }
- KeAcquireSpinLock(&DispatcherDatabaseLock, &oldlvl);
- WaitSet = Wait;
- Owner = KeGetCurrentThread();
-}
+/* FUNCTIONS *****************************************************************/
-VOID KeReleaseDispatcherDatabaseLockAtDpcLevel(BOOLEAN Wait)
+BOOLEAN
+__inline
+FASTCALL
+KiCheckAlertability(BOOLEAN Alertable,
+ PKTHREAD Thread,
+ KPROCESSOR_MODE WaitMode,
+ PNTSTATUS Status)
{
- DPRINT("KeReleaseDispatcherDatabaseLockAtDpcLevel(Wait %x)\n", Wait);
- assert(Wait == WaitSet);
- if (!Wait)
+ /*
+ * 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 (Thread->Alerted[(int)WaitMode])
+ {
+ Thread->Alerted[(int)WaitMode] = FALSE;
+ DPRINT("Thread was Alerted in the specified Mode\n");
+ *Status = STATUS_ALERTED;
+ return TRUE;
+ }
+ 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");
+ Thread->ApcState.UserApcPending = TRUE;
+ *Status = STATUS_USER_APC;
+ return TRUE;
+ }
+ 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))
{
- Owner = NULL;
- KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock);
+ /*
+ * 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;
}
-}
-VOID KeReleaseDispatcherDatabaseLock(BOOLEAN Wait)
-{
- DPRINT("KeReleaseDispatcherDatabaseLock(Wait %x)\n",Wait);
- assert(Wait==WaitSet);
- if (!Wait)
- {
- Owner = NULL;
- KeReleaseSpinLock(&DispatcherDatabaseLock, oldlvl);
- }
+ /* Stay in the loop */
+ return FALSE;
}
-static VOID KiSideEffectsBeforeWake(DISPATCHER_HEADER* hdr,
- PKTHREAD Thread,
- PBOOLEAN Abandoned)
/*
- * FUNCTION: Perform side effects on object before a wait for a thread is
- * satisfied
+ * @implemented
+ *
+ * FUNCTION: Puts the current thread into an alertable or nonalertable
+ * wait state for a given internal
+ * ARGUMENTS:
+ * WaitMode = Processor mode in which the caller is waiting
+ * Altertable = Specifies if the wait is alertable
+ * Interval = Specifies the interval to wait
+ * RETURNS: Status
*/
+NTSTATUS
+STDCALL
+KeDelayExecutionThread(KPROCESSOR_MODE WaitMode,
+ BOOLEAN Alertable,
+ PLARGE_INTEGER Interval)
{
- if (Abandoned != NULL)
- *Abandoned = FALSE;
-
- switch (hdr->Type)
- {
- case InternalSynchronizationEvent:
- hdr->SignalState = 0;
- break;
-
- case InternalSemaphoreType:
- hdr->SignalState--;
- break;
-
- case InternalProcessType:
- break;
-
- case InternalThreadType:
- break;
-
- case InternalNotificationEvent:
- break;
-
- case InternalSynchronizationTimer:
- hdr->SignalState = FALSE;
- break;
-
- case InternalNotificationTimer:
- break;
-
- case InternalMutexType:
- {
- PKMUTEX Mutex;
-
- Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
- hdr->SignalState--;
- assert(hdr->SignalState <= 1);
- if (hdr->SignalState == 0)
- {
- if (Thread == NULL)
- {
- DPRINT1("Thread == NULL!\n");
- KeBugCheck(0);
- }
- if (Abandoned != NULL)
- *Abandoned = Mutex->Abandoned;
- if (Thread != NULL)
- InsertTailList(&Thread->MutantListHead,
- &Mutex->MutantListEntry);
- Mutex->OwnerThread = Thread;
- Mutex->Abandoned = FALSE;
- }
- }
- break;
-
- default:
- DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n",
- __FILE__,__LINE__,hdr);
- KeBugCheck(0);
- }
-}
-
-static BOOLEAN
-KiIsObjectSignalled(DISPATCHER_HEADER* hdr,
- PKTHREAD Thread,
- PBOOLEAN Abandoned)
-{
- if (Abandoned != NULL)
- *Abandoned = FALSE;
-
- if (hdr->Type == InternalMutexType)
- {
- PKMUTEX Mutex;
-
- Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
-
- assert(hdr->SignalState <= 1);
- if ((hdr->SignalState < 1 && Mutex->OwnerThread == Thread) ||
- hdr->SignalState == 1)
- {
- KiSideEffectsBeforeWake(hdr,
- Thread,
- Abandoned);
- return(TRUE);
- }
- else
- {
- return(FALSE);
- }
- }
- if (hdr->SignalState <= 0)
- {
- return(FALSE);
- }
- else
- {
- KiSideEffectsBeforeWake(hdr,
- Thread,
- Abandoned);
- return(TRUE);
- }
-}
+ PKWAIT_BLOCK TimerWaitBlock;
+ PKTIMER ThreadTimer;
+ PKTHREAD CurrentThread = KeGetCurrentThread();
+ NTSTATUS Status;
-VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus)
-{
- PKWAIT_BLOCK WaitBlock;
- BOOLEAN WasWaiting = FALSE;
-
- KeAcquireDispatcherDatabaseLock(FALSE);
-
- WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList;
- if (WaitBlock != NULL)
- {
- WasWaiting = TRUE;
- }
- while (WaitBlock != NULL)
- {
- RemoveEntryList(&WaitBlock->WaitListEntry);
- WaitBlock = WaitBlock->NextWaitBlock;
- }
- Thread->Tcb.WaitBlockList = NULL;
-
- if (WasWaiting)
- {
- PsUnblockThread(Thread, &WaitStatus);
- }
-
- KeReleaseDispatcherDatabaseLock(FALSE);
-}
+ DPRINT("Entering KeDelayExecutionThread\n");
-static BOOLEAN KeDispatcherObjectWakeAll(DISPATCHER_HEADER* hdr)
-{
- PKWAIT_BLOCK current;
- PLIST_ENTRY current_entry;
- PKWAIT_BLOCK PrevBlock;
- NTSTATUS Status;
- BOOLEAN Abandoned;
-
- DPRINT("KeDispatcherObjectWakeAll(hdr %x)\n",hdr);
-
- if (IsListEmpty(&hdr->WaitListHead))
+ /* Check if the lock is already held */
+ if (CurrentThread->WaitNext)
{
- return(FALSE);
+ /* Lock is held, disable Wait Next */
+ DPRINT("Lock is held\n");
+ CurrentThread->WaitNext = FALSE;
}
-
- while (!IsListEmpty(&hdr->WaitListHead))
+ else
{
- current_entry = RemoveHeadList(&hdr->WaitListHead);
- current = CONTAINING_RECORD(current_entry,
- KWAIT_BLOCK,
- WaitListEntry);
- DPRINT("Waking %x\n",current->Thread);
- if (current->WaitType == WaitAny)
- {
- DPRINT("WaitAny: Remove all wait blocks.\n");
- for(PrevBlock = current->Thread->WaitBlockList; PrevBlock;
- PrevBlock = PrevBlock->NextWaitBlock)
- {
- if (PrevBlock != current)
- RemoveEntryList(&PrevBlock->WaitListEntry);
- }
- current->Thread->WaitBlockList = 0;
- }
- else
- {
- DPRINT("WaitAll: Remove the current wait block only.\n");
-
- PrevBlock = current->Thread->WaitBlockList;
- if (PrevBlock == current)
- {
- DPRINT( "WaitAll: Current block is list head.\n" );
- current->Thread->WaitBlockList = current->NextWaitBlock;
- }
- else
- {
- DPRINT( "WaitAll: Current block is not list head.\n" );
- while (PrevBlock && PrevBlock->NextWaitBlock != current)
- {
- PrevBlock = PrevBlock->NextWaitBlock;
- }
- if (PrevBlock)
- {
- PrevBlock->NextWaitBlock = current->NextWaitBlock;
- }
- }
- }
- KiSideEffectsBeforeWake(hdr, current->Thread, &Abandoned);
- Status = current->WaitKey;
- if (Abandoned)
- Status += STATUS_ABANDONED_WAIT_0;
- if (current->Thread->WaitBlockList == NULL)
- {
- PsUnblockThread(CONTAINING_RECORD(current->Thread,ETHREAD,Tcb),
- &Status);
- }
+ /* Lock not held, acquire it */
+ DPRINT("Lock is not held, acquiring\n");
+ CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
}
- return(TRUE);
-}
-static BOOLEAN KeDispatcherObjectWakeOne(DISPATCHER_HEADER* hdr)
-{
- PKWAIT_BLOCK current;
- PLIST_ENTRY current_entry;
- PKWAIT_BLOCK PrevBlock;
- NTSTATUS Status;
- BOOLEAN Abandoned;
-
- DPRINT("KeDispatcherObjectWakeOn(hdr %x)\n",hdr);
- DPRINT("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n",
- hdr->WaitListHead.Flink,hdr->WaitListHead.Blink);
- if (IsListEmpty(&(hdr->WaitListHead)))
+ /* Use built-in Wait block */
+ TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
+
+ /* Start Wait Loop */
+ do
{
- return(FALSE);
- }
- current_entry = RemoveHeadList(&(hdr->WaitListHead));
- current = CONTAINING_RECORD(current_entry,KWAIT_BLOCK,
- WaitListEntry);
- DPRINT("current_entry %x current %x\n",current_entry,current);
-
- if (current->WaitType == WaitAny)
- {
- DPRINT("WaitAny: Remove all wait blocks.\n");
- for( PrevBlock = current->Thread->WaitBlockList; PrevBlock; PrevBlock = PrevBlock->NextWaitBlock )
- if( PrevBlock != current )
- RemoveEntryList( &(PrevBlock->WaitListEntry) );
- current->Thread->WaitBlockList = 0;
- }
- else
- {
- DPRINT("WaitAll: Remove the current wait block only.\n");
-
- PrevBlock = current->Thread->WaitBlockList;
- if (PrevBlock == current)
- {
- DPRINT( "WaitAll: Current block is list head.\n" );
- current->Thread->WaitBlockList = current->NextWaitBlock;
- }
- else
- {
- DPRINT( "WaitAll: Current block is not list head.\n" );
- while ( PrevBlock && PrevBlock->NextWaitBlock != current)
- {
- PrevBlock = PrevBlock->NextWaitBlock;
- }
- if (PrevBlock)
- {
- PrevBlock->NextWaitBlock = current->NextWaitBlock;
- }
- }
- }
+ /* Chceck if we can do an alertable wait, if requested */
+ if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status)) break;
+
+ /* Set Timer */
+ ThreadTimer = &CurrentThread->Timer;
+
+ /* Setup the Wait Block */
+ CurrentThread->WaitBlockList = TimerWaitBlock;
+ TimerWaitBlock->Object = (PVOID)ThreadTimer;
+ TimerWaitBlock->Thread = CurrentThread;
+ TimerWaitBlock->WaitKey = (USHORT)STATUS_TIMEOUT;
+ TimerWaitBlock->WaitType = WaitAny;
+ TimerWaitBlock->NextWaitBlock = TimerWaitBlock;
+
+ /* Link the timer to this Wait Block */
+ InitializeListHead(&ThreadTimer->Header.WaitListHead);
+ InsertTailList(&ThreadTimer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry);
+
+ /* Insert the Timer into the Timer Lists and enable it */
+ if (!KiInsertTimer(ThreadTimer, *Interval))
+ {
+ /* FIXME: The timer already expired, we should find a new ready thread */
+ Status = STATUS_SUCCESS;
+ break;
+ }
- DPRINT("Waking %x\n",current->Thread);
- KiSideEffectsBeforeWake(hdr, current->Thread, &Abandoned);
- Status = current->WaitKey;
- if (Abandoned)
- Status += STATUS_ABANDONED_WAIT_0;
- PsUnblockThread(CONTAINING_RECORD(current->Thread, ETHREAD, Tcb),
- &Status);
- return(TRUE);
-}
+ /* Handle Kernel Queues */
+ if (CurrentThread->Queue)
+ {
+ DPRINT("Waking Queue\n");
+ KiWakeQueue(CurrentThread->Queue);
+ }
-BOOLEAN KeDispatcherObjectWake(DISPATCHER_HEADER* hdr)
-/*
- * FUNCTION: Wake threads waiting on a dispatcher object
- * NOTE: The exact semantics of waking are dependant on the type of object
- */
-{
- BOOL Ret;
-
- DPRINT("Entering KeDispatcherObjectWake(hdr %x)\n",hdr);
-// DPRINT("hdr->WaitListHead %x hdr->WaitListHead.Flink %x\n",
-// &hdr->WaitListHead,hdr->WaitListHead.Flink);
- DPRINT("hdr->Type %x\n",hdr->Type);
- switch (hdr->Type)
- {
- case InternalNotificationEvent:
- return(KeDispatcherObjectWakeAll(hdr));
-
- case InternalNotificationTimer:
- return(KeDispatcherObjectWakeAll(hdr));
-
- case InternalSynchronizationEvent:
- return(KeDispatcherObjectWakeOne(hdr));
-
- case InternalSynchronizationTimer:
- return(KeDispatcherObjectWakeOne(hdr));
-
- case InternalSemaphoreType:
- DPRINT("hdr->SignalState %d\n", hdr->SignalState);
- if(hdr->SignalState>0)
- {
- do
- {
- DPRINT("Waking one semaphore waiter\n");
- Ret = KeDispatcherObjectWakeOne(hdr);
- } while(hdr->SignalState > 0 && Ret) ;
- return(Ret);
- }
- else return FALSE;
-
- case InternalProcessType:
- return(KeDispatcherObjectWakeAll(hdr));
-
- case InternalThreadType:
- return(KeDispatcherObjectWakeAll(hdr));
-
- case InternalMutexType:
- return(KeDispatcherObjectWakeOne(hdr));
- }
- DbgPrint("Dispatcher object %x has unknown type %d\n", hdr, hdr->Type);
- KeBugCheck(0);
- return(FALSE);
-}
+ /* Block the Thread */
+ 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)
+ {
+ /* This is a good thing */
+ if (Status == STATUS_TIMEOUT) Status = STATUS_SUCCESS;
+
+ /* Return Status */
+ return Status;
+ }
+
+ DPRINT("Looping Again\n"); // FIXME: Need to modify interval
+ CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+ }
+ while (TRUE);
+
+ /* Release the Lock, we are done */
+ DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n",
+ KeGetCurrentThread(), Status);
+ KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+ return Status;
+}
-NTSTATUS STDCALL
-KeWaitForSingleObject(PVOID Object,
- KWAIT_REASON WaitReason,
- KPROCESSOR_MODE WaitMode,
- BOOLEAN Alertable,
- PLARGE_INTEGER Timeout)
/*
+ * @implemented
+ *
* FUNCTION: Puts the current thread into a wait state until the
- * given dispatcher object is set to signalled
+ * given dispatcher object is set to signalled
* ARGUMENTS:
* Object = Object to wait on
* WaitReason = Reason for the wait (debugging aid)
* Timeout = Optional timeout value
* RETURNS: Status
*/
+NTSTATUS
+STDCALL
+KeWaitForSingleObject(PVOID Object,
+ KWAIT_REASON WaitReason,
+ KPROCESSOR_MODE WaitMode,
+ BOOLEAN Alertable,
+ PLARGE_INTEGER Timeout)
{
- DISPATCHER_HEADER* hdr = (DISPATCHER_HEADER *)Object;
- PKTHREAD CurrentThread;
- NTSTATUS Status;
- KIRQL WaitIrql;
- BOOLEAN Abandoned;
-
- CurrentThread = KeGetCurrentThread();
- WaitIrql = KeGetCurrentIrql();
-
- /*
- * Set up the timeout
- * FIXME: Check for zero timeout
- */
- if (Timeout != NULL)
- {
- KeInitializeTimer(&CurrentThread->Timer);
- KeSetTimer(&CurrentThread->Timer, *Timeout, NULL);
- }
-
- do
- {
- KeAcquireDispatcherDatabaseLock(FALSE);
-
- /*
- * If we are going to wait alertably and a user apc is pending
- * then return
- */
- if (Alertable && KiTestAlert())
- {
- KeReleaseDispatcherDatabaseLock(FALSE);
- return(STATUS_USER_APC);
- }
-
- /*
- * If the object is signalled
- */
- if (KiIsObjectSignalled(hdr, CurrentThread, &Abandoned))
- {
- KeReleaseDispatcherDatabaseLock(FALSE);
- if (Timeout != NULL)
- {
- KeCancelTimer(&KeGetCurrentThread()->Timer);
- }
- if (Abandoned == TRUE)
- return(STATUS_ABANDONED_WAIT_0);
- return(STATUS_WAIT_0);
- }
-
- /*
- * Check if we have already timed out
- */
- if (Timeout != NULL &&
- KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread, NULL))
- {
- KeReleaseDispatcherDatabaseLock(FALSE);
- if (Timeout != NULL)
- {
- KeCancelTimer(&KeGetCurrentThread()->Timer);
- }
- return(STATUS_TIMEOUT);
- }
-
- /*
- * Set up for a wait
- */
- CurrentThread->WaitStatus = STATUS_UNSUCCESSFUL;
- /* Append wait block to the KTHREAD wait block list */
- CurrentThread->WaitBlockList = &CurrentThread->WaitBlock[0];
- CurrentThread->WaitBlock[0].Object = Object;
- CurrentThread->WaitBlock[0].Thread = CurrentThread;
- CurrentThread->WaitBlock[0].WaitKey = STATUS_WAIT_0;
- CurrentThread->WaitBlock[0].WaitType = WaitAny;
- InsertTailList(&hdr->WaitListHead,
- &CurrentThread->WaitBlock[0].WaitListEntry);
- if (Timeout != NULL)
- {
- CurrentThread->WaitBlock[0].NextWaitBlock =
- &CurrentThread->WaitBlock[1];
- CurrentThread->WaitBlock[1].Object = (PVOID)&CurrentThread->Timer;
- CurrentThread->WaitBlock[1].Thread = CurrentThread;
- CurrentThread->WaitBlock[1].WaitKey = STATUS_TIMEOUT;
- CurrentThread->WaitBlock[1].WaitType = WaitAny;
- CurrentThread->WaitBlock[1].NextWaitBlock = NULL;
- InsertTailList(&CurrentThread->Timer.Header.WaitListHead,
- &CurrentThread->WaitBlock[1].WaitListEntry);
- }
- else
- {
- CurrentThread->WaitBlock[0].NextWaitBlock = NULL;
- }
- PsBlockThread(&Status, (UCHAR)Alertable, WaitMode, TRUE, WaitIrql);
- } while (Status == STATUS_KERNEL_APC);
-
- if (Timeout != NULL)
- {
- KeCancelTimer(&KeGetCurrentThread()->Timer);
- }
-
- DPRINT("Returning from KeWaitForSingleObject()\n");
- return(Status);
-}
+ 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)
+ {
+ /* Lock is held, disable Wait Next */
+ DPRINT("Lock is held\n");
+ CurrentThread->WaitNext = FALSE;
+ }
+ else
+ {
+ /* Lock not held, acquire it */
+ DPRINT("Lock is not held, acquiring\n");
+ CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+ }
+
+ /* Start the actual Loop */
+ do
+ {
+ /* Get the current Wait Status */
+ WaitStatus = CurrentThread->WaitStatus;
+
+ /* Append wait block to the KTHREAD wait block list */
+ CurrentThread->WaitBlockList = WaitBlock = &CurrentThread->WaitBlock[0];
+ /* Get the Current Object */
+ 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;
+ WaitBlock->Thread = CurrentThread;
+ WaitBlock->WaitKey = (USHORT)(STATUS_WAIT_0);
+ WaitBlock->WaitType = WaitAny;
+ WaitBlock->NextWaitBlock = WaitBlock;
+
+ /* Make sure we can satisfy the Alertable request */
+ 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)
+ {
+ /* Fail if the timeout interval is actually 0 */
+ if (!Timeout->QuadPart)
+ {
+ /* Return a timeout */
+ Status = STATUS_TIMEOUT;
+ goto DontWait;
+ }
+
+ /* Point to Timer Wait Block and Thread Timer */
+ TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
+ ThreadTimer = &CurrentThread->Timer;
+
+ /* Connect the Timer Wait Block */
+ WaitBlock->NextWaitBlock = TimerWaitBlock;
+
+ /* Set up the Timer Wait Block */
+ TimerWaitBlock->Object = (PVOID)ThreadTimer;
+ TimerWaitBlock->Thread = CurrentThread;
+ TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
+ TimerWaitBlock->WaitType = WaitAny;
+ TimerWaitBlock->NextWaitBlock = WaitBlock;
+
+ /* Link the timer to this Wait Block */
+ InitializeListHead(&ThreadTimer->Header.WaitListHead);
+ 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 */
+ Status = STATUS_TIMEOUT;
+ goto DontWait;
+ }
+ }
+
+ /* Link the Object to this Wait Block */
+ InsertTailList(&CurrentObject->Header.WaitListHead,
+ &WaitBlock->WaitListEntry);
+
+ /* Handle Kernel Queues */
+ 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());
+ KiBlockThread(&Status,
+ Alertable,
+ WaitMode,
+ (UCHAR)WaitReason);
+
+ /* Check if we were executing an APC */
+ if (Status != STATUS_KERNEL_APC)
+ {
+ /* Return Status */
+ return Status;
+ }
+
+ /* Loop again and acquire the dispatcher lock */
+ DPRINT("Looping Again\n"); // FIXME: Change interval
+ CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+ }
+ while (TRUE);
+
+ /* Release the Lock, we are done */
+ DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n",
+ KeGetCurrentThread(), Status);
+ KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+ return Status;
+
+DontWait:
+ /* Adjust the Quantum */
+ KiAdjustQuantumThread(CurrentThread);
+
+ /* Release & Return */
+ DPRINT("Quick-return from KeWaitForMultipleObjects(), %x. Status: %d\n.",
+ KeGetCurrentThread(), Status);
+ KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
NTSTATUS STDCALL
KeWaitForMultipleObjects(ULONG Count,
- PVOID Object[],
- WAIT_TYPE WaitType,
- KWAIT_REASON WaitReason,
- KPROCESSOR_MODE WaitMode,
- BOOLEAN Alertable,
- PLARGE_INTEGER Timeout,
- PKWAIT_BLOCK WaitBlockArray)
+ PVOID Object[],
+ WAIT_TYPE WaitType,
+ KWAIT_REASON WaitReason,
+ KPROCESSOR_MODE WaitMode,
+ BOOLEAN Alertable,
+ PLARGE_INTEGER Timeout,
+ PKWAIT_BLOCK WaitBlockArray)
{
- DISPATCHER_HEADER* hdr;
- PKWAIT_BLOCK blk;
- PKTHREAD CurrentThread;
- ULONG CountSignaled;
- ULONG i;
- NTSTATUS Status;
- KIRQL WaitIrql;
- BOOLEAN Abandoned;
-
- DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
- "PsGetCurrentThread() %x\n",Count,Object,PsGetCurrentThread());
-
- CountSignaled = 0;
- CurrentThread = KeGetCurrentThread();
- WaitIrql = KeGetCurrentIrql();
-
- /*
- * Work out where we are going to put the wait blocks
- */
- if (WaitBlockArray == NULL)
+ PKMUTANT CurrentObject;
+ PKWAIT_BLOCK WaitBlock;
+ PKWAIT_BLOCK TimerWaitBlock;
+ PKTIMER ThreadTimer;
+ PKTHREAD CurrentThread = KeGetCurrentThread();
+ ULONG AllObjectsSignaled;
+ ULONG WaitIndex;
+ NTSTATUS Status;
+ NTSTATUS WaitStatus;
+ DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
+ "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 (Count > THREAD_WAIT_OBJECTS)
- {
- DbgPrint("(%s:%d) Too many objects!\n",
- __FILE__,__LINE__);
- return(STATUS_UNSUCCESSFUL);
- }
- blk = &CurrentThread->WaitBlock[0];
+ /* Lock is held, disable Wait Next */
+ DPRINT("Lock is held\n");
+ CurrentThread->WaitNext = FALSE;
}
- else
+ else
{
- if (Count > EX_MAXIMUM_WAIT_OBJECTS)
- {
- DbgPrint("(%s:%d) Too many objects!\n",
- __FILE__,__LINE__);
- return(STATUS_UNSUCCESSFUL);
- }
- blk = WaitBlockArray;
+ /* Lock not held, acquire it */
+ DPRINT("Lock is not held, acquiring\n");
+ CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
}
- /*
- * Set up the timeout if required
- */
- if (Timeout != NULL)
+ /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
+ if (!WaitBlockArray)
{
- KeInitializeTimer(&CurrentThread->Timer);
- KeSetTimer(&CurrentThread->Timer, *Timeout, NULL);
+ /* Check in regards to the Thread Object Limit */
+ if (Count > THREAD_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
+
+ /* Use the Thread's Wait Block */
+ WaitBlockArray = &CurrentThread->WaitBlock[0];
}
-
- do
- {
- KeAcquireDispatcherDatabaseLock(FALSE);
-
- /*
- * If we are going to wait alertably and a user apc is pending
- * then return
- */
- if (Alertable && KiTestAlert())
- {
- KeReleaseDispatcherDatabaseLock(FALSE);
- return(STATUS_USER_APC);
- }
-
- /*
- * Check if the wait is already satisfied
- */
- for (i = 0; i < Count; i++)
- {
- hdr = (DISPATCHER_HEADER *)Object[i];
-
- if (KiIsObjectSignalled(hdr, CurrentThread, &Abandoned))
- {
- CountSignaled++;
-
- if (WaitType == WaitAny)
- {
- KeReleaseDispatcherDatabaseLock(FALSE);
- DPRINT("One object is already signaled!\n");
- if (Abandoned == TRUE)
- return(STATUS_ABANDONED_WAIT_0 + i);
- return(STATUS_WAIT_0 + i);
- }
- }
- }
-
- if ((WaitType == WaitAll) && (CountSignaled == Count))
- {
- KeReleaseDispatcherDatabaseLock(FALSE);
- DPRINT("All objects are already signaled!\n");
- return(STATUS_WAIT_0);
- }
-
- /*
- * Check if we have already timed out
- */
- if (Timeout != NULL &&
- KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread, NULL))
- {
- KeReleaseDispatcherDatabaseLock(FALSE);
- if (Timeout != NULL)
- {
- KeCancelTimer(&KeGetCurrentThread()->Timer);
- }
- return(STATUS_TIMEOUT);
- }
-
- /* Append wait block to the KTHREAD wait block list */
- CurrentThread->WaitBlockList = blk;
-
- /*
- * Set up the wait
- */
- for (i = 0; i < Count; i++)
- {
- hdr = (DISPATCHER_HEADER *)Object[i];
-
- blk->Object = Object[i];
- blk->Thread = CurrentThread;
- blk->WaitKey = STATUS_WAIT_0 + i;
- blk->WaitType = WaitType;
- if (i == (Count - 1))
- {
- if (Timeout != NULL)
- {
- blk->NextWaitBlock = &CurrentThread->WaitBlock[3];
- }
- else
- {
- blk->NextWaitBlock = NULL;
- }
- }
- else
- {
- blk->NextWaitBlock = blk + 1;
- }
-
- InsertTailList(&hdr->WaitListHead, &blk->WaitListEntry);
-
- blk = blk->NextWaitBlock;
- }
- if (Timeout != NULL)
- {
- CurrentThread->WaitBlock[3].Object = (PVOID)&CurrentThread->Timer;
- CurrentThread->WaitBlock[3].Thread = CurrentThread;
- CurrentThread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
- CurrentThread->WaitBlock[3].WaitType = WaitAny;
- CurrentThread->WaitBlock[3].NextWaitBlock = NULL;
- InsertTailList(&CurrentThread->Timer.Header.WaitListHead,
- &CurrentThread->WaitBlock[3].WaitListEntry);
- }
-
- PsBlockThread(&Status, Alertable, WaitMode, TRUE, WaitIrql);
- } while(Status == STATUS_KERNEL_APC);
-
- if (Timeout != NULL)
+ else
{
- KeCancelTimer(&KeGetCurrentThread()->Timer);
+ /* Using our own Block Array. Check in regards to System Object Limit */
+ if (Count > MAXIMUM_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
}
- DPRINT("Returning from KeWaitForMultipleObjects()\n");
- return(Status);
+ /* Start the actual Loop */
+ do
+ {
+ /* Get the current Wait Status */
+ WaitStatus = CurrentThread->WaitStatus;
+
+ /* Append wait block to the KTHREAD wait block list */
+ CurrentThread->WaitBlockList = WaitBlock = WaitBlockArray;
+
+ /* Check if the wait is (already) satisfied */
+ AllObjectsSignaled = TRUE;
+
+ /* First, we'll try to satisfy the wait directly */
+ for (WaitIndex = 0; WaitIndex < Count; WaitIndex++)
+ {
+ /* Get the Current Object */
+ 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 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)WaitIndex;
+ WaitBlock->WaitType = (USHORT)WaitType;
+ WaitBlock->NextWaitBlock = WaitBlock + 1;
+
+ /* Move to the next Wait Block */
+ WaitBlock = WaitBlock->NextWaitBlock;
+ }
+
+ /* Return to the Root Wait Block */
+ WaitBlock--;
+ WaitBlock->NextWaitBlock = WaitBlockArray;
+
+ /* Check if this is a Wait All and all the objects are signaled */
+ if ((WaitType == WaitAll) && (AllObjectsSignaled))
+ {
+ /* Return to the Root Wait Block */
+ WaitBlock = CurrentThread->WaitBlockList;
+
+ /* Satisfy their Waits and return to the caller */
+ KiSatisifyMultipleObjectWaits(WaitBlock);
+ Status = STATUS_WAIT_0;
+ goto DontWait;
+ }
+
+ /* Make sure we can satisfy the Alertable request */
+ 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)
+ {
+ /* Make sure the timeout interval isn't actually 0 */
+ if (!Timeout->QuadPart)
+ {
+ /* Return a timeout */
+ Status = STATUS_TIMEOUT;
+ goto DontWait;
+ }
+
+ /* Point to Timer Wait Block and Thread Timer */
+ TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
+ ThreadTimer = &CurrentThread->Timer;
+
+ /* Connect the Timer Wait Block */
+ WaitBlock->NextWaitBlock = TimerWaitBlock;
+
+ /* Set up the Timer Wait Block */
+ TimerWaitBlock->Object = (PVOID)ThreadTimer;
+ TimerWaitBlock->Thread = CurrentThread;
+ TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
+ TimerWaitBlock->WaitType = WaitAny;
+ TimerWaitBlock->NextWaitBlock = WaitBlockArray;
+
+ /* Link the timer to this Wait Block */
+ 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 */
+ Status = STATUS_TIMEOUT;
+ goto DontWait;
+ }
+ }
+
+ /* Insert into Object's Wait List*/
+ WaitBlock = CurrentThread->WaitBlockList;
+ do
+ {
+ /* Get the Current Object */
+ CurrentObject = WaitBlock->Object;
+
+ /* Link the Object to this Wait Block */
+ InsertTailList(&CurrentObject->Header.WaitListHead,
+ &WaitBlock->WaitListEntry);
+
+ /* Move to the next Wait Block */
+ WaitBlock = WaitBlock->NextWaitBlock;
+ }
+ while (WaitBlock != WaitBlockArray);
+
+ /* Handle Kernel Queues */
+ 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());
+ KiBlockThread(&Status,
+ Alertable,
+ WaitMode,
+ (UCHAR)WaitReason);
+
+ /* Check if we were executing an APC */
+ DPRINT("Thread is back\n");
+ if (Status != STATUS_KERNEL_APC)
+ {
+ /* Return Status */
+ return Status;
+ }
+
+ /* Loop again and re-acquire the dispatcher lock */
+ DPRINT("Looping Again\n"); // FIXME: Fix-up the interval */
+ CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+ }
+ while (TRUE);
+
+ /* Release the Lock, we are done */
+ DPRINT("Returning, %x. Status: %d\n", KeGetCurrentThread(), Status);
+ KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+ return Status;
+
+DontWait:
+ /* Adjust the Quantum */
+ KiAdjustQuantumThread(CurrentThread);
+
+ /* Release & Return */
+ DPRINT("Returning, %x. Status: %d\n. We did not wait.",
+ KeGetCurrentThread(), Status);
+ KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
+ return Status;
}
-VOID KeInitializeDispatcher(VOID)
+VOID
+FASTCALL
+KiWaitTest(PVOID ObjectPointer,
+ KPRIORITY Increment)
{
- KeInitializeSpinLock(&DispatcherDatabaseLock);
+ PLIST_ENTRY WaitEntry;
+ PLIST_ENTRY WaitList;
+ PKWAIT_BLOCK CurrentWaitBlock;
+ PKWAIT_BLOCK NextWaitBlock;
+ PKTHREAD WaitThread;
+ PKMUTANT FirstObject = ObjectPointer, Object;
+
+ /* Loop the Wait Entries */
+ DPRINT("KiWaitTest for Object: %x\n", FirstObject);
+ WaitList = &FirstObject->Header.WaitListHead;
+ WaitEntry = WaitList->Flink;
+ while ((FirstObject->Header.SignalState > 0) && (WaitEntry != WaitList))
+ {
+ /* Get the current wait block */
+ CurrentWaitBlock = CONTAINING_RECORD(WaitEntry,
+ KWAIT_BLOCK,
+ WaitListEntry);
+ WaitThread = CurrentWaitBlock->Thread;
+
+ /* Check the current Wait Mode */
+ if (CurrentWaitBlock->WaitType == WaitAny)
+ {
+ /* Easy case, satisfy only this wait */
+ DPRINT("Satisfiying a Wait any\n");
+ WaitEntry = WaitEntry->Blink;
+ 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)
+ {
+ /* Check if the object is signaled */
+ 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 */
+ NextWaitBlock = NextWaitBlock->NextWaitBlock;
+ }
+
+ /* All the objects are signaled, we can satisfy */
+ DPRINT("Satisfiying a Wait All\n");
+ WaitEntry = WaitEntry->Blink;
+ KiSatisifyMultipleObjectWaits(CurrentWaitBlock);
+ }
+
+ /* All waits satisfied, unwait the thread */
+ DPRINT("Unwaiting the Thread\n");
+ KiAbortWaitThread(WaitThread, CurrentWaitBlock->WaitKey, Increment);
+
+SkipUnwait:
+ /* Next entry */
+ WaitEntry = WaitEntry->Flink;
+ }
+
+ DPRINT("Done\n");
}
-NTSTATUS STDCALL
-NtWaitForMultipleObjects(IN ULONG Count,
- IN HANDLE Object [],
- IN CINT WaitType,
- IN BOOLEAN Alertable,
- IN PLARGE_INTEGER Time)
+/* Must be called with the dispatcher lock held */
+VOID
+FASTCALL
+KiAbortWaitThread(PKTHREAD Thread,
+ NTSTATUS WaitStatus,
+ KPRIORITY Increment)
{
- KWAIT_BLOCK WaitBlockArray[EX_MAXIMUM_WAIT_OBJECTS];
- PVOID ObjectPtrArray[EX_MAXIMUM_WAIT_OBJECTS];
- NTSTATUS Status;
- ULONG i, j;
-
- DPRINT("NtWaitForMultipleObjects(Count %lu Object[] %x, Alertable %d, "
- "Time %x)\n", Count,Object,Alertable,Time);
-
- if (Count > EX_MAXIMUM_WAIT_OBJECTS)
- return STATUS_UNSUCCESSFUL;
-
- /* reference all objects */
- for (i = 0; i < Count; i++)
- {
- Status = ObReferenceObjectByHandle(Object[i],
- SYNCHRONIZE,
- NULL,
- UserMode,
- &ObjectPtrArray[i],
- NULL);
- if (Status != STATUS_SUCCESS)
- {
- /* dereference all referenced objects */
- for (j = 0; j < i; i++)
- {
- ObDereferenceObject(ObjectPtrArray[j]);
- }
-
- return(Status);
- }
- }
-
- Status = KeWaitForMultipleObjects(Count,
- ObjectPtrArray,
- WaitType,
- UserRequest,
- UserMode,
- Alertable,
- Time,
- WaitBlockArray);
-
- /* dereference all objects */
- for (i = 0; i < Count; i++)
- {
- ObDereferenceObject(ObjectPtrArray[i]);
- }
-
- return(Status);
-}
+ 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);
-NTSTATUS STDCALL
-NtWaitForSingleObject(IN HANDLE Object,
- IN BOOLEAN Alertable,
- IN PLARGE_INTEGER Time)
-{
- PVOID ObjectPtr;
- NTSTATUS Status;
-
- DPRINT("NtWaitForSingleObject(Object %x, Alertable %d, Time %x)\n",
- Object,Alertable,Time);
-
- Status = ObReferenceObjectByHandle(Object,
- SYNCHRONIZE,
- NULL,
- UserMode,
- &ObjectPtr,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- Status = KeWaitForSingleObject(ObjectPtr,
- UserMode,
- UserMode,
- Alertable,
- Time);
-
- ObDereferenceObject(ObjectPtr);
-
- return(Status);
+ /* Remove the Wait Blocks from the list */
+ DPRINT("Removing waits\n");
+ WaitBlock = Thread->WaitBlockList;
+ do
+ {
+ /* Remove it */
+ DPRINT("Removing Waitblock: %x, %x\n",
+ WaitBlock, WaitBlock->NextWaitBlock);
+ RemoveEntryList(&WaitBlock->WaitListEntry);
+
+ /* Go to the next one */
+ WaitBlock = WaitBlock->NextWaitBlock;
+ } while (WaitBlock != Thread->WaitBlockList);
+
+ /* 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);
+ }
+
+ /* Increment the Queue's active threads */
+ if (Thread->Queue)
+ {
+ DPRINT("Incrementing Queue's active threads\n");
+ Thread->Queue->CurrentCount++;
+ }
+
+ /* Reschedule the Thread */
+ DPRINT("Unblocking the Thread\n");
+ KiUnblockThread(Thread, &WaitStatus, 0);
}
+VOID
+FASTCALL
+KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
+{
+ /* Increase contention count */
+ FastMutex->Contention++;
+
+ /* Wait for the event */
+ KeWaitForSingleObject(&FastMutex->Gate,
+ WrMutex,
+ KernelMode,
+ FALSE,
+ NULL);
+}
-NTSTATUS STDCALL
-NtSignalAndWaitForSingleObject(IN HANDLE SignalObject,
- IN HANDLE WaitObject,
- IN BOOLEAN Alertable,
- IN PLARGE_INTEGER Time)
+VOID
+FASTCALL
+KiExitDispatcher(KIRQL OldIrql)
{
- KPROCESSOR_MODE ProcessorMode;
- DISPATCHER_HEADER* hdr;
- PVOID SignalObj;
- PVOID WaitObj;
- NTSTATUS Status;
-
- ProcessorMode = ExGetPreviousMode();
- Status = ObReferenceObjectByHandle(SignalObject,
- 0,
- NULL,
- ProcessorMode,
- &SignalObj,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- Status = ObReferenceObjectByHandle(WaitObject,
- SYNCHRONIZE,
- NULL,
- ProcessorMode,
- &WaitObj,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(SignalObj);
- return Status;
- }
-
- hdr = (DISPATCHER_HEADER *)SignalObj;
- switch (hdr->Type)
- {
- case InternalNotificationEvent:
- case InternalSynchronizationEvent:
- KeSetEvent(SignalObj,
- EVENT_INCREMENT,
- TRUE);
- break;
-
- case InternalMutexType:
- KeReleaseMutex(SignalObj,
- TRUE);
- break;
-
- case InternalSemaphoreType:
- KeReleaseSemaphore(SignalObj,
- SEMAPHORE_INCREMENT,
- 1,
- TRUE);
- break;
-
- default:
- ObDereferenceObject(SignalObj);
- ObDereferenceObject(WaitObj);
- return STATUS_OBJECT_TYPE_MISMATCH;
- }
-
- Status = KeWaitForSingleObject(WaitObj,
- UserRequest,
- ProcessorMode,
- Alertable,
- Time);
-
- ObDereferenceObject(SignalObj);
- ObDereferenceObject(WaitObj);
-
- return Status;
+ /* If it's the idle thread, dispatch */
+ if (!(KeIsExecutingDpc()) &&
+ (OldIrql < DISPATCH_LEVEL) &&
+ (KeGetCurrentThread()) &&
+ (KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread))
+ {
+ KiDispatchThreadNoLock(Ready);
+ }
+
+ /* Lower irql back */
+ KeLowerIrql(OldIrql);
}
+
+/* EOF */