1 
2 /*++
3 
4 Copyright (c) Microsoft. All rights reserved.
5 
6 Module Name:
7 
8     FxIoQueue.h
9 
10 Abstract:
11 
12     This module implements the I/O package queue object
13 
14 Author:
15 
16 
17 
18 
19 Environment:
20 
21     Both kernel and user mode
22 
23 Revision History:
24 
25 
26 --*/
27 
28 #ifndef _FXIOQUEUE_H_
29 #define _FXIOQUEUE_H_
30 
31 #include "fxioqueuecallbacks.hpp"
32 
33 extern "C" {
34 #if defined(EVENT_TRACING)
35 #include "FxIoQueue.hpp.tmh"
36 #endif
37 }
38 
39 
40 //
41 // These FxIoQueue public Enum and Struct are used to tie the queue
42 // with FxPkgIo.
43 //
44 enum FxIoQueueNodeType {
45     FxIoQueueNodeTypeInvalid = 0,
46     FxIoQueueNodeTypeQueue,
47     FxIoQueueNodeTypeBookmark,
48     FxIoQueueNodeTypeLast,
49 };
50 
51 struct FxIoQueueNode {
52 public:
53     //
54     // Data members.
55     //
56     LIST_ENTRY          m_ListEntry;
57     FxIoQueueNodeType   m_Type;
58 
59 public:
60     //
61     // Manager functions.
62     //
FxIoQueueNodeFxIoQueueNode63     FxIoQueueNode(
64         FxIoQueueNodeType NodeType
65         ) :
66         m_Type(NodeType)
67     {
68         ASSERT(_IsValidNodeType(m_Type));
69         InitializeListHead(&m_ListEntry);
70     }
71 
~FxIoQueueNodeFxIoQueueNode72     ~FxIoQueueNode()
73     {
74         ASSERT(IsListEmpty(&m_ListEntry) == TRUE);
75     }
76 
77 private:
78     //
79     // Turn off unsupported manager functions.
80     //
81     FxIoQueueNode();
82 
83     //
84     // Block default behavior to shallow copy the object because it contains
85     // a double-link entry; shallow copying the object produces an invalid
86     // copy because the double-link entry is not properly re-initialized.
87     //
88     FxIoQueueNode(const FxIoQueueNode&);
89 
90     FxIoQueueNode& operator=(const FxIoQueueNode&);
91 
92 public:
93     //
94     // Helper functions.
95     //
96     static
97     FxIoQueueNode*
_FromListEntryFxIoQueueNode98     _FromListEntry(
99         __in PLIST_ENTRY Entry
100         )
101     {
102         return CONTAINING_RECORD(Entry, FxIoQueueNode, m_ListEntry);
103     }
104 
105     static
106     BOOLEAN
_IsValidNodeTypeFxIoQueueNode107     _IsValidNodeType(
108         __in FxIoQueueNodeType NodeType
109         )
110     {
111         return ((NodeType > FxIoQueueNodeTypeInvalid) &&
112                 (NodeType < FxIoQueueNodeTypeLast)) ? TRUE : FALSE;
113     }
114 
115     __inline
116     BOOLEAN
IsNodeTypeFxIoQueueNode117     IsNodeType(
118         __in FxIoQueueNodeType NodeType
119         )
120     {
121         return (NodeType == m_Type) ? TRUE : FALSE;
122     }
123 };
124 
125 //
126 // These FxIoQueue private Enum's control the internal state machine
127 //
128 
129 // begin_wpp enum
130 typedef enum FxIoQueuePowerState {
131     FxIoQueuePowerInvalid = 0,
132     FxIoQueuePowerOn,
133     FxIoQueuePowerOff,
134     FxIoQueuePowerStartingTransition,
135     FxIoQueuePowerStopping,
136     FxIoQueuePowerStoppingNotifyingDriver,
137     FxIoQueuePowerStoppingDriverNotified,
138     FxIoQueuePowerPurge,
139     FxIoQueuePowerPurgeNotifyingDriver,
140     FxIoQueuePowerPurgeDriverNotified,
141     FxIoQueuePowerRestarting,
142     FxIoQueuePowerRestartingNotifyingDriver,
143     FxIoQueuePowerRestartingDriverNotified,
144     FxIoQueuePowerLast,
145 } FXIOQUEUE_POWER_STATE;
146 // end_wpp
147 
148 typedef struct _FXIO_FORWARD_PROGRESS_CONTEXT {
149     //
150     // Total Number of Reserved requests
151     //
152     ULONG m_NumberOfReservedRequests;
153     //
154     // Callback invoked to allocate resources for reserved requests at init time
155     //
156     FxIoQueueForwardProgressAllocateResourcesReserved   m_IoReservedResourcesAllocate;
157     //
158     // Callback invoked to allocate resources for non-reserved requests at run time
159     //
160     FxIoQueueForwardProgressAllocateResources   m_IoResourcesAllocate;
161     //
162     // Callback invoked to Examine the IRP and decide whether to fail it or not
163     //
164     FxIoQueueForwardProgressExamineIrp       m_IoExamineIrp;
165     //
166     // Policy configured for forward progress
167     //
168     WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY  m_Policy;
169     //
170     // List of available reserved requests
171     //
172     LIST_ENTRY  m_ReservedRequestList;
173 
174     //
175     // List of in use reserved requests
176     //
177     LIST_ENTRY  m_ReservedRequestInUseList;
178 
179     //
180     // List of all pended IRPs
181     //
182     LIST_ENTRY  m_PendedIrpList;
183     //
184     // This lock is used to add new entreies to the pended IRP list
185     // or the  add the request back to the Reserved List
186     //
187     MxLockNoDynam m_PendedReserveLock;
188 
189 } FXIO_FORWARD_PROGRESS_CONTEXT, *PFXIO_FORWARD_PROGRESS_CONTEXT;
190 
191 //
192 // This defines the valid arguments to the
193 // SetStatus call.
194 //
195 typedef enum _FX_IO_QUEUE_SET_STATE {
196     FxIoQueueSetAcceptRequests     = 0x80000001,
197     FxIoQueueClearAcceptRequests   = 0x80000002,
198     FxIoQueueSetDispatchRequests   = 0x80000004,
199     FxIoQueueClearDispatchRequests = 0x80000008,
200     FxIoQueueSetShutdown           = 0x80010000,
201     FxIoQueueClearShutdown         = 0x80020000,
202 } FX_IO_QUEUE_SET_STATE;
203 
204 
205 //
206 // This defines the internal queue state.
207 //
208 typedef enum _FX_IO_QUEUE_STATE {
209     //
210     // private == public values (low word).
211     //
212     FxIoQueueAcceptRequests     = WdfIoQueueAcceptRequests,     // 0x00000001
213     FxIoQueueDispatchRequests   = WdfIoQueueDispatchRequests,   // 0x00000002
214     FxIoQueueNoRequests         = WdfIoQueueNoRequests,         // 0x00000004
215     FxIoQueueDriverNoRequests   = WdfIoQueueDriverNoRequests,   // 0x00000008
216     FxIoQueuePnpHeld            = WdfIoQueuePnpHeld,            // 0x00000010
217     //
218     // private values only (high word).
219     //
220     // Queue is being shut down. Flag on means do not queue any request
221     // even if the accept request state is set. This flag prevents the
222     // following scenarios:
223     // (1) a race condition where a dispatch queue handler changes the
224     //     state of the queue to accept_requests while we are in the
225     //     middle of a power stopping (purge) operation (Win7 719587).
226     // (2) another thread calling Stop or Start on a queue that is in the
227     //     middle of a power stopping (purge) operation.
228     //
229     FxIoQueueShutdown           = 0x00010000
230 } FX_IO_QUEUE_STATE;
231 
232 class FxIoQueue : public FxNonPagedObject, IFxHasCallbacks {
233 
234     friend VOID GetTriageInfo(VOID);
235 
236 private:
237 
238     //
239     // forward progress fields
240     //
241     PFXIO_FORWARD_PROGRESS_CONTEXT m_FwdProgContext;
242 
243     //
244     // This is a true indicator whether the Queue is ready for forward progress
245     //
246     BOOLEAN m_SupportForwardProgress;
247 
248     //
249     // Specifies that the queue has been configured
250     // with driver callbacks and presentation serialization
251     //
252     BOOLEAN             m_Configured;
253 
254     //
255     // TRUE if this is a power managed queue. If TRUE, it is reported
256     // as a power managed queue, and will automatically start/resume
257     // based on power management requests.
258     //
259     // If false, the device driver has manual control on start/resume.
260     //
261     BOOLEAN             m_PowerManaged;
262 
263     //
264     // This is TRUE if we have an outstanding reference to the
265     // Pnp package about having I/O in our queue.
266     //
267     volatile BOOLEAN    m_PowerReferenced;
268 
269     //
270     // If TRUE, zero length read/writes are allowed to the driver.
271     // Otherwise, they are completed automatically with STATUS_SUCCESS.
272     //
273     BOOLEAN             m_AllowZeroLengthRequests;
274 
275     //
276     // True if callback operations to the driver occur at
277     // PASSIVE_LEVEL. Also marked in FxObject, but this cache
278     // avoids acquiring FxObject state lock.
279     //
280     BOOLEAN             m_PassiveLevel;
281 
282     //
283     // This is set before m_FinishDisposing is signalled to
284     // allow the Dispose thread to continue deletion of
285     // queue resources. Once this is set, no thread is
286     // allowed to run thru DispatchEvents.
287     //
288     volatile BOOLEAN    m_Deleted;
289 
290     //
291     // This is set when the I/O package marks the queue
292     // for deleting, but the I/O queue deferrs its final
293     // dereference until all outstanding I/O's to the
294     // device driver are completed.
295     //
296     volatile BOOLEAN    m_Disposing;
297     MxEvent             m_FinishDisposing;
298 
299     //
300     // Power State of the Queue
301     //
302     FXIOQUEUE_POWER_STATE m_PowerState;
303 
304     //
305     // This is the type of queue, and is configured by the
306     // user at initial queue creation time.
307     //
308     WDF_IO_QUEUE_DISPATCH_TYPE m_Type;
309 
310     //
311     // Maximum number of driver presented Requests on a parallel Queue
312     //
313     ULONG  m_MaxParallelQueuePresentedRequests;
314 
315     //
316     // This is the current processing status of the queue.
317     //
318     FX_IO_QUEUE_STATE m_QueueState;
319 
320     //
321     // The FxIoQueue tracks a request from the time it arrives by being
322     // enqueued, until it leaves by being completed, or forwarded.
323     //
324     // At any given time, a request may be in one the following five states:
325     //
326     // 1) Request is queued and cancelable
327     //
328     //    It is on the FxIrpQueue m_Queue using the LIST_ENTRY
329     //    FxRequest::m_Irp->Tail.Overlay.ListEntry
330     //
331     // 2) Request has been passed to the driver, and is not cancelable
332     //
333     //    It is on the LIST_ENTRY m_DriverNonCancelable using the LIST_ENTRY
334     //    FxRequest::m_OwnerListEntry
335     //
336     //    It is also on the LIST_ENTRY m_DriverInFlight using the LIST_ENTRY
337     //    FxRequest::m_InFlightListEntry
338     //
339     // 3) Request has been passed to the driver, and is cancelable
340     //
341     //    It is on the FxIrpQueue m_DriverCancelable using the LIST_ENTRY
342     //    FxRequest::m_Irp->Tail.Overlay.ListEntry
343     //
344     //    It is also on the LIST_ENTRY m_DriverInFlight using the LIST_ENTRY
345     //    FxRequest::m_InFlightListEntry
346     //
347     // 4) Request has been cancelled, but the driver has not been notified
348     //
349     //    It is on the LIST_ENTRY m_Cancelled using the LIST_ENTRY
350     //    FxRequest::m_OwnerListEntry
351     //
352     // 5) Request has been cancelled, driver has been notified, but has
353     //    not completed it yet
354     //
355     //    It is on the LIST_ENTRY m_DriverNonCancelable using the LIST_ENTRY
356     //    FxRequest::m_OwnerListEntry
357     //
358     //    It is also on the LIST_ENTRY m_DriverInFlight using the LIST_ENTRY
359     //    FxRequest::m_InFlightListEntry
360     //
361 
362     //
363     // This is the Queue of current requests that have not
364     // been presented to the driver
365     //
366     FxIrpQueue          m_Queue;
367 
368     //
369     // This is the list of requests that driver has accepted
370     // and is working on, but wants to be cancelable.
371     //
372     FxIrpQueue          m_DriverCancelable;
373 
374     //
375     // This is a list of cancelled requests to be notified to the driver.
376     //
377     // FxListEntryQueueOwned of FxRequest is used for linkage
378     //
379     LIST_ENTRY          m_Cancelled;
380 
381     //
382     // This is a list of request cancelled on queue waiting
383     // to be notified to the driver.
384     //
385     // FxListEntryQueueOwned of FxRequest is used for linkage
386     //
387     LIST_ENTRY          m_CanceledOnQueueList;
388 
389     //
390     // This is a list of requests that the driver has accepted
391     // and is working on, but has not been completed.
392     //
393     // They may, or may not be cancelable.
394     //
395     // FxListEntryDriverOwned of FxRequest is used for linkage
396     //
397     LIST_ENTRY          m_DriverOwned;
398 
399     //
400     // This is the list of power stop/start requests to be notified to
401     // the driver.
402     //
403     // FxListEntryDriverOwned of FxRequest is used for linkage
404     //
405     LIST_ENTRY          m_PowerNotify;
406 
407     //
408     // This is the list of power stop requests in which the driver
409     // has been notified, and must be zero before power code can
410     // resume the power thread.
411     //
412     // FxListEntryDriverOwned of FxRequest is used for linkage
413     //
414     LIST_ENTRY          m_PowerDriverNotified;
415 
416     //
417     // Pointer to FxPkgIo object that contains this queue.
418     // (No additional reference count)
419     //
420     FxPkgIo*            m_PkgIo;
421 
422     //
423     // Weak pointer to the associated FxCxDeviceInfo struct.
424     //
425     FxCxDeviceInfo*     m_CxDeviceInfo;
426 
427     //
428     // This is the count of currently executing callback
429     // handlers into the device driver.
430     //
431     // It is used to control the dispatch state to prevent stack
432     // recursions, as well as to handle notification when a queue
433     // is idle and has no callbacks outstanding.
434     //
435     volatile ULONG      m_Dispatching;
436 
437     //
438     // This is set when a queue goes from empty to
439     // having requests and allows a callback to the driver
440     // when a queue is ready.
441     //
442     volatile BOOLEAN    m_TransitionFromEmpty;
443 
444     //
445     // This flag is set when the we return no_more_requests from
446     // WdfRequesdtGetNextRequest but the queue actually holds one or
447     // more requests in cancellation state (their cancellation routine
448     // are already running).
449     // This flag insures that we call the ReadyNotify callback when a new
450     // request is inserted in the queue.
451     //
452     volatile BOOLEAN    m_ForceTransitionFromEmptyWhenAddingNewRequest;
453 
454     //
455     // This is set when the driver starts a WdfIoQueueStopAndPurge operation.
456     // This is cleared in the following conditions:
457     //  (a) there are no more driver owned requests.
458     //  (b) driver re-enables the dispatch gate.
459     // When set any requeued requests will be automatically deleted.
460     //
461     volatile BOOLEAN    m_CancelDispatchedRequests;
462 
463     BOOLEAN             m_IsDevicePowerPolicyOwner;
464 
465     //
466     // This is the number of requests the driver
467     // currently is processing both cancellable and noncancellable.
468     //
469     // For serial queue dispatch mode, this is used
470     // to control when a request can be presented to the driver.
471     // This is also used to implement counted Queues to make
472     // sure the count doesn't exceed max. allowed on the
473     // parallel Queue.
474     //
475     volatile LONG       m_DriverIoCount;
476 
477     //
478     // This is the number of requests that are about to be completed using two
479     // phase completion technique (to support queued-by-driver requests).
480     //
481     volatile LONG       m_TwoPhaseCompletions;
482 
483     //
484     // These are the driver configured callbacks to send
485     // I/O events to the driver
486     //
487     FxIoQueueIoDefault         m_IoDefault;
488     FxIoQueueIoStop            m_IoStop;
489     FxIoQueueIoResume          m_IoResume;
490     FxIoQueueIoRead            m_IoRead;
491     FxIoQueueIoWrite           m_IoWrite;
492     FxIoQueueIoDeviceControl   m_IoDeviceControl;
493     FxIoQueueIoInternalDeviceControl m_IoInternalDeviceControl;
494     FxIoQueueIoCanceledOnQueue m_IoCanceledOnQueue;
495 
496     FxCallbackLock*     m_IoCancelCallbackLockPtr;
497 
498     //
499     // These are status events registered by the device driver
500     //
501     FxIoQueueIoState          m_IdleComplete;
502     WDFCONTEXT                 m_IdleCompleteContext;
503 
504     FxIoQueueIoState          m_PurgeComplete;
505     WDFCONTEXT                 m_PurgeCompleteContext;
506 
507     FxIoQueueIoState          m_ReadyNotify;
508     WDFCONTEXT                 m_ReadyNotifyContext;
509 
510     //
511     // The following items support the callback constraints
512     // and handle locking and deferral
513     //
514     WDF_EXECUTION_LEVEL       m_ExecutionLevel;
515     WDF_SYNCHRONIZATION_SCOPE m_SynchronizationScope;
516 
517     //
518     // These are the passive and dispatch level presentation locks
519     //
520     FxCallbackSpinLock  m_CallbackSpinLock;
521     FxCallbackMutexLock m_CallbackMutexLock;
522 
523     //
524     // This pointer allows the proper lock to be acquired
525     // based on the configuration with a minimal of runtime
526     // checks. This is configured by ConfigureLocking()
527     //
528     FxCallbackLock*     m_CallbackLockPtr;
529     FxObject*           m_CallbackLockObjectPtr;
530 
531     //
532     // The IoQueue must sometimes defer event delivery to the
533     // device driver due to interactions with current locks held,
534     // and the device driver configured callback constraints.
535     //
536     // When a deferral occurs, a DPC or FxSystemWorkItem is used
537     // to post an event to later deliver the event(s) to the device
538     // driver. Whether a DPC or WorkItem is used depends
539     // on the drivers configured execution level constraints.
540     //
541     // The IoQueue is designed to be robust in that multiple events
542     // may occur while the queued DPC or WorkItem is outstanding,
543     // and they will be properly processed without having to enqueue
544     // one for each event. Basically, they are just a signal that
545     // an IoQueue needs some attention that could result in device
546     // driver notification.
547     //
548     // KDPC is only needed in kernel mode
549     //
550 
551 
552 
553 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
554     KDPC               m_Dpc;
555 #endif
556 
557     FxSystemWorkItem*  m_SystemWorkItem;
558 
559     //
560     // These are true if the associated Dpc or Work Item is queued
561     //
562     BOOLEAN            m_DpcQueued;
563     BOOLEAN            m_WorkItemQueued;
564 
565     //
566     // Track whether the above DPC and WorkItem needs to be requeued.
567     //
568     BOOLEAN            m_RequeueDeferredDispatcher;
569 
570     // This is set when the Queue is power idle
571     MxEvent            m_PowerIdle;
572 
573 
574 
575 
576 
577 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
578     MxEvent            m_RequestWaitEventUm;
579 #endif
580 
581 public:
582 
583     //
584     // List node to tie the queue with FxPkgIo.
585     //
586     FxIoQueueNode      m_IoPkgListNode;
587     //
588     // List entry is used by FxPkgIo to iterate list all the queues without
589     // holding a lock.
590     //
591     SINGLE_LIST_ENTRY  m_PowerSListEntry;
592 
593 public:
594     // Factory function
595     _Must_inspect_result_
596     static
597     NTSTATUS
598     _Create(
599         __in PFX_DRIVER_GLOBALS         DriverGlobals,
600         __in_opt PWDF_OBJECT_ATTRIBUTES Attributes,
601         __in PWDF_IO_QUEUE_CONFIG       Config,
602         __in_opt FxDriver*              Caller,
603         __in FxPkgIo*                   PkgIo,
604         __in BOOLEAN                    InitialPowerStateOn,
605         __deref_out FxIoQueue**         Object
606         );
607 
608     FxIoQueue(
609         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
610         __in FxPkgIo* PkgIo
611         );
612 
613     virtual
614     ~FxIoQueue(
615        );
616 
617     _Must_inspect_result_
618     NTSTATUS
619     Initialize(
620         __in PWDF_IO_QUEUE_CONFIG       pConfig,
621         __in_opt PWDF_OBJECT_ATTRIBUTES QueueAttributes,
622         __in_opt FxDriver*              Caller,
623         __in BOOLEAN                    InitialPowerStateOn
624         );
625 
626     _Releases_lock_(this->m_SpinLock.m_Lock)
627     VOID
628     CancelForQueue(
629         __in FxRequest* pRequest,
630         __in __drv_restoresIRQL KIRQL PreviousIrql
631         );
632 
633     // Do not specify argument names
634     FX_DECLARE_VF_FUNCTION_P1(
635     VOID,
636     VerifyCancelForDriver,
637         _In_ FxRequest*
638         );
639 
640     VOID
641     CancelForDriver(
642         __in FxRequest* pRequest
643         );
644 
645     // Do not specify argument names
646     FX_DECLARE_VF_FUNCTION_P1(
647     VOID,
648     VerifyValidateCompletedRequest,
649         _In_ FxRequest*
650         );
651 
652     __inline
653     VOID
RequestCompletedCallback(__in FxRequest * Request)654     RequestCompletedCallback(
655         __in FxRequest* Request
656         )
657     {
658         //
659         // This is called when a FxRequest object completes based
660         // on the callback event registered by the I/O queue support
661         // routines.
662         //
663 
664         KIRQL irql;
665 
666 #if FX_VERBOSE_TRACE
667         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
668                             "Enter: WDFQUEUE 0x%p, WDFREQUEST 0x%p",
669                             GetObjectHandle(),Request->GetHandle());
670 #endif
671         VerifyValidateCompletedRequest(GetDriverGlobals(), Request);
672 
673         Lock(&irql);
674 
675         //
676         // I/O has been completed by the driver
677         //
678         RemoveFromDriverOwnedList(Request);
679 
680         //
681         // Don't run the event dispatcher if we come from a Request
682         // complete callback in order to prevent stack recursion.
683         //
684         // Since some other thread (possibly this thread higher on
685         // the stack) is running the dispatcher, no events will get lost.
686         //
687         DispatchInternalEvents(irql);
688     }
689 
690     __inline
691     VOID
PreRequestCompletedCallback(__in FxRequest * Request)692     PreRequestCompletedCallback(
693         __in FxRequest* Request
694         )
695     {
696         //
697         // This is called when a driver created request is about to be completed.
698         // This callback removes the FxRequest object from the internal queue linked
699         // lists.  A call to PostRequestCompletedCallback must be made after irp is
700         // completed.
701         //
702 
703         KIRQL irql;
704 
705 #if FX_VERBOSE_TRACE
706         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
707                             "Enter: WDFQUEUE 0x%p, WDFREQUEST 0x%p",
708                             GetObjectHandle(),Request->GetHandle());
709 #endif
710 
711         VerifyValidateCompletedRequest(GetDriverGlobals(), Request);
712 
713         Lock(&irql);
714 
715         //
716         // I/O has been completed by the driver
717         //
718         PreRemoveFromDriverOwnedList(Request);
719 
720         Unlock(irql);
721     }
722 
723     __inline
724     VOID
PostRequestCompletedCallback(__in FxRequest * Request)725     PostRequestCompletedCallback(
726         __in FxRequest* Request
727         )
728     {
729         // Do not acccess Request, at this point the object may have already been
730         // deleted or reused.
731 
732         //
733         // This is called when a queued-by-driver request (driver created) is
734         // completed or sent to a lower driver with 'send-and-forget' option.
735         // This callback allows the queue to schedule another request for delivery.
736         //
737 
738         KIRQL irql;
739 
740 #if FX_VERBOSE_TRACE
741         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO,
742                             "Enter: WDFQUEUE 0x%p, WDFREQUEST 0x%p",
743                             GetObjectHandle(), FxRequest::_ToHandle(Request));
744 #else
745         UNREFERENCED_PARAMETER(Request);
746 #endif
747 
748         Lock(&irql);
749 
750         //
751         // I/O has been completed by the driver
752         //
753         PostRemoveFromDriverOwnedList();
754 
755         //
756         // Don't run the event dispatcher if we come from a Request
757         // complete callback in order to prevent stack recursion.
758         //
759         // Since some other thread (possibly this thread higher on
760         // the stack) is running the dispatcher, no events will get lost.
761         //
762         DispatchInternalEvents(irql);
763     }
764 
765     __inline
766     FxDriver*
GetDriver(VOID)767     GetDriver(VOID) {
768         return m_PkgIo->GetDriver();
769     }
770 
771     __inline
772     CfxDevice*
GetDevice(VOID)773     GetDevice(VOID)
774     {
775         return m_Device;
776     }
777 
778     __inline
779     FxPkgIo*
GetPackage(VOID)780     GetPackage(VOID) {
781         return m_PkgIo;
782     }
783 
784     WDFQUEUE
785     __inline
GetHandle(VOID)786     GetHandle(
787         VOID
788         )
789     {
790         return (WDFQUEUE) GetObjectHandle();
791     }
792 
793     __inline
794     BOOLEAN
IsPowerManaged()795     IsPowerManaged() {
796         return m_PowerManaged;
797     }
798 
799     VOID
800     StartPowerTransitionOn(
801         VOID
802         );
803 
804     VOID
805     StartPowerTransitionOff(
806         VOID
807         );
808 
809     VOID
810     StopProcessingForPower(
811         __in FxIoStopProcessingForPowerAction Action
812         );
813 
814     VOID
815     ResumeProcessingForPower(
816         VOID
817         );
818 
819     VOID
820     SetStateForShutdown(
821         VOID
822         );
823 
824     VOID
825     ResetStateForRestart(
826         VOID
827         );
828 
829     WDF_IO_QUEUE_STATE
830     GetState(
831         __out_opt PULONG   pQueueCount,
832         __out_opt PULONG   pDriverCount
833        );
834 
835     VOID
836     SetState(
837         __in FX_IO_QUEUE_SET_STATE NewStatus
838        );
839 
840 
841     __inline
842     BOOLEAN
IsState(__in WDF_IO_QUEUE_STATE State)843     IsState(
844         __in WDF_IO_QUEUE_STATE State
845         )
846     {
847         ASSERT(!(State & 0x80000000)); // Don't allow FX_IO_QUEUE_SET states
848         return (((int)m_QueueState & (int) (State)) != 0);
849     }
850 
851     __inline
852     BOOLEAN
IsState(__in FX_IO_QUEUE_STATE State)853     IsState(
854         __in FX_IO_QUEUE_STATE State
855         )
856     {
857         ASSERT(!(State & 0x80000000)); // Don't allow FX_IO_QUEUE_SET states
858         return (((int)m_QueueState & (int) (State)) != 0);
859     }
860 
861     // GetRequest Verifiers
862     // Do not specify argument names
863     FX_DECLARE_VF_FUNCTION_P1(
864     NTSTATUS,
865     VerifyGetRequestUpdateFlags,
866         _In_ FxRequest*
867         );
868 
869     // Do not specify argument names
870     FX_DECLARE_VF_FUNCTION_P1(
871     VOID,
872     VerifyGetRequestRestoreFlags,
873         _In_ FxRequest*
874         );
875 
876     _Must_inspect_result_
877     NTSTATUS
878     GetRequest(
879         __in_opt  MdFileObject FileObject,
880         __in_opt  FxRequest*   TagRequest,
881         __deref_out FxRequest**  pOutRequest
882         );
883 
884     // PeekRequest Verifiers
885     // Do not specify argument names
886     FX_DECLARE_VF_FUNCTION_P1(
887     NTSTATUS,
888     VerifyPeekRequest,
889         _In_ FxRequest*
890         );
891 
892     _Must_inspect_result_
893     NTSTATUS
894     PeekRequest(
895         __in_opt  FxRequest*          TagRequest,
896         __in_opt  MdFileObject        FileObject,
897         __out_opt PWDF_REQUEST_PARAMETERS Parameters,
898         __deref_out FxRequest**         pOutRequest
899         );
900 
901     // ForwardRequest Verifiers
902     // Do not specify argument names
903     FX_DECLARE_VF_FUNCTION_P2(
904     NTSTATUS,
905     VerifyForwardRequest,
906         _In_ FxIoQueue*,
907         _In_ FxRequest*
908         );
909 
910     _Must_inspect_result_
911     NTSTATUS
912     ForwardRequest(
913         __in FxIoQueue* pDestQueue,
914         __in FxRequest* pRequest
915        );
916 
917     // QueueDriverCreatedRequest
918     // Do not specify argument names
919     FX_DECLARE_VF_FUNCTION_P2(
920     NTSTATUS,
921     VerifyQueueDriverCreatedRequest,
922         _In_    FxRequest*,
923         _Inout_ SHORT*
924         );
925 
926     _Must_inspect_result_
927     NTSTATUS
928     QueueDriverCreatedRequest(
929         __in FxRequest* Request,
930         __in BOOLEAN    ParentQueue
931         );
932 
933     __drv_requiresIRQL(DISPATCH_LEVEL)
934     VOID
935     ProcessAcknowledgedRequests(
936         __in FxRequest* Request,
937         __out PKIRQL PreviousIrql
938         );
939 
940     // Do not specify argument names
941     FX_DECLARE_VF_FUNCTION_P1(
942     NTSTATUS,
943     VerifyRequeue,
944         _In_ FxRequest*
945         );
946 
947     _Must_inspect_result_
948     NTSTATUS
949     Requeue(
950         __in FxRequest* pRequest
951        );
952 
953     // Do not specify argument names
954     FX_DECLARE_VF_FUNCTION_P2(
955     NTSTATUS,
956     VerifyRequestCancelable,
957         _In_ FxRequest*,
958         _In_ BOOLEAN
959         );
960 
961     _Must_inspect_result_
962     NTSTATUS
963     RequestCancelable(
964         __in FxRequest* pRequest,
965         __in BOOLEAN    Cancelable,
966         __in_opt PFN_WDF_REQUEST_CANCEL  EvtRequestCancel,
967         __in BOOLEAN    FailIfIrpIsCancelled
968        );
969 
970     _Must_inspect_result_
971     NTSTATUS
972     RequestCompleteEvent(
973        __in FxRequest* Request
974        );
975 
976 
977     _Must_inspect_result_
978     NTSTATUS
979     QueueRequest(
980         __in FxRequest* pRequest
981         );
982 
983     _Must_inspect_result_
984     NTSTATUS
985     QueueRequestFromForward(
986         __in FxRequest* pRequest
987         );
988 
989     _Must_inspect_result_
990     BOOLEAN
991     CanThreadDispatchEventsLocked(
992         __in KIRQL PreviousIrql
993         );
994 
995     _Releases_lock_(this->m_SpinLock.m_Lock)
996     __drv_requiresIRQL(DISPATCH_LEVEL)
997     BOOLEAN
998     DispatchEvents(
999         __in __drv_restoresIRQL KIRQL PreviousIrql,
1000         __in_opt FxRequest* NewRequest = NULL
1001         );
1002 
1003     _Releases_lock_(this->m_SpinLock.m_Lock)
__drv_requiresIRQL(DISPATCH_LEVEL)1004     __drv_requiresIRQL(DISPATCH_LEVEL)
1005     __inline
1006     VOID
1007     DispatchInternalEvents(
1008         __in __drv_restoresIRQL KIRQL PreviousIrql
1009         )
1010     /*++
1011 
1012         Routine Description:
1013 
1014         Dispatch events and requests from the queue to the driver.
1015 
1016         The IoQueue object lock must be held on entry, but this
1017         routine returns to the caller with the lock released.
1018 
1019         To avoid recursion, this routine checks to see if this or another
1020         thread is already in the dispatch-event loop. If so, it
1021         doesn't re-enter the dispatch-even loop.
1022 
1023     --*/
1024     {
1025         if(m_Dispatching == 0) {
1026             //
1027             // Nobody is dispatching events so we must
1028             // call the main DispatchEvents function because
1029             // the caller of this function might have affected the
1030             // state of the queue.
1031             //
1032             (VOID) DispatchEvents(PreviousIrql);
1033 
1034         } else {
1035 
1036             Unlock(PreviousIrql);
1037         }
1038     }
1039 
1040 
1041     VOID
1042     DispatchRequestToDriver(
1043         __in FxRequest* pRequest
1044         );
1045 
1046     virtual
1047     VOID
GetConstraints(__out WDF_EXECUTION_LEVEL * ExecutionLevel,__out WDF_SYNCHRONIZATION_SCOPE * SynchronizationScope)1048     GetConstraints(
1049         __out WDF_EXECUTION_LEVEL*       ExecutionLevel,
1050         __out WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope
1051         ) {
1052 
1053         if (ExecutionLevel != NULL) {
1054             *ExecutionLevel = m_ExecutionLevel;
1055         }
1056 
1057         if (SynchronizationScope != NULL) {
1058             *SynchronizationScope = m_SynchronizationScope;
1059         }
1060     }
1061 
1062     virtual
1063     FxCallbackLock*
GetCallbackLockPtr(__deref_out FxObject ** LockObject)1064     GetCallbackLockPtr(
1065         __deref_out FxObject** LockObject
1066         )
1067     {
1068         if (LockObject != NULL) {
1069             *LockObject = m_CallbackLockObjectPtr;
1070         }
1071 
1072         return m_CallbackLockPtr;
1073     }
1074 
1075     _Must_inspect_result_
1076     virtual
1077     NTSTATUS
QueryInterface(__in FxQueryInterfaceParams * Params)1078     QueryInterface(
1079         __in FxQueryInterfaceParams* Params
1080         )
1081     {
1082         switch (Params->Type) {
1083         case FX_TYPE_QUEUE:
1084             *Params->Object = (FxIoQueue*) this;
1085             break;
1086 
1087         case FX_TYPE_IHASCALLBACKS:
1088             *Params->Object = (IFxHasCallbacks*) this;
1089             break;
1090 
1091         default:
1092             return FxNonPagedObject::QueryInterface(Params); // __super call
1093         }
1094 
1095         return STATUS_SUCCESS;
1096     }
1097 
1098     virtual
1099     BOOLEAN
1100     Dispose(
1101         VOID
1102         );
1103 
1104     //
1105     // Start the Queue
1106     //
1107     VOID
1108     QueueStart(
1109         VOID
1110         );
1111 
1112     //
1113     // Idle/Stop the Queue
1114     //
1115     _Must_inspect_result_
1116     NTSTATUS
1117     QueueIdle(
1118         __in BOOLEAN                    CancelQueueRequests,
1119         __in_opt PFN_WDF_IO_QUEUE_STATE IdleComplete,
1120         __in_opt WDFCONTEXT             Context
1121         );
1122 
1123     //
1124     // Idle the Queue
1125     //
1126     _Must_inspect_result_
1127     NTSTATUS
1128     QueueIdleSynchronously(
1129         __in BOOLEAN    CancelRequests
1130         );
1131 
1132     //
1133     // Purge the Queue
1134     //
1135     _Must_inspect_result_
1136     NTSTATUS
1137     QueuePurge(
1138         __in BOOLEAN                 CancelQueueRequests,
1139         __in BOOLEAN                 CancelDriverRequests,
1140         __in_opt PFN_WDF_IO_QUEUE_STATE PurgeComplete,
1141         __in_opt WDFCONTEXT              Context
1142         );
1143 
1144     _Must_inspect_result_
1145     NTSTATUS
1146     QueuePurgeSynchronously(
1147         VOID
1148         );
1149 
1150     //
1151     // Idle the Queue
1152     //
1153     _Must_inspect_result_
1154     NTSTATUS
1155     QueueDrain(
1156         __in_opt PFN_WDF_IO_QUEUE_STATE DrainComplete,
1157         __in_opt WDFCONTEXT              Context
1158         );
1159 
1160     //
1161     // Idle the Queue
1162     //
1163     _Must_inspect_result_
1164     NTSTATUS
1165     QueueDrainSynchronously(
1166         VOID
1167         );
1168 
1169     //
1170     // Notify the driver through a callback when the queue transitions
1171     // from no requests to having a request.
1172     //
1173     _Must_inspect_result_
1174     NTSTATUS
1175     ReadyNotify(
1176         __in PFN_WDF_IO_QUEUE_STATE QueueReady,
1177         __in_opt WDFCONTEXT              Context
1178         );
1179 
1180 
1181     VOID
1182     FlushByFileObject(
1183         __in MdFileObject FileObject
1184         );
1185 
1186     //
1187     // Return count of queued and driver pending requests.
1188     //
1189     VOID
1190     GetRequestCount(
1191         __out_opt PULONG pQueuedRequests,
1192         __out_opt PULONG pDriverPendingRequests
1193         );
1194 
1195 
1196     _Must_inspect_result_
1197     NTSTATUS
1198     ConfigureConstraints(
1199         __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes,
1200         __in_opt FxDriver*              Caller
1201         );
1202 
1203     VOID
1204     DeferredDispatchRequestsFromDpc(
1205         VOID
1206         );
1207 
1208     VOID
1209     DeferredDispatchRequestsFromWorkerThread(
1210         VOID
1211         );
1212 
1213     __inline
1214     static
1215     FxIoQueue*
_FromIoPkgListEntry(__in PLIST_ENTRY Entry)1216     _FromIoPkgListEntry(
1217         __in PLIST_ENTRY Entry
1218         )
1219     {
1220         return CONTAINING_RECORD(Entry, FxIoQueue, m_IoPkgListNode.m_ListEntry);
1221     }
1222 
1223     __inline
1224     static
1225     FxIoQueue*
_FromPowerSListEntry(__in PSINGLE_LIST_ENTRY Entry)1226     _FromPowerSListEntry(
1227         __in PSINGLE_LIST_ENTRY Entry
1228         )
1229     {
1230         return CONTAINING_RECORD(Entry, FxIoQueue, m_PowerSListEntry);
1231     }
1232 
1233     DECLSPEC_NORETURN
1234     VOID
1235     FatalError(
1236         __in NTSTATUS Status
1237         );
1238 
1239     BOOLEAN
1240     IsIoEventHandlerRegistered(
1241         __in WDF_REQUEST_TYPE RequestType
1242         );
1243 
1244     __inline
1245     VOID
SetPowerState(__in FXIOQUEUE_POWER_STATE PowerState)1246     SetPowerState(
1247         __in FXIOQUEUE_POWER_STATE PowerState
1248         )
1249     {
1250         if (m_PowerManaged) {
1251             m_PowerState = PowerState;
1252         }
1253     }
1254 
1255     _Must_inspect_result_
1256     NTSTATUS
1257     GetReservedRequest(
1258         __in MdIrp Irp,
1259         __deref_out_opt FxRequest **ReservedRequest
1260         );
1261 
1262     __inline
1263     BOOLEAN
IsForwardProgressQueue(VOID)1264     IsForwardProgressQueue(
1265         VOID
1266         )
1267     {
1268         return m_SupportForwardProgress;
1269     }
1270 
1271     __inline
1272     NTSTATUS
InvokeAllocateResourcesCallback(__in FxRequest * Request)1273     InvokeAllocateResourcesCallback(
1274     __in FxRequest *Request
1275     )
1276     /*++
1277 
1278     Routine Description:
1279         Give callback to allocate resources at runtime for a general request
1280         (not a reserved request).
1281 
1282     --*/
1283     {
1284         NTSTATUS status;
1285 
1286         ASSERT(Request->IsReserved() == FALSE);
1287 
1288         status = STATUS_SUCCESS;
1289         if (m_FwdProgContext->m_IoResourcesAllocate.Method != NULL) {
1290             Request->SetPresented();
1291             status = m_FwdProgContext->m_IoResourcesAllocate.Invoke(
1292                 GetHandle(), Request->GetHandle());
1293         }
1294 
1295         return status;
1296     }
1297 
1298     VOID
1299     ReturnReservedRequest(
1300         __in FxRequest *ReservedRequest
1301         );
1302 
1303     _Must_inspect_result_
1304     NTSTATUS
1305     AllocateReservedRequest(
1306         __deref_out FxRequest** Request
1307         );
1308 
1309     _Must_inspect_result_
1310     NTSTATUS
1311     AssignForwardProgressPolicy(
1312         __in PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY Policy
1313     );
1314 
1315     // ForwardRequestWorker verifiers
1316     // Do not specify argument names
1317     FX_DECLARE_VF_FUNCTION_P1_EX(
1318     ,
1319     SHORT,
1320     0,
1321     VerifyForwardRequestUpdateFlags,
1322         _In_ FxRequest*
1323         );
1324 
1325     _Must_inspect_result_
1326     NTSTATUS
1327     ForwardRequestWorker(
1328         __in FxRequest* Request,
1329         __in FxIoQueue* DestQueue
1330         );
1331 
1332     // ForwardRequestToParent Verifiers
1333     // Do not specify argument names
1334     FX_DECLARE_VF_FUNCTION_P2(
1335     NTSTATUS,
1336     VerifyForwardRequestToParent,
1337         _In_ FxIoQueue*,
1338         _In_ FxRequest*
1339         );
1340 
1341     _Must_inspect_result_
1342     NTSTATUS
1343     ForwardRequestToParent(
1344         __in FxIoQueue* DestQueue,
1345         __in FxRequest* Request,
1346         __in PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions
1347         );
1348 
1349     __inline
1350     VOID
SetCxDeviceInfo(__in FxCxDeviceInfo * CxDeviceInfo)1351     SetCxDeviceInfo(
1352         __in FxCxDeviceInfo* CxDeviceInfo
1353         )
1354     {
1355         m_CxDeviceInfo = CxDeviceInfo;
1356     }
1357 
1358     __inline
1359     FxCxDeviceInfo*
GetCxDeviceInfo(VOID)1360     GetCxDeviceInfo(
1361         VOID
1362         )
1363     {
1364         return m_CxDeviceInfo;
1365     }
1366 
1367     __inline
1368     VOID
SetInterruptQueue(VOID)1369     SetInterruptQueue(
1370         VOID
1371         )
1372     {
1373         MarkNoDeleteDDI(ObjectLock);
1374     }
1375 
1376     VOID
1377     FlushQueuedDpcs(
1378         VOID
1379         );
1380 
1381     VOID
1382     InsertQueueDpc(
1383         VOID
1384     );
1385 
1386 private:
1387 
1388     //
1389     // Helper functions for event processing loop DispatchEvents()
1390     //
1391     __drv_requiresIRQL(DISPATCH_LEVEL)
1392     VOID
1393     ProcessIdleComplete(
1394         __out PKIRQL PreviousIrql
1395         );
1396 
1397     __drv_requiresIRQL(DISPATCH_LEVEL)
1398     VOID
1399     ProcessPurgeComplete(
1400         __out PKIRQL PreviousIrql
1401         );
1402 
1403     __drv_requiresIRQL(DISPATCH_LEVEL)
1404     VOID
1405     ProcessReadyNotify(
1406         __out PKIRQL PreviousIrql
1407         );
1408 
1409     __drv_requiresIRQL(DISPATCH_LEVEL)
1410     BOOLEAN
1411     ProcessCancelledRequests(
1412         __out PKIRQL PreviousIrql
1413         );
1414 
1415     __drv_requiresIRQL(DISPATCH_LEVEL)
1416     BOOLEAN
1417     ProcessCancelledRequestsOnQueue(
1418         __out PKIRQL PreviousIrql
1419         );
1420 
1421     __drv_requiresIRQL(DISPATCH_LEVEL)
1422     BOOLEAN
1423     ProcessPowerEvents(
1424         __out PKIRQL PreviousIrql
1425         );
1426 
1427     __inline
1428     BOOLEAN
IsPowerStateNotifyingDriver(VOID)1429     IsPowerStateNotifyingDriver(
1430         VOID
1431         )
1432     {
1433         if (m_PowerState == FxIoQueuePowerStoppingNotifyingDriver ||
1434             m_PowerState == FxIoQueuePowerPurgeNotifyingDriver ||
1435             m_PowerState == FxIoQueuePowerRestartingNotifyingDriver) {
1436             return TRUE;
1437         }
1438         else {
1439             return FALSE;
1440         }
1441     }
1442 
1443     //
1444     // Insert in the list of requests that the driver is operating
1445     // on.
1446     //
1447     // Must be called with the FxIoQueue lock held.
1448     //
1449     __inline
1450     VOID
InsertInDriverOwnedList(__in FxRequest * Request)1451     InsertInDriverOwnedList(
1452         __in FxRequest* Request
1453         )
1454     {
1455         m_DriverIoCount++;
1456 
1457         InsertTailList(&m_DriverOwned, Request->GetListEntry(FxListEntryDriverOwned));
1458         return;
1459     }
1460 
1461     //
1462     // Remove the request from the list that the driver is operating
1463     // on.
1464     //
1465     // Must be called with the FxIoQueue lock held.
1466     //
1467     // Note: ForwardRequest and two phase completions (queued-by-driver) cases breaks
1468     //          this up and manipulates the list entry and m_DriverIoCount separately.
1469     //
1470     __inline
1471     VOID
RemoveFromDriverOwnedList(__in FxRequest * Request)1472     RemoveFromDriverOwnedList(
1473         __in FxRequest* Request
1474         )
1475     {
1476         PLIST_ENTRY listEntry;
1477 
1478         listEntry = Request->GetListEntry(FxListEntryDriverOwned);
1479 
1480         RemoveEntryList(listEntry);
1481         InitializeListHead(listEntry);
1482 
1483         m_DriverIoCount--;
1484         ASSERT(m_DriverIoCount >= 0);
1485 
1486         return;
1487     }
1488 
1489     //
1490     // Pre-Remove the request from the list that the driver is operating on
1491     // (the first of two phase completion).
1492     //
1493     // Must be called with the FxIoQueue lock held.
1494     //
1495     __inline
1496     VOID
PreRemoveFromDriverOwnedList(__in FxRequest * Request)1497     PreRemoveFromDriverOwnedList(
1498         __in FxRequest* Request
1499         )
1500     {
1501         PLIST_ENTRY listEntry;
1502 
1503         listEntry = Request->GetListEntry(FxListEntryDriverOwned);
1504 
1505         RemoveEntryList(listEntry);
1506         InitializeListHead(listEntry);
1507 
1508         m_TwoPhaseCompletions++;
1509         ASSERT(m_TwoPhaseCompletions > 0);
1510 
1511         return;
1512     }
1513 
1514     //
1515     // Post-Remove the request from the list that the driver is operating on
1516     // (the second of two phase completion).
1517     //
1518     // Must be called with the FxIoQueue lock held.
1519     //
1520     __inline
1521     VOID
PostRemoveFromDriverOwnedList(VOID)1522     PostRemoveFromDriverOwnedList(
1523         VOID
1524         )
1525     {
1526         m_TwoPhaseCompletions--;
1527         ASSERT(m_TwoPhaseCompletions >= 0);
1528 
1529         m_DriverIoCount--;
1530         ASSERT(m_DriverIoCount >= 0);
1531         return;
1532     }
1533 
1534     //
1535     // This is called after inserting a new request in the IRP queue.
1536     //
1537     // Must be called with the FxIoQueue lock held.
1538     //
1539     __inline
1540     VOID
CheckTransitionFromEmpty(VOID)1541     CheckTransitionFromEmpty(
1542         VOID
1543         )
1544     {
1545         if (m_Queue.GetRequestCount() == 1L ||
1546             m_ForceTransitionFromEmptyWhenAddingNewRequest) {
1547 
1548             SetTransitionFromEmpty();
1549         }
1550     }
1551 
1552     //
1553     // Indicate that the queue went from empty to having one or more requests.
1554     //
1555     // Must be called with the FxIoQueue lock held.
1556     //
1557     __inline
1558     VOID
SetTransitionFromEmpty(VOID)1559     SetTransitionFromEmpty(
1560         VOID
1561         )
1562     {
1563         m_TransitionFromEmpty = TRUE;
1564         m_ForceTransitionFromEmptyWhenAddingNewRequest = FALSE;
1565 
1566         if(m_IsDevicePowerPolicyOwner &&
1567            m_PowerManaged &&
1568            m_PowerReferenced == FALSE) {
1569 
1570             if (NT_SUCCESS(m_Device->m_PkgPnp->PowerReference(FALSE))) {
1571                 m_PowerReferenced = TRUE;
1572             }
1573         }
1574     }
1575 
1576     NTSTATUS
1577     InsertNewRequestLocked(
1578         __deref_in FxRequest** Request,
1579         __in KIRQL PreviousIrql
1580         );
1581 
1582     __inline
1583     NTSTATUS
InsertNewRequest(__in FxRequest ** Request,__in KIRQL PreviousIrql)1584     InsertNewRequest(
1585         __in FxRequest** Request,
1586         __in KIRQL PreviousIrql
1587         )
1588     {
1589         NTSTATUS status;
1590 
1591         if (*Request != NULL) {
1592             status = InsertNewRequestLocked(Request, PreviousIrql);
1593         }
1594         else {
1595             status = STATUS_SUCCESS; // nothing to do.
1596         }
1597 
1598         return status;
1599     }
1600 
1601     VOID
1602     FreeAllReservedRequests(
1603         __in BOOLEAN Verify
1604         );
1605 
1606     _Must_inspect_result_
1607     NTSTATUS
1608     QueueForwardProgressIrpLocked(
1609         __in MdIrp Irp
1610         );
1611 
1612     _Must_inspect_result_
1613     MdIrp
1614     GetForwardProgressIrpLocked(
1615         __in_opt PFILE_OBJECT FileObject
1616         );
1617 
1618     BOOLEAN
1619     IsPagingIo(
1620         __in MdIrp Irp
1621     );
1622 
1623     VOID
PutBackReservedRequest(__in FxRequest * ReservedRequest)1624     PutBackReservedRequest(
1625         __in FxRequest *ReservedRequest
1626     )
1627     {
1628         KIRQL      oldIrql;
1629     PLIST_ENTRY listEntry;
1630 
1631     ASSERT(m_Deleted == FALSE);
1632 
1633     listEntry = ReservedRequest->GetListEntry(FxListEntryForwardProgress);
1634 
1635     m_FwdProgContext->m_PendedReserveLock.Acquire(&oldIrql);
1636 
1637     RemoveEntryList(listEntry);
1638     InitializeListHead(listEntry);
1639 
1640     InsertTailList(&m_FwdProgContext->m_ReservedRequestList, listEntry);
1641 
1642     if (GetDriverGlobals()->FxVerifierIO) {
1643       VerifierVerifyFwdProgListsLocked();
1644     }
1645 
1646     m_FwdProgContext->m_PendedReserveLock.Release(oldIrql);
1647     }
1648 
1649 
1650     VOID
1651     GetForwardProgressIrps(
1652         __in     PLIST_ENTRY    IrpListHead,
1653         __in_opt MdFileObject   FileObject
1654         );
1655 
1656     VOID
1657     CancelIrps(
1658         __in PLIST_ENTRY    IrpListHead
1659         );
1660 
1661     VOID
1662     PurgeForwardProgressIrps(
1663         __in_opt MdFileObject FileObject
1664         );
1665 
1666     VOID
1667     VerifierVerifyFwdProgListsLocked(
1668         VOID
1669         );
1670 
1671 protected:
1672     static
1673     EVT_IRP_QUEUE_CANCEL
1674     _IrpCancelForQueue;
1675 
1676     //
1677     // This is our Cancel Safe Queue Callback from
1678     // FxIrpQueue notifying us of an I/O cancellation
1679     // on a driver owned request (driver queue)
1680     //
1681     static
1682     EVT_IRP_QUEUE_CANCEL
1683     _IrpCancelForDriver;
1684 
1685     static
1686     EVT_SYSTEMWORKITEM
1687     _DeferredDispatchThreadThunk;
1688 
1689     static
1690     MdDeferredRoutineType
1691     _DeferredDispatchDpcThunk;
1692 
1693     static
1694     EVT_WDF_IO_QUEUE_STATE
1695     _PurgeComplete;
1696 
1697     static
1698     EVT_WDF_IO_QUEUE_STATE
1699     _IdleComplete;
1700 
1701     static
1702     MdCancelRoutineType
1703     _WdmCancelRoutineForReservedIrp;
1704 
1705 };
1706 
1707 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
1708 #include "fxioqueuekm.hpp"
1709 #else
1710 #include "fxioqueueum.hpp"
1711 #endif
1712 
1713 
1714 #endif // _FXIOQUEUE_H_
1715