test: queueobj.c File Reference

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# queueobj.c File Reference

`#include "ki.h"`

Go to the source code of this file.

## Defines

#define | ASSERT_QUEUE(Q) ASSERT((Q)->Header.Type == QueueObject);

## Functions

VOID | KeInitializeQueue (IN PRKQUEUE Queue, IN ULONG Count OPTIONAL)
LONG | KeReadStateQueue (IN PRKQUEUE Queue)
LONG | KeInsertQueue (IN PRKQUEUE Queue, IN PLIST_ENTRY Entry)
LONG | KeInsertHeadQueue (IN PRKQUEUE Queue, IN PLIST_ENTRY Entry)
PLIST_ENTRY | KeRemoveQueue (IN PRKQUEUE Queue, IN KPROCESSOR_MODE WaitMode, IN PLARGE_INTEGER Timeout OPTIONAL)
PLIST_ENTRY | KeRundownQueue (IN PRKQUEUE Queue)
VOID FASTCALL | KiActivateWaiterQueue (IN PRKQUEUE Queue)
LONG FASTCALL | KiInsertQueue (IN PRKQUEUE Queue, IN PLIST_ENTRY Entry, IN BOOLEAN Head)

## Define Documentation

#define ASSERT_QUEUE | ( | Q |  | ) | ASSERT((Q)->Header.Type == QueueObject);

| Definition at line 33 of file queueobj.c. Referenced by KeInsertHeadQueue(), KeInsertQueue(), KeReadStateQueue(), KeRemoveQueue(), KeRundownQueue(), and KiInsertQueue().

## Function Documentation

VOID KeInitializeQueue | ( | IN PRKQUEUE | Queue,
|  | IN ULONG Count | OPTIONAL
| ) |

Definition at line 36 of file queueobj.c.

References Count, KeNumberProcessors, and QueueObject.

Referenced by ExpWorkerInitialization(), FsRtlInitializeWorkerThread(), and NtCreateIoCompletion().

    00043                    :
    00044
    00045     This function initializes a kernel queue object.
    00046
    00047 Arguments:
    00048
    00049     Queue - Supplies a pointer to a dispatcher object of type event.
    00050
    00051     Count - Supplies the target maximum number of threads that should
    00052         be concurrently active. If this parameter is not specified,
    00053         then the number of processors is used.
    00054
    00055 Return Value:
    00056
    00057     None.
    00058
    00059 --*/
    00060
    00061 {
    00062
    00063     //
    00064     // Initialize standard dispatcher object header and set initial
    00065     // state of queue object.
    00066     //
    00067
    00068     Queue->Header.Type = QueueObject;
    00069     Queue->Header.Size = sizeof(KQUEUE) / sizeof(LONG);
    00070     Queue->Header.SignalState = 0;
    00071     InitializeListHead(&Queue->Header.WaitListHead);
    00072
    00073     //
    00074     // Initialize queue listhead, the thread list head, the current number
    00075     // of threads, and the target maximum number of threads.
    00076     //
    00077
    00078     InitializeListHead(&Queue->EntryListHead);
    00079     InitializeListHead(&Queue->ThreadListHead);
    00080     Queue->CurrentCount = 0;
    00081     if (ARGUMENT_PRESENT((PVOID)(ULONG_PTR)Count)) {
    00082         Queue->MaximumCount = Count;
    00083
    00084     } else {
    00085         Queue->MaximumCount = KeNumberProcessors;
    00086     }
    00087
    00088     return;
    00089 }

LONG KeInsertHeadQueue | ( | IN PRKQUEUE | Queue,
|  | IN PLIST_ENTRY | Entry
| ) |

Definition at line 181 of file queueobj.c.

References ASSERT, ASSERT_QUEUE, DISPATCH_LEVEL, KiInsertQueue(), KiLockDispatcherDatabase, KiUnlockDispatcherDatabase(), and TRUE.

    00188                    :
    00189
    00190     This function inserts the specified entry in the queue object entry
    00191     list and attempts to satisfy the wait of a single waiter.
    00192
    00193     N.B. The wait discipline for Queue object is LIFO.
    00194
    00195 Arguments:
    00196
    00197     Queue - Supplies a pointer to a dispatcher object of type Queue.
    00198
    00199     Entry - Supplies a pointer to a list entry that is inserted in the
    00200         queue object entry list.
    00201
    00202 Return Value:
    00203
    00204     The previous signal state of the Queue object.
    00205
    00206 --*/
    00207
    00208 {
    00209
    00210     KIRQL OldIrql;
    00211     LONG OldState;
    00212
    00213     ASSERT_QUEUE(Queue);
    00214     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00215
    00216     //
    00217     // Raise IRQL to dispatcher level and lock dispatcher database.
    00218     //
    00219
    00220     KiLockDispatcherDatabase(&OldIrql);
    00221
    00222     //
    00223     // Insert the specified entry in the queue object entry list.
    00224     //
    00225
    00226     OldState = KiInsertQueue(Queue, Entry, TRUE);
    00227
    00228     //
    00229     // Unlock the dispather database, lower IRQL to the previous level, and
    00230     // return signal state of Queue object.
    00231     //
    00232
    00233     KiUnlockDispatcherDatabase(OldIrql);
    00234     return OldState;
    00235 }

LONG KeInsertQueue | ( | IN PRKQUEUE | Queue,
|  | IN PLIST_ENTRY | Entry
| ) |

Definition at line 124 of file queueobj.c.

References ASSERT, ASSERT_QUEUE, DISPATCH_LEVEL, FALSE, KiInsertQueue(), KiLockDispatcherDatabase, and KiUnlockDispatcherDatabase().

Referenced by ExQueueWorkItem(), FsRtlpPostStackOverflow(), IopCompleteRequest(), and IoSetIoCompletion().

    00131                    :
    00132
    00133     This function inserts the specified entry in the queue object entry
    00134     list and attempts to satisfy the wait of a single waiter.
    00135
    00136     N.B. The wait discipline for Queue object is LIFO.
    00137
    00138 Arguments:
    00139
    00140     Queue - Supplies a pointer to a dispatcher object of type Queue.
    00141
    00142     Entry - Supplies a pointer to a list entry that is inserted in the
    00143         queue object entry list.
    00144
    00145 Return Value:
    00146
    00147     The previous signal state of the Queue object.
    00148
    00149 --*/
    00150
    00151 {
    00152
    00153     KIRQL OldIrql;
    00154     LONG OldState;
    00155
    00156     ASSERT_QUEUE(Queue);
    00157     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00158
    00159     //
    00160     // Raise IRQL to dispatcher level and lock dispatcher database.
    00161     //
    00162
    00163     KiLockDispatcherDatabase(&OldIrql);
    00164
    00165     //
    00166     // Insert the specified entry in the queue object entry list.
    00167     //
    00168
    00169     OldState = KiInsertQueue(Queue, Entry, FALSE);
    00170
    00171     //
    00172     // Unlock the dispather database, lower IRQL to the previous level, and
    00173     // return signal state of Queue object.
    00174     //
    00175
    00176     KiUnlockDispatcherDatabase(OldIrql);
    00177     return OldState;
    00178 }

LONG KeReadStateQueue | ( | IN PRKQUEUE | Queue | ) |

Definition at line 92 of file queueobj.c.

References ASSERT_QUEUE.

Referenced by ExpDetectWorkerThreadDeadlock(), and NtQueryIoCompletion().

    00098                    :
    00099
    00100     This function reads the current signal state of a Queue object.
    00101
    00102 Arguments:
    00103
    00104     Queue - Supplies a pointer to a dispatcher object of type Queue.
    00105
    00106 Return Value:
    00107
    00108     The current signal state of the Queue object.
    00109
    00110 --*/
    00111
    00112 {
    00113
    00114     ASSERT_QUEUE(Queue);
    00115
    00116     //
    00117     // Return current signal state of Queue object.
    00118     //
    00119
    00120     return Queue->Header.SignalState;
    00121 }

PLIST_ENTRY KeRemoveQueue | ( | IN PRKQUEUE | Queue,
|  | IN KPROCESSOR_MODE | WaitMode,
|  | IN PLARGE_INTEGER Timeout | OPTIONAL
| ) |

Definition at line 238 of file queueobj.c.

References _KTHREAD::Alertable, APC_LEVEL, _KTHREAD::ApcState, ASSERT, ASSERT_QUEUE, DISPATCH_LEVEL, _KTIMER::DueTime, ExWorkerQueue, FALSE, _KTIMER::Header, KeBugCheckEx(), KeGetCurrentThread, _KAPC_STATE::KernelApcPending, KernelMode, KiActivateWaiterQueue(), KiComputeWaitInterval(), KiInsertTreeTimer(), KiInsertWaitList, KiLockDispatcherDatabase, KiSwapThread(), KiUnlockDispatcherDatabase(), _KWAIT_BLOCK::NextWaitBlock, NTSTATUS(), NULL, _KWAIT_BLOCK::Object, _KTHREAD::Queue, _KTHREAD::QueueListEntry, _KTHREAD::State, _KWAIT_BLOCK::Thread, _KTHREAD::Timer, TRUE, _KAPC_STATE::UserApcPending, _KTHREAD::WaitBlock, _KTHREAD::WaitBlockList, Waiting, _KTHREAD::WaitIrql, _KWAIT_BLOCK::WaitKey, _KWAIT_BLOCK::WaitListEntry, _DISPATCHER_HEADER::WaitListHead, _KTHREAD::WaitMode, _KTHREAD::WaitNext, _KTHREAD::WaitReason, _KTHREAD::WaitStatus, _KTHREAD::WaitTime, _KWAIT_BLOCK::WaitType, and WrQueue.

Referenced by ExpWorkerThread(), FsRtlWorkerThread(), and NtRemoveIoCompletion().

    00246                    :
    00247
    00248     This function removes the next entry from the Queue object entry
    00249     list. If no list entry is available, then the calling thread is
    00250     put in a wait state.
    00251
    00252     N.B. The wait discipline for Queue object LIFO.
    00253
    00254 Arguments:
    00255
    00256     Queue - Supplies a pointer to a dispatcher object of type Queue.
    00257
    00258     WaitMode  - Supplies the processor mode in which the wait is to occur.
    00259
    00260     Timeout - Supplies a pointer to an optional absolute of relative time over
    00261         which the wait is to occur.
    00262
    00263 Return Value:
    00264
    00265     The address of the entry removed from the Queue object entry list or
    00266     STATUS_TIMEOUT.
    00267
    00268     N.B. These values can easily be distinguished by the fact that all
    00269          addresses in kernel mode have the high order bit set.
    00270
    00271 --*/
    00272
    00273 {
    00274
    00275     LARGE_INTEGER DueTime;
    00276     PLIST_ENTRY Entry;
    00277     PRKTHREAD NextThread;
    00278     LARGE_INTEGER NewTime;
    00279     KIRQL OldIrql;
    00280     PRKQUEUE OldQueue;
    00281     PLARGE_INTEGER OriginalTime;
    00282     PRKTHREAD Thread;
    00283     PRKTIMER Timer;
    00284     PRKWAIT_BLOCK WaitBlock;
    00285     LONG_PTR WaitStatus;
    00286
    00287     ASSERT_QUEUE(Queue);
    00288     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00289
    00290     //
    00291     // If the dispatcher database lock is not already held, then set the wait
    00292     // IRQL and lock the dispatcher database. Else set boolean wait variable
    00293     // to FALSE.
    00294     //
    00295
    00296     Thread = KeGetCurrentThread();
    00297     if (Thread->WaitNext) {
    00298         Thread->WaitNext = FALSE;
    00299
    00300     } else {
    00301         KiLockDispatcherDatabase(&OldIrql);
    00302         Thread->WaitIrql = OldIrql;
    00303     }
    00304
    00305     //
    00306     // Check if the thread is currently processing a queue entry and whether
    00307     // the new queue is the same as the old queue.
    00308     //
    00309
    00310     OldQueue = Thread->Queue;
    00311     Thread->Queue = Queue;
    00312     if (Queue != OldQueue) {
    00313
    00314         //
    00315         // If the thread was previously associated with a queue, then remove
    00316         // the thread from the old queue object thread list and attempt to
    00317         // activate another thread.
    00318         //
    00319
    00320         Entry = &Thread->QueueListEntry;
    00321         if (OldQueue != NULL) {
    00322             RemoveEntryList(Entry);
    00323             KiActivateWaiterQueue(OldQueue);
    00324         }
    00325
    00326         //
    00327         // Insert thread in the thread list of the new queue that the thread
    00328         // will be associate with.
    00329         //
    00330
    00331         InsertTailList(&Queue->ThreadListHead, Entry);
    00332
    00333     } else {
    00334
    00335         //
    00336         // The previous and current queue are the same queue - decrement the
    00337         // current number of threads.
    00338         //
    00339
    00340         Queue->CurrentCount -= 1;
    00341     }
    00342
    00343     //
    00344     //
    00345     // Start of wait loop.
    00346     //
    00347     //
    00348     // Note this loop is repeated if a kernel APC is delivered in the
    00349     // middle of the wait or a kernel APC is pending on the first attempt
    00350     // through the loop.
    00351     //
    00352     // If the Queue object entry list is not empty, then remove the next
    00353     // entry from the Queue object entry list. Otherwise, wait for an entry
    00354     // to be inserted in the queue.
    00355     //
    00356
    00357     OriginalTime = Timeout;
    00358     do {
    00359
    00360         //
    00361         // Check if there is a queue entry available and the current
    00362         // number of active threads is less than target maximum number
    00363         // of threads.
    00364         //
    00365
    00366         Entry = Queue->EntryListHead.Flink;
    00367         if ((Entry != &Queue->EntryListHead) &&
    00368             (Queue->CurrentCount < Queue->MaximumCount)) {
    00369
    00370             //
    00371             // Decrement the number of entires in the Queue object entry list,
    00372             // increment the number of active threads, remove the next entry
    00373             // rom the list, and set the forward link to NULL.
    00374             //
    00375
    00376             Queue->Header.SignalState -= 1;
    00377             Queue->CurrentCount += 1;
    00378             if ((Entry->Flink == NULL) || (Entry->Blink == NULL)) {
    00379                 KeBugCheckEx(INVALID_WORK_QUEUE_ITEM,
    00380                              (ULONG_PTR)Entry,
    00381                              (ULONG_PTR)Queue,
    00382                              (ULONG_PTR)&ExWorkerQueue[0],
    00383                              (ULONG_PTR)((PWORK_QUEUE_ITEM)Entry)->WorkerRoutine);
    00384             }
    00385
    00386             RemoveEntryList(Entry);
    00387             Entry->Flink = NULL;
    00388             break;
    00389
    00390         } else {
    00391
    00392             //
    00393             // Set address of wait block list in thread object.
    00394             //
    00395
    00396             Thread->WaitBlockList = &Thread->WaitBlock[0];
    00397
    00398             //
    00399             // Test to determine if a kernel APC is pending.
    00400             //
    00401             // If a kernel APC is pending and the previous IRQL was less than
    00402             // APC_LEVEL, then a kernel APC was queued by another processor
    00403             // just after IRQL was raised to DISPATCH_LEVEL, but before the
    00404             // dispatcher database was locked.
    00405             //
    00406             // N.B. that this can only happen in a multiprocessor system.
    00407             //
    00408
    00409             if (Thread->ApcState.KernelApcPending && (Thread->WaitIrql < APC_LEVEL)) {
    00410
    00411                 //
    00412                 // Increment the current thread count, unlock the dispatcher
    00413                 // database, and lower IRQL to previous value. An APC interrupt
    00414                 // will immediately occur which will result in the delivery of
    00415                 // the kernel APC if possible.
    00416                 //
    00417
    00418                 Queue->CurrentCount += 1;
    00419                 KiUnlockDispatcherDatabase(Thread->WaitIrql);
    00420
    00421             } else {
    00422
    00423                 //
    00424                 // Test if a user APC is pending.
    00425                 //
    00426
    00427                 if ((WaitMode != KernelMode) && (Thread->ApcState.UserApcPending)) {
    00428                     Entry = (PLIST_ENTRY)ULongToPtr(STATUS_USER_APC);
    00429                     Queue->CurrentCount += 1;
    00430                     break;
    00431                 }
    00432
    00433                 //
    00434                 // Construct a wait block and check to determine if the wait
    00435                 // is already satisfied. If the wait is satisfied, then perform
    00436                 // wait completion and return. Else put current thread in a
    00437                 // wait state if an explicit timeout value of zero is not
    00438                 // specified.
    00439                 //
    00440
    00441                 Thread->WaitStatus = (NTSTATUS)0;
    00442                 WaitBlock = &Thread->WaitBlock[0];
    00443                 WaitBlock->Object = (PVOID)Queue;
    00444                 WaitBlock->WaitKey = (CSHORT)(STATUS_SUCCESS);
    00445                 WaitBlock->WaitType = WaitAny;
    00446                 WaitBlock->Thread = Thread;
    00447
    00448                 //
    00449                 // Check to determine if a timeout value is specified.
    00450                 //
    00451
    00452                 if (ARGUMENT_PRESENT(Timeout)) {
    00453
    00454                     //
    00455                     // If the timeout value is zero, then return immediately
    00456                     // without waiting.
    00457                     //
    00458
    00459                     if (!(Timeout->LowPart | Timeout->HighPart)) {
    00460                         Entry = (PLIST_ENTRY)ULongToPtr(STATUS_TIMEOUT);
    00461                         Queue->CurrentCount += 1;
    00462                         break;
    00463                     }
    00464
    00465                     //
    00466                     // Initialize a wait block for the thread specific timer,
    00467                     // insert wait block in timer wait list, insert the timer
    00468                     // in the timer tree.
    00469                     //
    00470
    00471                     Timer = &Thread->Timer;
    00472                     WaitBlock->NextWaitBlock = &Thread->WaitBlock[1];
    00473                     WaitBlock = &Thread->WaitBlock[1];
    00474                     WaitBlock->Object = (PVOID)Timer;
    00475                     WaitBlock->WaitKey = (CSHORT)(STATUS_TIMEOUT);
    00476                     WaitBlock->WaitType = WaitAny;
    00477                     WaitBlock->Thread = Thread;
    00478                     Timer->Header.WaitListHead.Flink = &WaitBlock->WaitListEntry;
    00479                     Timer->Header.WaitListHead.Blink = &WaitBlock->WaitListEntry;
    00480                     WaitBlock->WaitListEntry.Flink = &Timer->Header.WaitListHead;
    00481                     WaitBlock->WaitListEntry.Blink = &Timer->Header.WaitListHead;
    00482                     if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) {
    00483                         Entry = (PLIST_ENTRY)ULongToPtr(STATUS_TIMEOUT);
    00484                         Queue->CurrentCount += 1;
    00485                         break;
    00486                     }
    00487
    00488                     DueTime.QuadPart = Timer->DueTime.QuadPart;
    00489                 }
    00490
    00491                 //
    00492                 // Close up the circular list of wait control blocks.
    00493                 //
    00494
    00495                 WaitBlock->NextWaitBlock = &Thread->WaitBlock[0];
    00496
    00497                 //
    00498                 // Insert wait block in object wait list.
    00499                 //
    00500
    00501                 WaitBlock = &Thread->WaitBlock[0];
    00502                 InsertTailList(&Queue->Header.WaitListHead, &WaitBlock->WaitListEntry);
    00503
    00504                 //
    00505                 // Set the thread wait parameters, set the thread dispatcher
    00506                 // state to Waiting, and insert the thread in the wait list.
    00507                 //
    00508
    00509                 Thread->Alertable = FALSE;
    00510                 Thread->WaitMode = WaitMode;
    00511                 Thread->WaitReason = WrQueue;
    00512                 Thread->WaitTime = KiQueryLowTickCount();
    00513                 Thread->State = Waiting;
    00514                 KiInsertWaitList(WaitMode, Thread);
    00515
    00516                 //
    00517                 // Switch context to selected thread.
    00518                 //
    00519                 // Control is returned at the original IRQL.
    00520                 //
    00521
    00522                 ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
    00523
    00524                 WaitStatus = KiSwapThread();
    00525
    00526                 //
    00527                 // If the thread was not awakened to deliver a kernel mode APC,
    00528                 // then return wait status.
    00529                 //
    00530
    00531                 Thread->WaitReason = 0;
    00532                 if (WaitStatus != STATUS_KERNEL_APC) {
    00533                     return (PLIST_ENTRY)WaitStatus;
    00534                 }
    00535
    00536                 if (ARGUMENT_PRESENT(Timeout)) {
    00537
    00538                     //
    00539                     // Reduce the amount of time remaining before timeout occurs.
    00540                     //
    00541
    00542                     Timeout = KiComputeWaitInterval(OriginalTime,
    00543                                                     &DueTime,
    00544                                                     &NewTime);
    00545                 }
    00546             }
    00547
    00548             //
    00549             // Raise IRQL to DISPATCH_LEVEL, lock the dispatcher database,
    00550             // and decrement the count of active threads.
    00551             //
    00552
    00553             KiLockDispatcherDatabase(&OldIrql);
    00554             Thread->WaitIrql = OldIrql;
    00555             Queue->CurrentCount -= 1;
    00556         }
    00557
    00558     } while (TRUE);
    00559
    00560     //
    00561     // Unlock the dispatcher database and return the list entry address or a
    00562     // status of timeout.
    00563     //
    00564
    00565     KiUnlockDispatcherDatabase(Thread->WaitIrql);
    00566     return Entry;
    00567 }

PLIST_ENTRY KeRundownQueue | ( | IN PRKQUEUE | Queue | ) |

Definition at line 570 of file queueobj.c.

References ASSERT, ASSERT_QUEUE, DISPATCH_LEVEL, KiLockDispatcherDatabase, KiUnlockDispatcherDatabase(), NULL, and _KTHREAD::Queue.

Referenced by IopDeleteIoCompletion().

    00576                    :
    00577
    00578     This function runs down the specified queue by removing the listhead
    00579     from the queue list, removing any associated threads from the thread
    00580     list, and returning the address of the first entry.
    00581
    00582
    00583 Arguments:
    00584
    00585     Queue - Supplies a pointer to a dispatcher object of type Queue.
    00586
    00587 Return Value:
    00588
    00589     If the queue list is not empty, then the address of the first entry in
    00590     the queue is returned as the function value. Otherwise, a value of NULL
    00591     is returned.
    00592
    00593 --*/
    00594
    00595 {
    00596
    00597     PLIST_ENTRY Entry;
    00598     PLIST_ENTRY FirstEntry;
    00599     KIRQL OldIrql;
    00600     PKTHREAD Thread;
    00601
    00602     ASSERT_QUEUE(Queue);
    00603     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00604
    00605     //
    00606     // Raise IRQL to dispatch level and lock the dispatcher database.
    00607     //
    00608
    00609     KiLockDispatcherDatabase(&OldIrql);
    00610
    00611     //
    00612     // Get the address of the first entry in the queue and check if the
    00613     // list is empty or contains entries that should be flushed. If there
    00614     // are no entries in the list, then set the return value to NULL.
    00615     // Otherwise, set the return value to the address of the first list
    00616     // entry and remove the listhead from the list.
    00617     //
    00618
    00619     FirstEntry = Queue->EntryListHead.Flink;
    00620     if (FirstEntry == &Queue->EntryListHead) {
    00621         FirstEntry = NULL;
    00622
    00623     } else {
    00624         RemoveEntryList(&Queue->EntryListHead);
    00625     }
    00626
    00627     //
    00628     // Remove all associated threads from the thread list of the queue.
    00629     //
    00630
    00631     while (Queue->ThreadListHead.Flink != &Queue->ThreadListHead) {
    00632         Entry = Queue->ThreadListHead.Flink;
    00633         Thread = CONTAINING_RECORD(Entry, KTHREAD, QueueListEntry);
    00634         Thread->Queue = NULL;
    00635         RemoveEntryList(Entry);
    00636     }
    00637
    00638     //
    00639     // Unlock the dispatcher database, lower IRQL to its previous level,
    00640     // and return the function value.
    00641     //
    00642
    00643     KiUnlockDispatcherDatabase(OldIrql);
    00644     return FirstEntry;
    00645 }

VOID FASTCALL KiActivateWaiterQueue | ( | IN PRKQUEUE | Queue | ) |

Definition at line 649 of file queueobj.c.

References KiUnwaitThread(), NULL, and _KWAIT_BLOCK::Thread.

Referenced by KeDelayExecutionThread(), KeRemoveQueue(), KeTerminateThread(), KeWaitForMultipleObjects(), and KeWaitForSingleObject().

    00655                    :
    00656
    00657     This function is called when the current thread is about to enter a
    00658     wait state and is currently processing a queue entry. The current
    00659     number of threads processign entries for the queue is decrement and
    00660     an attempt is made to activate another thread if the current count
    00661     is less than the maximum count, there is a waiting thread, and the
    00662     queue is not empty.
    00663
    00664 Arguments:
    00665
    00666     Queue - Supplies a pointer to a dispatcher object of type event.
    00667
    00668 Return Value:
    00669
    00670     None.
    00671
    00672 --*/
    00673
    00674 {
    00675
    00676     PRLIST_ENTRY Entry;
    00677     PRKTHREAD Thread;
    00678     PRKWAIT_BLOCK WaitBlock;
    00679     PRLIST_ENTRY WaitEntry;
    00680
    00681     //
    00682     // Decrement the current count of active threads and check if another
    00683     // thread can be activated. If the current number of active threads is
    00684     // less than the target maximum number of threads, there is a entry in
    00685     // in the queue, and a thread is waiting, then remove the entry from the
    00686     // queue, decrement the number of entries in the queue, and unwait the
    00687     // respectiive thread.
    00688     //
    00689
    00690     Queue->CurrentCount -= 1;
    00691     if (Queue->CurrentCount < Queue->MaximumCount) {
    00692         Entry = Queue->EntryListHead.Flink;
    00693         WaitEntry = Queue->Header.WaitListHead.Blink;
    00694         if ((Entry != &Queue->EntryListHead) &&
    00695             (WaitEntry != &Queue->Header.WaitListHead)) {
    00696             RemoveEntryList(Entry);
    00697             Entry->Flink = NULL;
    00698             Queue->Header.SignalState -= 1;
    00699             WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
    00700             Thread = WaitBlock->Thread;
    00701             KiUnwaitThread(Thread, (LONG_PTR)Entry, 0);
    00702         }
    00703     }
    00704
    00705     return;
    00706 }

LONG FASTCALL KiInsertQueue | ( | IN PRKQUEUE | Queue,
|  | IN PLIST_ENTRY | Entry,
|  | IN BOOLEAN | Head
| ) |

Definition at line 710 of file queueobj.c.

References ASSERT_QUEUE, FALSE, _KTIMER::Header, _DISPATCHER_HEADER::Inserted, KeGetCurrentThread, KiReadyThread(), KiRemoveTreeTimer, _KTHREAD::Queue, _KWAIT_BLOCK::Thread, _KTHREAD::Timer, TRUE, _KTHREAD::WaitListEntry, _KTHREAD::WaitReason, _KTHREAD::WaitStatus, and WrQueue.

Referenced by KeInsertHeadQueue(), KeInsertQueue(), and KeTerminateThread().

    00718                    :
    00719
    00720     This function inserts the specified entry in the queue object entry
    00721     list and attempts to satisfy the wait of a single waiter.
    00722
    00723     N.B. The wait discipline for Queue object is LIFO.
    00724
    00725 Arguments:
    00726
    00727     Queue - Supplies a pointer to a dispatcher object of type Queue.
    00728
    00729     Entry - Supplies a pointer to a list entry that is inserted in the
    00730         queue object entry list.
    00731
    00732     Head - Supplies a boolean value that determines whether the queue
    00733         entry is inserted at the head or tail of the queue if it can
    00734         not be immediately dispatched.
    00735
    00736 Return Value:
    00737
    00738     The previous signal state of the Queue object.
    00739
    00740 --*/
    00741
    00742 {
    00743
    00744     LONG OldState;
    00745     PRKTHREAD Thread;
    00746     PKTIMER Timer;
    00747     PKWAIT_BLOCK WaitBlock;
    00748     PLIST_ENTRY WaitEntry;
    00749
    00750     ASSERT_QUEUE(Queue);
    00751
    00752     //
    00753     // Capture the current signal state of queue object and check if there
    00754     // is a thread waiting on the queue object, the current number of active
    00755     // threads is less than the target number of threads, and the wait reason
    00756     // of the current thread is not queue wait or the wait queue is not the
    00757     // same queue as the insertion queue. If these conditions are satisfied,
    00758     // then satisfy the thread wait and pass the thread the address of the
    00759     // queue entry as the wait status. Otherwise, set the state of the queue
    00760     // object to signaled and insert the specified entry in the queue object
    00761     // entry list.
    00762     //
    00763
    00764     OldState = Queue->Header.SignalState;
    00765     Thread = KeGetCurrentThread();
    00766     WaitEntry = Queue->Header.WaitListHead.Blink;
    00767     if ((WaitEntry != &Queue->Header.WaitListHead) &&
    00768         (Queue->CurrentCount < Queue->MaximumCount) &&
    00769         ((Thread->Queue != Queue) ||
    00770         (Thread->WaitReason != WrQueue))) {
    00771
    00772         //
    00773         // Remove the last wait block from the wait list and get the address
    00774         // of the waiting thread object.
    00775         //
    00776
    00777         RemoveEntryList(WaitEntry);
    00778         WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
    00779         Thread = WaitBlock->Thread;
    00780
    00781         //
    00782         // Set the wait completion status, remove the thread from its wait
    00783         // list, increment the number of active threads, and clear the wait
    00784         // reason.
    00785         //
    00786
    00787         Thread->WaitStatus = (LONG_PTR)Entry;
    00788         RemoveEntryList(&Thread->WaitListEntry);
    00789         Queue->CurrentCount += 1;
    00790         Thread->WaitReason = 0;
    00791
    00792         //
    00793         // If thread timer is still active, then cancel thread timer.
    00794         //
    00795
    00796         Timer = &Thread->Timer;
    00797         if (Timer->Header.Inserted == TRUE) {
    00798             KiRemoveTreeTimer(Timer);
    00799         }
    00800
    00801         //
    00802         // Ready the thread for execution.
    00803         //
    00804
    00805         KiReadyThread(Thread);
    00806
    00807     } else {
    00808         Queue->Header.SignalState += 1;
    00809         if (Head != FALSE) {
    00810             InsertHeadList(&Queue->EntryListHead, Entry);
    00811
    00812         } else {
    00813             InsertTailList(&Queue->EntryListHead, Entry);
    00814         }
    00815     }
    00816
    00817     return OldState;
    00818 }
    }