{
PLIST_ENTRY QueueEntry;
LONG_PTRStatus;
PKTHREADThread = KeGetCurrentThread();
PKQUEUE PreviousQueue;
PKWAIT_BLOCK WaitBlock = &Thread->WaitBlock[0];
PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
PKTIMERTimer = &Thread->Timer;
BOOLEAN Swappable;
PLARGE_INTEGER OriginalDueTime = Timeout;
LARGE_INTEGERDueTime = {{0}}, NewDueTime, InterruptTime;
ULONG Hand = 0;
ASSERT_QUEUE(Queue);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Check if the Lock is already held */if (Thread->WaitNext)
{
/* It is, so next time don't do expect this */
Thread->WaitNext = FALSE;
KxQueueThreadWait();
}
else
{
/* Raise IRQL to synch, prepare the wait, then lock the database */
Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
KxQueueThreadWait();
KiAcquireDispatcherLockAtDpcLevel();
}
/* * 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)
{
/* Get the current entry */
QueueEntry = &Thread->QueueListEntry;
if (PreviousQueue)
{
/* Remove from this list */RemoveEntryList(QueueEntry);
/* Wake the queue */KiActivateWaiterQueue(PreviousQueue);
}
/* Insert in this new Queue */InsertTailList(&Queue->ThreadListHead, QueueEntry);
}
else
{
/* Same queue, decrement waiting threads */
Queue->CurrentCount--;
}
/* Loop until the queue is processed */while (TRUE)
{
/* Check if the counts are valid and if there is still a queued entry */
QueueEntry = Queue->EntryListHead.Flink;
if ((Queue->CurrentCount < Queue->MaximumCount) &&
(QueueEntry != &Queue->EntryListHead))
{
/* Decrease the number of entries */
Queue->Header.SignalState--;
/* Increase numbef of running threads */
Queue->CurrentCount++;
/* Check if the entry is valid. If not, bugcheck */if (!(QueueEntry->Flink) || !(QueueEntry->Blink))
{
/* Invalid item */KeBugCheckEx(INVALID_WORK_QUEUE_ITEM,
(ULONG_PTR)QueueEntry,
(ULONG_PTR)Queue,
(ULONG_PTR)NULL,
(ULONG_PTR)((PWORK_QUEUE_ITEM)QueueEntry)->
WorkerRoutine);
}
/* Remove the Entry */RemoveEntryList(QueueEntry);
QueueEntry->Flink = NULL;
/* Nothing to wait on */break;
}
else
{
/* Check if a kernel APC is pending and we're below APC_LEVEL */if ((Thread->ApcState.KernelApcPending) &&
!(Thread->SpecialApcDisable) && (Thread->WaitIrql < APC_LEVEL))
{
/* Increment the count and unlock the dispatcher */
Queue->CurrentCount++;
KiReleaseDispatcherLockFromDpcLevel();
KiExitDispatcher(Thread->WaitIrql);
}
else
{
/* Fail if there's a User APC Pending */if ((WaitMode != KernelMode) &&
(Thread->ApcState.UserApcPending))
{
/* Return the status and increase the pending threads */
QueueEntry = (PLIST_ENTRY)STATUS_USER_APC;
Queue->CurrentCount++;
break;
}
/* Enable the Timeout Timer if there was any specified */if (Timeout)
{
/* Check if the timer expired */
InterruptTime.QuadPart = KeQueryInterruptTime();
if ((ULONG64)InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
{
/* It did, so we don't need to wait */
QueueEntry = (PLIST_ENTRY)STATUS_TIMEOUT;
Queue->CurrentCount++;
break;
}
/* It didn't, so activate it */
Timer->Header.Inserted = TRUE;
}
/* Insert the wait block in the list */InsertTailList(&Queue->Header.WaitListHead,
&WaitBlock->WaitListEntry);
/* Setup the wait information */
Thread->State = Waiting;
/* Add the thread to the wait list */KiAddThreadToWaitList(Thread, Swappable);
/* Activate thread swap */ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
KiSetThreadSwapBusy(Thread);
/* Check if we have a timer */if (Timeout)
{
/* Insert it */KxInsertTimer(Timer, Hand);
}
else
{
/* Otherwise, unlock the dispatcher */KiReleaseDispatcherLockFromDpcLevel();
}
/* Do the actual swap */
Status = KiSwapThread(Thread, KeGetCurrentPrcb());
/* Reset the wait reason */
Thread->WaitReason = 0;
/* Check if we were executing an APC */if (Status != STATUS_KERNEL_APC) return (PLIST_ENTRY)Status;
/* Check if we had a timeout */if (Timeout)
{
/* Recalculate due times */Timeout = KiRecalculateDueTime(OriginalDueTime,
&DueTime,
&NewDueTime);
}
}
/* Start another wait */
Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
KxQueueThreadWait();
KiAcquireDispatcherLockAtDpcLevel();
Queue->CurrentCount--;
}
}
/* Unlock Database and return */KiReleaseDispatcherLockFromDpcLevel();
KiExitDispatcher(Thread->WaitIrql);
return QueueEntry;
}
Generated on Sun May 27 2012 05:18:00 for ReactOS by
1.7.6.1
ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.