ReactOS  0.4.15-dev-2945-g7100a24
fxioqueue.cpp
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7  FxIoQueue.cpp
8 
9 Abstract:
10 
11  This module implements the FxIoQueue object and C interfaces
12 
13 Author:
14 
15 
16 
17 
18 Revision History:
19 
20 
21 
22 
23 --*/
24 
25 #include "ioprivshared.hpp"
26 #include "fxioqueue.hpp"
27 
28 extern "C" {
29 #if defined(EVENT_TRACING)
30 #include "FxIoQueue.tmh"
31 #endif
32 }
33 
34 //
35 // Public constructors
36 //
38  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
39  __in FxPkgIo* PkgIo
40  ) :
41  FxNonPagedObject(FX_TYPE_QUEUE, sizeof(FxIoQueue), FxDriverGlobals),
42  m_CallbackSpinLock(FxDriverGlobals),
43  m_CallbackMutexLock(FxDriverGlobals),
44  m_IoPkgListNode(FxIoQueueNodeTypeQueue)
45  {
54 
55  // A newly created queue can not accept requests until initialized
57 
58  //
59  // Set our Cancel callbacks
60  //
62 
64 
66 
68 
70 
72 
74 
76 
77  //
78  // We do not reference count the I/O package instance
79  // since it contains us. The fact we exist, the I/O
80  // package instance exists.
81  //
82  m_PkgIo = PkgIo;
84 
85  m_Device = PkgIo->GetDevice();
86 
89 
90  m_Dispatching = 0L;
91 
94 
95  m_DriverIoCount = 0L;
97 
99 
102 
105 
108 
111 
112 #if FX_IS_KERNEL_MODE
113 
114  // Initialize the DPC used for deferrals
116  &m_Dpc,
118  this
119  );
120 #endif
121 
122  m_DpcQueued = FALSE;
123 
125 
127 
128  m_Deleted = FALSE;
131 
134 
138 
139  return;
140 }
141 
143 {
145 
146  if (m_PkgIo != NULL) {
147  m_PkgIo = NULL;
148  }
149 
160 }
161 
163 NTSTATUS
168  __in_opt FxDriver* Caller,
169  __in FxPkgIo* PkgIo,
170  __in BOOLEAN InitialPowerStateOn,
172  )
173 {
175  FxIoQueue* pQueue;
176 
177  *Object = NULL;
178 
180 
181  if (pQueue == NULL) {
184  "Memory allocation failed: %!STATUS!", status);
185  return status;
186  }
187 
188  //
189  // Initialize it, creating the handle to pass the driver
190  // and configuring its callbacks and queue type
191  //
193  Attributes,
194  Caller,
195  InitialPowerStateOn);
196  if (!NT_SUCCESS(status)) {
198  "Could not configure queue: %!STATUS!", status);
199  goto Done;
200  }
201 Done:
202  if (NT_SUCCESS(status)) {
203  *Object = pQueue;
204  }
205  else {
206  //
207  // Release our newly allocated Queue object
208  //
210  }
211 
212  return status;
213 }
214 
216 NTSTATUS
218  __in PWDF_IO_QUEUE_CONFIG pConfig,
220  __in_opt FxDriver* Caller,
221  __in BOOLEAN InitialPowerStateOn
222  )
223 
224 /*++
225 
226 Routine Description:
227 
228  Initialize the IoQueue after creating.
229 
230  This creates the handle required for passing to the driver.
231 
232 Arguments:
233 
234 Returns:
235 
236  NTSTATUS
237 
238 --*/
239 
240 {
242  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
243 
245  if (!NT_SUCCESS(Status)) {
246  return Status;
247  }
248 
250  if (!NT_SUCCESS(Status)) {
251  return Status;
252  }
253 
254 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
256  if (!NT_SUCCESS(Status)) {
257  return Status;
258  }
259 #endif
260 
262 
263  //
264  // Set the execution level and callback synchronization based on
265  // configuration
266  //
268  if (!NT_SUCCESS(Status)) {
269  return Status;
270  }
271 
272  //
273  // Validate dispatch type.
274  //
275  if (pConfig->DispatchType <= WdfIoQueueDispatchInvalid ||
276  pConfig->DispatchType >= WdfIoQueueDispatchMax) {
278  "Invalid dispatch type "
279  "specified %d, Queue 0x%p %!STATUS!",
280  pConfig->DispatchType,
281  GetObjectHandle(),
284  }
285 
286  //
287  // If not a manual queue, must set at least IoStart, or one of
288  // read|write|devicecontrol
289  //
290  if ((pConfig->DispatchType != WdfIoQueueDispatchManual) &&
291  (pConfig->EvtIoDefault == NULL)) {
292 
293  if ((pConfig->EvtIoDefault == NULL) &&
294  (pConfig->EvtIoRead == NULL) &&
295  (pConfig->EvtIoWrite == NULL) &&
296  (pConfig->EvtIoDeviceControl == NULL) &&
297  (pConfig->EvtIoInternalDeviceControl == NULL)) {
298 
300  "At least one of EvtIoDefault|EvtIoRead|EvtIoWrite|"
301  "EvtIoDeviceControl|EvtIoInternalDeviceControl "
302  "must be set %!STATUS!", STATUS_WDF_NO_CALLBACK);
303  return STATUS_WDF_NO_CALLBACK;
304  }
305  }
306 
307  //
308  // A manual queue should not set any callback function
309  // pointers since they will not get invoked.
310  //
311  if (pConfig->DispatchType == WdfIoQueueDispatchManual) {
312 
313  if ((pConfig->EvtIoDefault != NULL) ||
314  (pConfig->EvtIoRead != NULL) ||
315  (pConfig->EvtIoWrite != NULL) ||
316  (pConfig->EvtIoDeviceControl != NULL) ||
317  (pConfig->EvtIoInternalDeviceControl != NULL)) {
318 
320  "Cannot set io callback events "
321  "on a manual WDFQUEUE 0x%p %!STATUS!",
322  GetObjectHandle(),
325  }
326  }
327 
328  //
329  // For version less than v1.9 m_MaxParallelQueuePresentedRequests is set to
330  // -1 by the FxIoQueue Constructor.
331  // By checking > below we mean v1.9 and above (public API already did the official
332  // validation).
333  //
334  if (pConfig->Size > sizeof(WDF_IO_QUEUE_CONFIG_V1_7)) {
335  if (pConfig->Settings.Parallel.NumberOfPresentedRequests != 0 &&
336  (pConfig->DispatchType == WdfIoQueueDispatchSequential ||
337  pConfig->DispatchType == WdfIoQueueDispatchManual)) {
340  "Cannot have NumberOfPresentedRequests other "
341  "than 0 on a Sequential or manual WDFQUEUE 0x%p."
342  "Make Sure you set NumberOfPresentedRequests"
343  " to 0, %!STATUS!",
344  GetObjectHandle(),
345  Status
346  );
347  return Status;
348 
349  }
350  else{
352  pConfig->Settings.Parallel.NumberOfPresentedRequests;
353  }
354  }
355 
356  //
357  // Initialize our workitem if we have to support passive callbacks
358  //
359  if (m_PassiveLevel) {
360 
361  Status = FxSystemWorkItem::_Create(FxDriverGlobals,
364  );
365 
366  if (!NT_SUCCESS(Status)) {
368  "Could not allocate workitem: %!STATUS!", Status);
369  return Status;
370  }
371  }
372 
373  m_Type = pConfig->DispatchType;
374 
375  switch(pConfig->PowerManaged) {
376 
377  case WdfUseDefault:
378  if(m_Device->IsFilter()){
380  } else {
382  }
383  break;
384 
385  case WdfTrue:
387  break;
388 
389  case WdfFalse:
391  break;
392  default:
393  ASSERTMSG("Invalid value in WDF_IO_QUEUE_CONFIG PowerManaged field\n", FALSE);
394  break;
395  }
396 
397  //
398  // Queues for NonPnp devices can't be power managed.
399  //
400  if(m_Device->IsLegacy()) {
402  }
403 
404  //
405  // If power managed queue, ensure its initial power state
406  // is same as the device.
407  //
408  if (m_PowerManaged) {
409  if (InitialPowerStateOn) {
411  }
412  else {
414  }
415  } else {
417  }
418 
419  m_AllowZeroLengthRequests = pConfig->AllowZeroLengthRequests;
420 
422  "EvtIoDefault 0x%p, EvtIoRead 0x%p, EvtIoWrite 0x%p, "
423  "EvtIoDeviceControl 0x%p for WDFQUEUE 0x%p",
424  pConfig->EvtIoDefault,
425  pConfig->EvtIoRead,
426  pConfig->EvtIoWrite,
427  pConfig->EvtIoDeviceControl, GetObjectHandle());
428 
429  m_IoDefault.Method = pConfig->EvtIoDefault;
430  m_IoStop.Method = pConfig->EvtIoStop;
431  m_IoResume.Method = pConfig->EvtIoResume;
432  m_IoRead.Method = pConfig->EvtIoRead;
433  m_IoWrite.Method = pConfig->EvtIoWrite;
434  m_IoDeviceControl.Method = pConfig->EvtIoDeviceControl;
435  m_IoInternalDeviceControl.Method = pConfig->EvtIoInternalDeviceControl;
436  m_IoCanceledOnQueue.Method = pConfig->EvtIoCanceledOnQueue;
437 
438 
439  // A newly created queue can accept and dispatch requests once initialized
441 
442  m_Configured = TRUE;
443 
444  return STATUS_SUCCESS;
445 }
446 
447 BOOLEAN
449  )
450 /*++
451 
452 Routine Description:
453 
454  Should be called at PASSIVE_LEVEL because of the synchronous call
455  to drain requests, workitems, and dpcs associated with this queue.
456 
457 Arguments:
458 
459 Returns:
460 
461  TRUE or FALSE
462 
463 --*/
464 {
465  KIRQL irql;
466 
467  if (IsCommitted() == FALSE) {
468  //
469  // We called DeleteFromFailedCreate because we couldn't commit the
470  // object.
471  //
472  goto End;
473  }
474 
475  //
476  // If object is commited means we are added to the FxPkgIo queue list.
477  //
478  //
479  // Purge the queue asynchrnously without providing any callback. That way,
480  // we allow the driver to have an outstanding purge request while the delete
481  // is in progress.
482  //
484 
485  Lock(&irql);
486 
487  //
488  // Mark that this queue is disposing
489  //
490 
492 
493  m_Disposing = TRUE;
494 
495  //
496  // Just make sure the state hasn't changed after the purge.
497  //
499 
500  //
501  // Call the FxPkgIo to remove its references to this queue
502  //
503  // Note: We are holding the queue lock to prevent races, and
504  // FxPkgIo never calls FxIoQueue methods while holding
505  // its lock.
506  //
508 
509  DispatchEvents(irql);
510 
511  //
512  // Wait for the finished event to be signalled. This event will
513  // be signalled when the queue is in a disposed state and there
514  // are no more pending events.
515  //
517  "waiting for the queue to be deleted, WDFQUEUE", GetHandle(),
520 
521 
522  ASSERT(m_Deleted == TRUE);
523 
525  ASSERT(m_DriverIoCount == 0);
526 
527  if (IsForwardProgressQueue()) {
531  }
532 
533  if (m_FwdProgContext != NULL) {
537  }
538 
539  //
540  // Rundown the workitem.
541  //
542  if (m_SystemWorkItem != NULL) {
545  }
546 
547  //
548  // Rundown the DPCs
549  //
550  if (m_DpcQueued) {
551  FlushQueuedDpcs();
552  }
553 
554  //
555  // All callbacks into the device driver acquire and release a
556  // reference on the queue. This ensures that the queue will
557  // not actually complete deleting until return from any
558  // outstanding event callbacks into the device driver.
559  //
560  // See DispatchRequestToDriver()
561  //
562 End:
563 
564  FxNonPagedObject::Dispose(); // __super call
565 
566  return TRUE;
567 }
568 
570 NTSTATUS
573  __in_opt FxDriver* Caller
574  )
575 
576 /*++
577 
578 Routine Description:
579 
580  Configures the locking and threading model for the
581  Queue according to parameters specified by the device
582  driver when it initialized.
583 
584 Arguments:
585 
586 Returns:
587 
588  NTSTATUS
589 
590 --*/
591 
592 {
593  WDF_EXECUTION_LEVEL ParentLevel;
594  WDF_SYNCHRONIZATION_SCOPE ParentScope;
595  BOOLEAN AutomaticLockingRequired;
596 
597  AutomaticLockingRequired = FALSE;
598  ASSERT(m_Device != NULL);
599 
600  //
601  // Initialize both spin and mutex locks
602  //
605 
606  //
607  // If WDF_OBJECT_ATTRIBUTES is specified, these override any
608  // default settings.
609  //
610  if (ObjectAttributes != NULL) {
611  m_ExecutionLevel = ObjectAttributes->ExecutionLevel;
612  m_SynchronizationScope = ObjectAttributes->SynchronizationScope;
613  }
614 
615  //
616  // If no WDFQUEUE specific attributes are specified, we
617  // get them from WDFDEVICE, which allows WDFDEVICE to
618  // provide a default for all WDFQUEUE's created.
619  //
620  m_Device->GetConstraints(&ParentLevel, &ParentScope);
623 
625  m_ExecutionLevel = ParentLevel;
626  }
627 
629  m_SynchronizationScope = ParentScope;
630  }
631 
632  //
633  // For backward compatibility purposes always have a lock associated with the
634  // object even for WdfSynchronizationScopeNone. This is so that we return a non-null
635  // presentation lock for the WDFQUEUE object.
636  //
638  //
639  // Mark FxObject as passive level to ensure that Dispose and Destroy
640  // callbacks are passive to the driver
641  //
644 
645  //
646  // Passive Callbacks constraint has been set, we use a mutex for the
647  // callback lock.
648  //
651  }
652  else {
653  //
654  // If no passive level constraint is specified, then spinlocks
655  // are used for callbacks since they are lightweight and work with
656  // DPC's and Timer's
657  //
660  }
661 
662  //
663  // Configure synchronization scope
664  //
667 
668  //
669  // WDF extensions are not allowed to use this type of synchronization.
670  //
671  if (Caller != NULL && Caller != GetDriverGlobals()->Driver) {
674  "WDFQUEUE 0x%p Synchronization scope is set to "
675  "device; WDF extension drivers are not allowed "
676  "to use this type of synchronization, %!STATUS!",
678  return status;
679  }
680 
681  //
682  // If we inherit the Sync. scope from parent or device
683  // and if the parent/device has Exec. Level different from Queue
684  // then disallow that case.
685  // FUTURE PROOF NOTE: Adding a new Execution Level will need reevaluation
686  // of the check below.
687  //
688  if (ParentLevel != m_ExecutionLevel) {
691  "WDFQUEUE 0x%p Synchronization scope is set to device"
692  " but the Device ExecutionLevel: 0x%x"
693  " doesn't match Queue ExecutionLevel: 0x%x, %!STATUS!",
694  GetObjectHandle(), ParentLevel,
696  return status;
697  }
698  //
699  // Per device automatic callback synchronization, so we update our
700  // callback lock ptr to point to the devices lock
701  //
702  AutomaticLockingRequired = TRUE;
703 
704  //
705  // Get the callback lock and object from the device
706  //
708  }
710  //
711  // Per object automatic serialization
712  //
713  AutomaticLockingRequired = TRUE;
714 
715  // m_CallbackLockPtr has been set above in execution level constraint
716  }
717 
718 
719  if (AutomaticLockingRequired) {
720  //
721  // If automatic locking has been configured, set the lock
722  // on the FxCallback object delegates
723  //
734 
736  }
737  else {
738  //
739  // No automatic locking specified
740  //
751 
753 
754  }
755 
756  return STATUS_SUCCESS;
757 }
758 
761  __out_opt PULONG pQueueCount,
762  __out_opt PULONG pDriverCount
763  )
764 {
765  int stat;
767 
768  // Get request counts
770 
771  if (pQueueCount ) *pQueueCount = QueueCount;
772 
773  if (pDriverCount ) *pDriverCount = DriverCount;
774 
775  //
776  // First fill in the values that are kept up to date at runtime
777  //
779 
780  //
781  // Set additional information bits from information retrieved
782  // from other sources. It's cheaper to get this info at the infrequent
783  // GetStatus time, rather than keep the bits up to date at each
784  // request and queue transition.
785  //
786  if (QueueCount == 0) {
788  }
789 
790  if (DriverCount == 0) {
792  }
793 
794  if(m_PowerManaged) {
795 
798  }
799  }
800 
801  return (WDF_IO_QUEUE_STATE)stat;
802 }
803 
804 VOID
806  __in FX_IO_QUEUE_SET_STATE NewStatus
807  )
808 {
809  int AllowedBits;
810 
811  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
812 
813  //
814  // Only allow setting of valid bits
815  //
816  AllowedBits = (int)(FxIoQueueSetAcceptRequests |
822  );
823 
824  if ((int)NewStatus & ~AllowedBits) {
826  "Invalid WDFQUEUE 0x%p state",
827  GetObjectHandle());
828  FxVerifierDbgBreakPoint(FxDriverGlobals);
829  return;
830  }
831 
832  //
833  // Clear the high bit used to prevent accidental mixing of
834  // WDF_IO_QUEUE_STATE and FX_IO_QUEUE_SET_STATE
835  //
836  NewStatus = (FX_IO_QUEUE_SET_STATE)((int)NewStatus & 0x7FFFFFFF);
837 
838  if (NewStatus & (int)FxIoQueueClearShutdown) {
840  }
841 
842  if (NewStatus & (int)FxIoQueueSetShutdown) {
844  }
845 
846  if (NewStatus & (int)FxIoQueueSetAcceptRequests) {
847  if (IsState(FxIoQueueShutdown) == FALSE) {
849  }
850  else {
851  DoTraceLevelMessage(FxDriverGlobals,
853  "WDFQUEUE 0x%p is shut down, preventing queue "
854  "from accepting requests",
855  GetObjectHandle());
856  }
857  }
858 
859  if (NewStatus & (int)FxIoQueueClearAcceptRequests) {
861  }
862 
863  if (NewStatus & (int)FxIoQueueSetDispatchRequests) {
865  //
866  // If the queue is allowed to dispatch new requests, we must clear this flag.
867  // See also WdfIoQueueStopAndPurge for more info about the flag.
868  //
870  }
871 
872  if (NewStatus & (int)FxIoQueueClearDispatchRequests) {
874  }
875 
876  return;
877 }
878 
880 NTSTATUS
881 FX_VF_METHOD(FxIoQueue, VerifyGetRequestUpdateFlags) (
882  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
884  )
885 {
886  KIRQL irql;
888 
890 
891  if (TagRequest != NULL) {
892  //
893  // WdfIoQueueRetrieveFoundRequest is only valid on manual queues.
894  // v1.11 and above: driver is not required to find the request
895  // using WdfIoQueueFindRequest.
896  // v1.9 and below: driver is required to find the request
897  // using WdfIoQueueFindRequest.
898  //
899  if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
900  if (m_Type != WdfIoQueueDispatchManual) {
903  FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
904  "WdfIoQueueRetrieveFoundRequest is allowed "
905  "only on a manual queue 0x%p, %!STATUS!",
906  GetHandle(), status);
907  FxVerifierDbgBreakPoint(FxDriverGlobals);
908  return status;
909  }
910  }
911  else {
912  //
913  // Legacy validation.
914  //
915  TagRequest->Lock(&irql);
916  status = TagRequest->VerifyRequestIsTagRequest(FxDriverGlobals);
917  TagRequest->Unlock(irql);
918  if (!NT_SUCCESS(status)) {
919  return status;
920  }
921  }
922  }
923 
925  if ((m_Type == WdfIoQueueDispatchSequential) && (m_DriverIoCount == 0)) {
926 
928  "Driver called WdfIoQueueRetrieveNextRequest on a sequential WDFQUEUE 0x%p with no "
929  "outstanding requests. This can cause a race with automatically dispatched "
930  "requests. Call WdfIoQueueRetrieveNextRequest before completing the current request(s)",
931  GetObjectHandle());
932 
933  FxVerifierDbgBreakPoint(FxDriverGlobals);
934 
935  // Allow them to continue, though this is a race condition in their driver
936  }
937  Unlock(irql);
938 
940 }
941 
942 VOID
943 FX_VF_METHOD(FxIoQueue, VerifyGetRequestRestoreFlags)(
944  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
946  )
947 {
948  UNREFERENCED_PARAMETER(FxDriverGlobals);
949  KIRQL irql;
950 
952  pRequest->Lock(&irql);
953 
954  pRequest->ClearVerifierFlagsLocked(FXREQUEST_FLAG_TAG_REQUEST);
955  pRequest->SetVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED);
956 
957  pRequest->Unlock(irql);
958 }
959 
961 NTSTATUS
965  __deref_out FxRequest** pOutRequest
966  )
967 /*++
968 
969 Routine Description:
970 
971  This method is called by
972 
973  WdfIoQueueRetrieveNextRequest
974  WdfIoQueueRetrieveRequestByFileObject
975  WdfIoQueueRetrieveFoundRequest
976 
977  to retrieve a request from the queue.
978 
979 Arguments:
980 
981 Returns:
982 
983  NTSTATUS
984 
985 --*/
986 {
989  FxRequestCompletionState oldState;
991  KIRQL irql;
992 
993  status = VerifyGetRequestUpdateFlags(pFxDriverGlobals, TagRequest);
994  if(!NT_SUCCESS(status)){
995  return status;
996  }
997 
998  //
999  // Don't allow on parallel queues
1000  //
1001  if ((m_Type != WdfIoQueueDispatchManual) &&
1005  "Cannot be called on a parallel WDFQUEUE 0x%p, %!STATUS!",
1006  GetObjectHandle(), status);
1007  return status;
1008  }
1009 
1010  Lock(&irql);
1011 
1012  //
1013  // Only if the queue state allows requests to be retrieved.
1014  // It's okay to retrieve requests while the queue is in a transitioning state.
1015  //
1019  "WDFQUEUE 0x%p is powered off, %!STATUS!",
1020  GetObjectHandle(), status);
1021  Unlock(irql);
1022  return status;
1023  }
1024 
1025  //
1026  // See if the queue is (still) processing requests
1027  //
1031  "WDFQUEUE 0x%p is stopped, %!STATUS!",
1032  GetObjectHandle(), status);
1033  Unlock(irql);
1034  return status;
1035  }
1036 
1037  #pragma warning(disable:4127)
1038  while (TRUE) {
1039 
1040  #pragma warning(default:4127)
1041  //
1042  // Get the next FxRequest from the cancel safe queue
1043  //
1045  if (!NT_SUCCESS(status)) {
1046  //
1047  // This code address the following race condition:
1048  // 1) Queue has only one request (count 1).
1049  // 2) Request in queue is cancelled.
1050  // 3) Request's cancellation logic starts to run on thread 1.
1051  // 4) But before cancellation logic gets the queue's lock
1052  // thread 2 calls WdfIoQueueRetrieveNextRequest.
1053  // 5) WdfIoQueueRetrieveNextRequest returns no more requests.
1054  // Driver waits for the ReadyNotify callback. (count 1)
1055  // 6) Thread 3 adds a new request in queue. (count 1->2)
1056  // 7) Thread 1 finally runs. (count 2->1).
1057  // 8) At this point driver stops responding b/c it never receives ReadyNotify.
1058  //
1059  // This code below forces the queue logic to send a ReadyNotify
1060  // callback the next time a new request is added (in step 6 above).
1061  //
1062  if (STATUS_NO_MORE_ENTRIES == status &&
1063  NULL == FileObject && // WdfIoQueueRetrieveNextRequest
1064  NULL == TagRequest && // WdfIoQueueRetrieveNextRequest
1065  m_Queue.GetRequestCount() > 0L) {
1066 
1068  }
1069 
1070  Unlock(irql);
1071  return status;
1072  }
1073 
1074  //
1075  // If we don't allow zero length read/write's to the driver,
1076  // complete it now with success and attempt to get another
1077  // request from the queue.
1078  //
1080 
1081 
1082 
1083 
1084 
1085  (VOID)pRequest->GetCurrentIrpStackLocation();
1086 
1087  FxIrp* pIrp = pRequest->GetFxIrp();
1089 
1090  if ((majorFunction == IRP_MJ_READ) &&
1091  (pIrp->GetParameterReadLength() == 0)) {
1092 
1093  Unlock(irql);
1095  "Zero length WDFREQUEST 0x%p completed automatically by WDFQUEUE 0x%p",
1096  pRequest->GetHandle(),GetObjectHandle());
1097  pRequest->CompleteWithInformation(STATUS_SUCCESS, 0);
1098  pRequest->RELEASE(FXREQUEST_COMPLETE_TAG);
1099 
1100  Lock(&irql);
1101 
1102  // Get another request from the queue
1103  continue;
1104  }
1105  else if ((majorFunction == IRP_MJ_WRITE) &&
1106  (pIrp->GetParameterWriteLength() == 0)) {
1107 
1108  Unlock(irql);
1110  "Zero length WDFREQUEST 0x%p completed automatically by WDFQUEUE 0x%p",
1111  pRequest->GetHandle(), GetObjectHandle());
1112 
1113  pRequest->CompleteWithInformation(STATUS_SUCCESS, 0);
1114  pRequest->RELEASE(FXREQUEST_COMPLETE_TAG);
1115 
1116  Lock(&irql);
1117 
1118  // Get another request from the queue
1119  continue;
1120  }
1121  }
1122 
1123  break;
1124  }
1125 
1126  // Increase the driver owned request count
1128 
1129  Unlock(irql);
1130 
1131  //
1132  // We don't need to check for PurgeComplete since
1133  // we are giving the request to the driver
1134  //
1135 
1136  // pRequest is not cancellable now
1137 
1138  //
1139  // We are now going to return the request
1140  // to the driver, and it must complete it.
1141  //
1142 
1143  //
1144  // Set a completion event, this takes a reference
1145  //
1146  oldState = pRequest->SetCompletionState(FxRequestCompletionStateQueue);
1147  ASSERT(oldState == FxRequestCompletionStateNone);
1148  UNREFERENCED_PARAMETER(oldState);
1149 
1150  //
1151  // Track that we have given the request to the driver
1152  //
1153  VerifyGetRequestRestoreFlags(pFxDriverGlobals, pRequest);
1154 
1155  pRequest->SetPresented();
1156 
1157  //
1158  // Release our original reference. The FxRequest::Complete
1159  // will release the final one since we have registered a completion
1160  // callback handler
1161  //
1162  // We now have one reference count on the FxRequest object until
1163  // its completion routine runs since the completion event made
1164  // an extra reference, and will dereference it when it fires, or
1165  // its canceled.
1166  //
1167 
1168  pRequest->RELEASE(FXREQUEST_STATE_TAG);
1169 
1170  // Return it to the driver
1171  *pOutRequest = pRequest;
1172 
1173  return STATUS_SUCCESS;
1174 }
1175 
1177 NTSTATUS
1178 FX_VF_METHOD(FxIoQueue, VerifyPeekRequest) (
1179  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1181  )
1182 {
1183  NTSTATUS status;
1184  KIRQL irql;
1185 
1187 
1188  TagRequest->Lock(&irql);
1189  status = TagRequest->VerifyRequestIsTagRequest(FxDriverGlobals);
1190  TagRequest->Unlock(irql);
1191 
1192  return status;
1193 }
1194 
1196 NTSTATUS
1201  __deref_out FxRequest** pOutRequest
1202  )
1203 /*++
1204 
1205 Routine Description:
1206 
1207  This method is called by WdfIoQueueFindRequest to
1208  look for a specific request from the queue. If tagrequest
1209  is not specified then this method will return the very
1210  first request from the queue.
1211 
1212  If the fileobject is specified then fileobject is also
1213  used as one of the constrain for returing the request.
1214 
1215  Important point to remember is that only request information
1216  is returned to the caller. The request is still present in
1217  the queue.
1218 
1219  If the request is returned, there is an additional reference
1220  taken on the queue to prevent it from deletion while the
1221  caller is using the request handle. The caller has to
1222  explicitly drop the reference once he is done using the
1223  request handle.
1224 
1225 Arguments:
1226 
1227 Returns:
1228 
1229  NTSTATUS
1230 
1231 --*/
1232 
1233 {
1234  NTSTATUS status;
1235  FxRequest* pRequest = NULL;
1237  KIRQL irql;
1238 
1239  //
1240  // FindRequest is allowed only on a manual queue.
1241  //
1245  "FindRequest is allowed only on a manaul queue 0x%p, %!STATUS!",
1246  GetHandle(), status);
1248  return status;
1249  }
1250 
1251  if (TagRequest != NULL) {
1252  status = VerifyPeekRequest(pFxDriverGlobals, TagRequest);
1253  if (!NT_SUCCESS(status)) {
1254  return status;
1255  }
1256  }
1257 
1258  //
1259  // Get the next FxRequest from the cancel safe queue
1260  //
1261  // If success, it will return a referenced FxRequest in
1262  // which the caller must release the reference.
1263  //
1264  Lock(&irql);
1265 
1267  &m_Queue,
1268  TagRequest,
1269  FileObject,
1270  Parameters,
1271  &pRequest
1272  );
1273 
1274  //
1275  // This code address the following potential race condition:
1276  // 1) Queue has only one request (count 1).
1277  // 2) Request in queue is cancelled.
1278  // 3) Request's cancellation logic starts to run on thread 1.
1279  // 4) But before cancellation logic gets the queue's lock
1280  // thread 2 calls WdfIoQueueFindRequest to find any request.
1281  // 5) WdfIoQueueFindRequest returns no more requests.
1282  // Driver waits for the ReadyNotify callback. (count 1)
1283  // 6) Thread 3 adds a new request in queue. (count 1->2)
1284  // 7) Thread 1 finally runs. (count 2->1).
1285  // 8) At this point driver stops responding b/c it never receives ReadyNotify.
1286  //
1287  // This code below forces the queue logic to send a ReadyNotify
1288  // callback the next time a new request is added (in step 6 above).
1289  //
1290  if (STATUS_NO_MORE_ENTRIES == status &&
1291  NULL == FileObject && // WdfIoQueueFindRequest(any request)
1292  NULL == TagRequest && // WdfIoQueueFindRequest(any request)
1293  m_Queue.GetRequestCount() > 0L) {
1294 
1296  }
1297 
1298  Unlock(irql);
1299 
1300  if (!NT_SUCCESS(status)) {
1301  return status;
1302  }
1303 
1304  //
1305  // Mark it as a tag request to detect abuse since its not
1306  // driver owned.
1307  //
1309  pRequest->SetVerifierFlags(FXREQUEST_FLAG_TAG_REQUEST);
1310  }
1311 
1312  // Return it to the driver
1313  *pOutRequest = pRequest;
1314 
1315  return status;
1316 }
1317 
1318 SHORT
1319 FX_VF_METHOD(FxIoQueue, VerifyForwardRequestUpdateFlags) (
1320  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1322  )
1324  UNREFERENCED_PARAMETER(FxDriverGlobals);
1326  KIRQL irql;
1327 
1329 
1330  Request->Lock(&irql);
1331 
1332  // Save old flags to put them back if forward fails
1333  OldFlags = Request->GetVerifierFlagsLocked();
1334 
1335  //
1336  // Set that the request was forwarded. This effects
1337  // cancel behavior.
1338  //
1339  Request->SetVerifierFlagsLocked(FXREQUEST_FLAG_FORWARDED);
1340 
1341  ASSERT((Request->GetVerifierFlagsLocked() & FXREQUEST_FLAG_DRIVER_OWNED) != 0);
1342 
1343  // Set that the request is no longer driver owned
1344  Request->ClearVerifierFlagsLocked(
1346 
1347  Request->Unlock(irql);
1348 
1349  return OldFlags;
1350 }
1351 
1353 NTSTATUS
1357  )
1358 {
1359  NTSTATUS status;
1360  FxRequestCompletionState oldState;
1361  PLIST_ENTRY ple;
1362  SHORT OldFlags;
1363  KIRQL irql;
1364 
1365  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
1366 
1367  OldFlags = 0;
1368 
1369  //
1370  // The request has only one reference, held by the completion
1371  // callback function. We need to take another one before cancelling
1372  // this function, otherwise we will lose the request object
1373  //
1374  Request->ADDREF(FXREQUEST_STATE_TAG);
1375 
1376  //
1377  // Cancel its current completion event for this queue
1378  //
1379  oldState = Request->SetCompletionState(FxRequestCompletionStateNone);
1381 
1382  OldFlags = VerifyForwardRequestUpdateFlags(FxDriverGlobals, Request);
1383 
1384  //
1385  // Remove it from this queues driver owned list.
1386  //
1387  // This must be done before forward since new queue will
1388  // use the list entry in the FxRequest
1389  //
1390  // We can't use RemoveFromDriverOwnedList since we want the
1391  // m_DriverIoCount to be left alone in case the forward fails.
1392  // If we don't, another thread can run when we drop the lock, notice
1393  // that there are no more requests, and raise the purged and empty
1394  // events. But if the forward fails, the request will wind up back
1395  // on the queue! So m_DriverIoCount is used as a gate to prevent
1396  // these events from firing until we are really sure this queue
1397  // is done with the request.
1398  //
1399 
1400 
1401 
1402 
1403 
1404 
1405 
1406 
1407 
1408 
1409 
1410  Lock(&irql);
1411  ple = Request->GetListEntry(FxListEntryDriverOwned);
1414  Unlock(irql);
1415 
1416  //
1417  // Attempt to pass the request onto the target queue
1418  //
1420  if (!NT_SUCCESS(status)) {
1421 
1422  //
1423  // Target queue did not accept the request, so we
1424  // restore the original completion callback function
1425  // and flags
1426  //
1427  oldState = Request->SetCompletionState(oldState);
1428  ASSERT(oldState == FxRequestCompletionStateNone);
1429  UNREFERENCED_PARAMETER(oldState);
1430 
1431  if (FxDriverGlobals->FxVerifierOn) {
1432  Request->SetVerifierFlags(OldFlags);
1433  }
1434 
1435  // Release the extra reference we took
1436  Request->RELEASE(FXREQUEST_STATE_TAG);
1437 
1438  Lock(&irql);
1439  // Place it back on the driver owned list
1441  Unlock(irql);
1442  }
1443  else {
1444 
1445  Lock(&irql);
1446 
1447  // Request is no longer part of the I/O count for this queue
1448  m_DriverIoCount--;
1449 
1450  ASSERT(m_DriverIoCount >= 0);
1451 
1452  //
1453  // Don't run the event dispatcher if we are called from a
1454  // dispath routine in order to prevent stack recursion.
1455  // Since some other thread (possibly this thread higher on
1456  // the stack) is running the dispatcher, no events will get lost.
1457  //
1458  //
1459  // This returns with the IoQueue lock released
1460  //
1461  DispatchInternalEvents(irql);
1462 
1463  //
1464  // We don't dereference the request object since the new IoQueue
1465  // will release it when it is done.
1466  //
1467  }
1468 
1469  return status;
1470 }
1471 
1473 NTSTATUS
1474 FX_VF_METHOD(FxIoQueue, VerifyForwardRequestToParent) (
1475  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1478  )
1479 {
1480  KIRQL irql;
1481  NTSTATUS status;
1482 
1484 
1485  if (m_Device->m_ParentDevice == NULL) {
1488  "No parent device for WDFQUEUE 0x%p Device, %!STATUS!",
1490  FxVerifierDbgBreakPoint(FxDriverGlobals);
1491  goto Done;
1492  }
1493 
1494  Request->Lock(&irql);
1495 
1496  status = Request->VerifyRequestIsDriverOwned(FxDriverGlobals);
1497 
1499  status = Request->VerifyRequestIsNotCancelable(FxDriverGlobals);
1500  }
1501 
1502  Request->Unlock(irql);
1503 
1505  goto Done;
1506  }
1507 
1508  if (DestQueue == this) {
1511  "Cannot forward a request to the same WDFQUEUE 0x%p"
1512  " %!STATUS!", GetObjectHandle(), status);
1513  FxVerifierDbgBreakPoint(FxDriverGlobals);
1514  goto Done;
1515  }
1516 
1517  if (m_Device->m_ParentDevice != DestQueue->m_Device) {
1520  "Cannot forward a request to "
1521  "a different WDFDEVICE 0x%p which is not the "
1522  "parent, %!STATUS!",
1524  status);
1525  FxVerifierDbgBreakPoint(FxDriverGlobals);
1526  goto Done;
1527  }
1528 
1529  if (Request->IsReserved()) {
1532  "Cannot forward reserved WDFREQUEST 0x%p to a "
1533  "parent WDFDEVICE 0x%p, %!STATUS!",
1534  Request->GetHandle(),
1536  status);
1537  FxVerifierDbgBreakPoint(FxDriverGlobals);
1538  goto Done;
1539  }
1540 
1541  //
1542  // Make sure the child device is a PDO
1543  //
1544  ASSERT(m_Device->IsPdo());
1545 
1546  //
1547  // Check if the WdfPdoInitSetForwardRequestToParent was called to increase
1548  // the StackSize of the child Device to include the stack size of the
1549  // parent Device
1550  //
1551  if (m_Device->IsPnp()
1552  &&
1553  m_Device->GetPdoPkg()->m_AllowForwardRequestToParent == FALSE) {
1556  "WdfPdoInitSetForwardRequestToParent not called on "
1557  "WDFDEVICE 0x%p, %!STATUS!", m_Device->GetHandle(),
1558  status);
1559  FxVerifierDbgBreakPoint(FxDriverGlobals);
1560  goto Done;
1561  }
1562 
1563 Done:
1564  return status;
1565 }
1566 
1568 NTSTATUS
1573  )
1574 
1575 /*++
1576 
1577 Routine Description:
1578 
1579  ForwardRequest is called from the drivers EvtIoDefault routine
1580  and the following conditions apply:
1581 
1582  Request is not on a CSQ and not cancellable
1583 
1584  Request is FXREQUEST_FLAG_DRIVER_OWNED
1585 
1586  m_DriverIoCount has been incremented to reflect the request
1587 
1588  Request has an I/O completion callback function pointing to
1589  FxIoQueueRequestComplete with the context for this Queue
1590 
1591  The Request has one reference count from the I/O completion callback.
1592 
1593  If a driver calls this API, it will not complete the request
1594  as a result of this queues EvtIoDefault, and does not own
1595  the request until it has been re-presented by the Destination
1596  Queue.
1597 
1598 Arguments:
1599 
1600 Returns:
1601 
1602  NTSTATUS
1603 
1604 --*/
1605 {
1606  NTSTATUS status;
1608  BOOLEAN forwardRequestToParent;
1609  FxIrp* pIrp;
1610 
1612 
1614 
1615  forwardRequestToParent = Request->m_ForwardRequestToParent;
1616 
1617  status = VerifyForwardRequestToParent(pFxDriverGlobals,
1618  DestQueue,
1619  Request);
1620  if(!NT_SUCCESS(status)){
1621  return status;
1622  }
1623 
1624  pIrp = Request->GetFxIrp();
1625 
1628 
1629  //
1630  // Save a pointer to the device object for this request so that it can
1631  // be used later in completion.
1632  //
1634 
1635  Request->SetDeviceBase((CfxDeviceBase *)m_Device->m_ParentDevice);
1636  Request->m_ForwardRequestToParent = TRUE;
1637 
1639 
1640  //
1641  // Undo the actions of changing the FxDevice and
1642  // changing the deviceObject and stack location in the IRP
1643  //
1644  if (!NT_SUCCESS(status)) {
1645  Request->SetDeviceBase((CfxDeviceBase *)m_Device);
1646  pIrp = Request->GetFxIrp();
1649 
1650  //
1651  // Set the value of m_ForwardRequestToParent to the previous
1652  // value so that if the Request has been forwarded to Parent
1653  // successfully but fails to be forwarded to the grandparent
1654  // from the parent then we free it back using ExFreePool
1655  // instead of the Lookaside buffer .
1656  //
1657  Request->m_ForwardRequestToParent = forwardRequestToParent;
1658  }
1659 
1660  return status;
1661 }
1662 
1664 NTSTATUS
1665 FX_VF_METHOD(FxIoQueue, VerifyForwardRequest) (
1666  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1669  )
1670 {
1671  NTSTATUS status;
1672  KIRQL irql;
1673 
1675 
1676  pRequest->Lock(&irql);
1677 
1678  status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals);
1679  if (NT_SUCCESS(status)) {
1680  status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals);
1681  }
1682 
1683  pRequest->Unlock(irql);
1684 
1685  if (!NT_SUCCESS(status)) {
1686  return status;
1687  }
1688 
1689  if (pDestQueue == this) {
1691  "Cannot forward a request to the same WDFQUEUE 0x%p"
1692  " %!STATUS!",
1693  GetObjectHandle(),
1695  FxVerifierDbgBreakPoint(FxDriverGlobals);
1697  }
1698 
1699  if ((m_Device != pDestQueue->m_Device)) {
1701  "Cannot forward a request to a different WDFDEVICE 0x%p",
1703  FxVerifierDbgBreakPoint(FxDriverGlobals);
1705  }
1706 
1707  return status;
1708 }
1709 
1711 NTSTATUS
1715  )
1716 /*++
1717 
1718 Routine Description:
1719 
1720  ForwardRequest is called from the drivers EvtIoDefault routine
1721  and the following conditions apply:
1722 
1723  Request is not on a CSQ and not cancellable
1724 
1725  Request is FXREQUEST_FLAG_DRIVER_OWNED
1726 
1727  m_DriverIoCount has been incremented to reflect the request
1728 
1729  Request has an I/O completion callback function pointing to
1730  FxIoQueueRequestComplete with the context for this Queue
1731 
1732  The Request has one reference count from the I/O completion callback.
1733 
1734  If a driver calls this API, it will not complete the request
1735  as a result of this queues EvtIoDefault, and does not own
1736  the request until it has been re-presented by the Destination
1737  Queue.
1738 
1739 Arguments:
1740 
1741 Returns:
1742 
1743  NTSTATUS
1744 
1745 --*/
1746 {
1747  NTSTATUS status;
1748 
1749  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
1750 
1751  status = VerifyForwardRequest(FxDriverGlobals, pDestQueue, pRequest);
1752  if (!NT_SUCCESS(status)) {
1753  return status;
1754  }
1755 
1757  return status;
1758 }
1759 
1761 NTSTATUS
1762 FX_VF_METHOD(FxIoQueue, VerifyQueueDriverCreatedRequest) (
1763  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1766  )
1767 {
1768  NTSTATUS status;
1769  KIRQL irql;
1770 
1772 
1773  Request->Lock(&irql);
1774 
1775  *OldFlags = Request->GetVerifierFlagsLocked();
1777 
1778  status = Request->VerifyRequestIsNotCancelable(FxDriverGlobals);
1779  if (NT_SUCCESS(status)) {
1780  // Clear the driver owned flag.
1782  Request->ClearVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED);
1783  }
1784 
1785  Request->Unlock(irql);
1786  return status;
1787 }
1788 
1790 NTSTATUS
1793  __in BOOLEAN ParentQueue
1794  )
1795 /*++
1796 
1797 Routine Description:
1798 
1799  Insert a driver-created-request into this queue.
1800  The following conditions apply:
1801 
1802  Request is not on a CSQ and not cancellable.
1803 
1804  Request doesn't have the FXREQUEST_FLAG_DRIVER_OWNED set yet.
1805 
1806  Request doesn't have an I/O completion callback function pointing to
1807  FxIoQueueRequestComplete since the original queue is NULL.
1808 
1809  The Request has one reference count from WdfRequestCreate[FromIrp].
1810 
1811  On a successful return, the request is owned by the queue. Driver can complete
1812  this request only after it has been re-presented to the driver.
1813 
1814 Arguments:
1815 
1816  Request - Driver created request (already validated by public API) to
1817  insert in queue.
1818 
1819  ParentQueue - TRUE if the queue is owned by the parent device.
1820 
1821 Returns:
1822 
1823  NTSTATUS
1824 
1825 --*/
1826 {
1827  NTSTATUS status;
1828  CfxDeviceBase * origDeviceBase;
1829  SHORT oldFlags = 0;
1830  FxIrp* fxIrp;
1831 
1833  fxIrp = Request->GetFxIrp();
1834 
1835  status = VerifyQueueDriverCreatedRequest(fxDriverGlobals, Request, &oldFlags);
1836  if(!NT_SUCCESS(status)) {
1837  return status;
1838  }
1839 
1840  ASSERT(Request->SetCompletionState(FxRequestCompletionStateNone) ==
1842 
1843  //
1844  // If this is the parent queue, we need to adjust the IRP's stack.
1845  //
1846  if (ParentQueue) {
1847 
1848  //
1849  // IRP should not have a completion routine set yet.
1850  //
1851 
1853 
1856 
1857  //
1858  // Save a pointer to the device object for this request so that it can
1859  // be used later in completion.
1860  //
1862  }
1863 
1864  origDeviceBase = Request->GetDeviceBase();
1866 
1867  //
1868  // Attempt to insert the request into the queue
1869  //
1871  if (!NT_SUCCESS(status)) {
1872  //
1873  // Request was not accepted, restore the original DeviceBase and flags.
1874  //
1875  ASSERT(Request->SetCompletionState(FxRequestCompletionStateNone) ==
1877 
1878  //
1879  // Restore original device/info.
1880  //
1881  Request->SetDeviceBase(origDeviceBase);
1882 
1884  Request->SetVerifierFlags(oldFlags);
1885  }
1886 
1887  //
1888  // If this is the parent queue, we need to adjust the IRP's stack.
1889  //
1890  if (ParentQueue) {
1892  //
1893  // There is no completion routine. See above assert.
1894  //
1895  Request->m_Irp.ClearNextStack();
1896  }
1897  }
1898 
1899  return status;
1900 }
1901 
1903 NTSTATUS
1904 FX_VF_METHOD(FxIoQueue, VerifyRequeue) (
1905  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1907  )
1908 {
1910  KIRQL irql;
1911 
1913 
1914  pRequest->Lock(&irql);
1915 
1916  status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals);
1917  if (NT_SUCCESS(status)) {
1918  status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals);
1919  }
1920 
1921  if (NT_SUCCESS(status)) {
1922  pRequest->ClearVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED |
1924  }
1925  pRequest->Unlock(irql);
1926 
1927  return status;
1928 }
1929 
1930 
1932 NTSTATUS
1935  )
1936 {
1937  NTSTATUS status;
1938  FxRequestCompletionState oldState;
1939  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
1940  KIRQL irql;
1941 
1942  status = VerifyRequeue(FxDriverGlobals, pRequest);
1943  if (!NT_SUCCESS(status)) {
1944  return status;
1945  }
1946 
1947  //
1948  // Requeue is allowed only on Manual queue.
1949  //
1950  if(pRequest->GetCurrentQueue()->m_Type != WdfIoQueueDispatchManual) {
1951 
1953  "Requeue is allowed only for "
1954  "a manual queue, WDFREQUEST 0x%p "
1955  "%!STATUS!",
1956  pRequest,
1958  FxVerifierDbgBreakPoint(FxDriverGlobals);
1960  }
1961 
1962  //
1963  // The request has only one reference, held by the completion
1964  // callback function. We need to take another one before cancelling
1965  // this function, otherwise we will lose the request object
1966  //
1967  pRequest->ADDREF(FXREQUEST_STATE_TAG);
1968 
1969  // Cancel the request complete callback (deletes a reference)
1970  oldState = pRequest->SetCompletionState(FxRequestCompletionStateNone);
1972  UNREFERENCED_PARAMETER(oldState);
1973 
1974  Lock(&irql);
1975 
1976  //
1977  // We are going to place the request back on the queue
1978  //
1979 
1980 
1981  // Driver did not accept the I/O
1983 
1985  "WDFREQUEST 0x%p", pRequest->GetHandle());
1986 
1987  //
1988  // Check if we need to delete this request.
1989  //
1991  //
1992  // Do not requeue this request.
1993  //
1995  }
1996  else {
1997  //
1998  // Place the request back at the head of the main queue
1999  // so as not to re-order requests
2000  //
2001  status = pRequest->InsertHeadIrpQueue(&m_Queue, NULL);
2002  }
2003 
2004  if (!NT_SUCCESS(status)) {
2005 
2006  // Request did not get placed in queue
2008  //
2009  // Let the caller think the request is requeued successfully
2010  // because this is no different from the request cancelling
2011  // while it's in the queue. By returning STATUS_CANCELLED
2012  // the caller can't take any recovery action anyways
2013  // because the request is gone.
2014  //
2016 
2017  //
2018  // We must add a reference since the CancelForQueue path
2019  // assumes we were on the FxIrpQueue with the extra reference
2020  //
2021  pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
2022 
2023  //
2024  // Mark the request as cancelled, place it on the cancel list,
2025  // and schedule the cancel event to the driver
2026  //
2027  CancelForQueue(pRequest, irql);
2028 
2029  Lock(&irql);
2030  }
2031  else {
2032  // Check if went from no requests to have requests
2034  }
2035 
2036  //
2037  // Visit the DispatchEvent so that we can deliver EvtIoReadyNotify
2038  //
2039  DispatchEvents(irql);
2040 
2041  return status;
2042 }
2043 
2045 NTSTATUS
2046 FX_VF_METHOD(FxIoQueue, VerifyRequestCancelable) (
2047  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
2050  )
2052  NTSTATUS status;
2053  KIRQL irql;
2054 
2056 
2057  pRequest->Lock(&irql);
2058 
2059  // Make sure the driver owns the request
2060  status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals);
2061  if (!NT_SUCCESS(status)) {
2062  goto Done;
2063  }
2064 
2065  if (Cancelable) {
2066  //
2067  // Make sure the request is not cancelable for it to be made
2068  // cancelable.
2069  //
2070  status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals);
2071  if (!NT_SUCCESS(status)) {
2072  goto Done;
2073  }
2074  }
2075  else {
2076  //
2077  // Make sure the request is cancelable for it to be made
2078  // uncancelable.
2079  //
2080  status = pRequest->VerifyRequestIsCancelable(FxDriverGlobals);
2081  if (!NT_SUCCESS(status)) {
2082  goto Done;
2083  }
2084  }
2085 
2086 Done:
2087  pRequest->Unlock(irql);
2088  return status;
2089 }
2090 
2092 NTSTATUS
2097  __in BOOLEAN FailIfIrpIsCancelled
2098  )
2099 /*++
2100 
2101  Routine Description:
2102 
2103  This is called to mark or unmark the request cancelable.
2104 
2105  Arguments:
2106 
2107  FxRequest* - Request that is completing
2108 
2109  Cancelable - if TRUE, mark the request cancellable
2110  if FALSE, mark the request not cancelable
2111  if it's previously marked canceelable.
2112 
2113  EvtRequestCancel - points to driver provided cancel routine
2114  if the cancelable flag is TRUE.
2115 
2116  FailIfIrpIsCancelled - if FALSE and the IRP is already cancelled,
2117  call the provided cancel routine and
2118  return success.
2119  if TRUE and the IRP is already cancelled,
2120  return STATUS_CANCELLED.
2121 
2122  Returns:
2123 
2124  NTSTATUS
2125 
2126 --*/
2127 {
2128  NTSTATUS status;
2129  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
2130  KIRQL irql;
2131 
2132  status = VerifyRequestCancelable(FxDriverGlobals, pRequest, Cancelable);
2133  if(!NT_SUCCESS(status)) {
2134  return status;
2135  }
2136 
2137  if (Cancelable) {
2138 
2139  if (FxDriverGlobals->FxVerifierOn) {
2140  pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE);
2141  }
2142  //
2143  // Set the Request for cancel status by inserting in the driver owned
2144  // CSQ. Note: This could fire the cancel callback right away
2145  // if the IRP was already cancelled.
2146  //
2147 
2149 
2150  Lock(&irql);
2151 
2152  pRequest->m_CancelRoutine.m_Cancel = EvtRequestCancel;
2153 
2154  //
2155  // Check if we need to delete this request.
2156  //
2158  //
2159  // Purge is in progress, cancel this request.
2160  //
2162  }
2163  else {
2164  status = pRequest->InsertTailIrpQueue(&m_DriverCancelable, NULL);
2165  }
2166 
2167  if (NT_SUCCESS(status)) {
2168  Unlock(irql);
2169  }
2170  else if (FailIfIrpIsCancelled == FALSE) {
2171 
2173 
2174  // This is not an error to the driver
2176 
2177  pRequest->m_Canceled = TRUE;
2178 
2179  Unlock(irql);
2180 
2181  //
2182  // We must add a reference since the CancelForDriver path
2183  // assumes we were on the FxIrpQueue with the extra reference
2184  //
2185  pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
2186 
2187  //
2188  // Mark the request as cancelled, place it on the cancel list,
2189  // and schedule the cancel event to the driver
2190  //
2192  }
2193  else {
2194 
2196 
2197  pRequest->m_CancelRoutine.m_Cancel = NULL;
2198 
2199  //
2200  // Let the caller complete the request with STATUS_CANCELLED.
2201  //
2202  Unlock(irql);
2203 
2204  if (FxDriverGlobals->FxVerifierOn) {
2205  pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE);
2206  }
2207  }
2208 
2209  return status;
2210  }
2211  else {
2212  //
2213  // This can return STATUS_CANCELLED if the request
2214  // has been canceled already
2215  //
2216  Lock(&irql);
2217  status = pRequest->RemoveFromIrpQueue(&m_DriverCancelable);
2218 
2219  if (NT_SUCCESS(status)) {
2220  pRequest->m_CancelRoutine.m_Cancel = NULL;
2221  }
2222  else {
2223  //
2224  // In the failure case, the cancel routine has won the race and will
2225  // be invoked on another thread.
2226  //
2227  DO_NOTHING();
2228  }
2229  Unlock(irql);
2230 
2231  if (FxDriverGlobals->FxVerifierOn) {
2232 
2233  // We got the request back, can clear the cancelable flag
2234  if (NT_SUCCESS(status)) {
2235  pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE);
2236  }
2237  }
2238 
2239  return status;
2240  }
2241 }
2242 
2244 NTSTATUS
2247  )
2248 
2249 /*++
2250 
2251  Routine Description:
2252 
2253  Enqueue a request to the end of the queue.
2254 
2255  Note: This routine owns the final disposition of
2256  the Request object, and must handle it and
2257  dereference even if the driver does not.
2258 
2259  Arguments:
2260 
2261  pRequest - Pointer to Request object
2262 
2263  Returns:
2264 
2265  NTSTATUS
2266 --*/
2267 
2268 {
2269  NTSTATUS Status;
2270  KIRQL irql;
2271  MdIrp pIrp;
2272  FxIrp* pFxIrp;
2273 
2274  // Get IoQueue Object Lock
2275  Lock(&irql);
2276 
2277  ASSERT(pRequest->GetRefCnt() == 1);
2278 
2279  //
2280  // If the request is reserved, take an additional reference. This reference
2281  // will be released when the request is completed. This additional reference
2282  // enables us to detect 2 to 1 transition in the completion path so that
2283  // we can reclaim the reserved request for reuse.
2284  //
2285  if (pRequest->IsReserved()) {
2286  pRequest->ADDREF(FXREQUEST_FWDPRG_TAG);
2287  }
2288 
2289  //
2290  // If queue is not taking new requests, fail now
2291  //
2293 
2295  "WDFQUEUE 0x%p is not accepting requests, "
2296  "state is %!WDF_IO_QUEUE_STATE!, %s"
2297  "completing WDFREQUEST 0x%p %!STATUS!",
2300  "power stopping (Drain) in progress," : "",
2301  pRequest->GetHandle(),
2303 
2304  // Must release IoQueue object Lock
2305  Unlock(irql);
2306 
2308 
2309  // Complete it with error
2310  pRequest->CompleteWithInformation(Status, 0);
2311 
2312  // Dereference request object
2313  pRequest->RELEASE(FXREQUEST_COMPLETE_TAG);
2314 
2315  return Status;
2316  }
2317 
2319  "Queuing WDFREQUEST 0x%p on WDFQUEUE 0x%p",
2320  pRequest->GetHandle(),GetObjectHandle());
2321 
2322  (VOID)pRequest->GetIrp(&pIrp);
2323 
2324  pFxIrp = pRequest->GetFxIrp();
2325 
2326  pFxIrp->MarkIrpPending();
2327 
2328  //
2329  // If the request is reserved, we may be called to dispatch
2330  // a pending reserved IRP from within the context of the completion routine.
2331  // So to avoid recursion, we will insert the request in the queue and try
2332  // to dispatch in the return path. If the request is not reserved then we
2333  // will dispatch it directly because this path is meant for dispatching new
2334  // incoming I/O. There is no concern for running into recursion in that
2335  // scenario.
2336  //
2337  if (pRequest->IsReserved() && m_Dispatching != 0) {
2339  Unlock(irql);
2340  }
2341  else {
2342  DispatchEvents(irql, pRequest);
2343  }
2344 
2345  // We always return status pending through the frameworks
2346  return STATUS_PENDING;
2347 }
2348 
2350 NTSTATUS
2353  )
2354 
2355 /*++
2356 
2357  Routine Description:
2358 
2359  Enqueue a request to the end of the queue.
2360 
2361  This is an internal version that does not fail
2362  the request if it can not be enqueued.
2363 
2364  Arguments:
2365 
2366  pRequest - Pointer to Request object
2367 
2368  Returns:
2369 
2370  STATUS_SUCCESS on success
2371 --*/
2372 
2373 {
2374  NTSTATUS status;
2375  KIRQL irql;
2376  BOOLEAN fromIo;
2377 
2378  // Get IoQueue Object Lock
2379  Lock(&irql);
2380 
2381  //
2382  // If queue is not taking new requests, fail now
2383  //
2385 
2387 
2389  "WDFQUEUE 0x%p is not accepting requests "
2390  "state is %!WDF_IO_QUEUE_STATE!, %s"
2391  "WDFREQUEST 0x%p %!STATUS!",
2394  "power stopping (Drain) in progress," : "",
2395  pRequest->GetHandle(), status);
2396 
2397  Unlock(irql);
2398 
2399  return status;
2400  }
2401 #if FX_VERBOSE_TRACE
2403  "Queuing WDFREQUEST 0x%p on WDFQUEUE 0x%p",
2404  pRequest->GetHandle(), GetObjectHandle());
2405 #endif
2406  //
2407  // The Request has one reference count, and no completion
2408  // callback function. It has been completely removed from
2409  // its previous queue.
2410  //
2411 
2412  //
2413  // Cache this info b/c the request can be delete and freed by the time we use it.
2414  //
2415  fromIo = pRequest->IsAllocatedFromIo();
2416 
2417  //
2418  // Insert it in the Cancel Safe Queue
2419  //
2420  // This will mark the IRP pending
2421  //
2422  status = pRequest->InsertTailIrpQueue(&m_Queue, NULL);
2423 
2424  if (!NT_SUCCESS(status)) {
2425 
2426  pRequest->SetCurrentQueue(this);
2427 
2429 
2430  //
2431  // We must add a reference since the CancelForQueue path
2432  // assumes we were on the FxIrpQueue with the extra reference
2433  //
2434  pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
2435 
2436  //
2437  // Mark the request as cancelled, place it on the cancel list,
2438  // and schedule the cancel event to the driver
2439  //
2440  CancelForQueue(pRequest, irql);
2441 
2442  Lock(&irql);
2443  }
2444  else {
2445  pRequest->SetCurrentQueue(this);
2446 
2447  // Check if went from no requests to have requests
2449  }
2450 
2451  //
2452  // If the request is driver-created, we may be called to dispatch
2453  // a request from within the context of the completion routine.
2454  // So to avoid recursion, we will try to dispatch in the return path.
2455  // If the request is not driver-created then we will dispatch it directly because
2456  // this path is meant for dispatching new incoming I/O. There is no concern for
2457  // running into recursion in that scenario.
2458  //
2459  if (fromIo == FALSE && m_Dispatching != 0) {
2460  Unlock(irql);
2461  }
2462  else {
2463  //
2464  // Attempt to dispatch any new requests.
2465  //
2466  // This releases, and re-acquires the IoQueue lock
2467  //
2468  DispatchEvents(irql);
2469  }
2470 
2471  return STATUS_SUCCESS;
2472 }
2473 
2474 VOID
2476  )
2477 
2478 /*++
2479 
2480  Routine Description:
2481 
2482  Dispatch requests from the queue to the driver
2483  from within the m_Dpc
2484 
2485  Arguments:
2486 
2487  Returns:
2488 
2489 --*/
2490 
2491 {
2492  KIRQL irql;
2493 
2494  Lock(&irql);
2495 
2496  ASSERT(m_DpcQueued != FALSE);
2497 
2499 
2500  DispatchEvents(irql);
2501 
2502  //
2503  // DispatchEvents drops the lock before returning. So reacquire the lock.
2504  //
2505  Lock(&irql);
2506 
2508  InsertQueueDpc();
2509  } else {
2511  m_DpcQueued = FALSE;
2512  }
2513 
2514  Unlock(irql);
2515 
2516  return;
2517 }
2518 
2519 VOID
2521  )
2522 
2523 /*++
2524 
2525  Routine Description:
2526 
2527  Dispatch requests from the queue to the driver
2528  from within the m_WorkItem.
2529 
2530  Arguments:
2531 
2532  Returns:
2533 
2534 --*/
2535 
2536 {
2537  KIRQL irql;
2538 
2539  Lock(&irql);
2540 
2542 
2544 
2545  DispatchEvents(irql);
2546 
2547  //
2548  // DispatchEvents drops the lock before returning. So reacquire
2549  // the lock.
2550  //
2551  Lock(&irql);
2552 
2553  if (m_Deleted == FALSE &&
2556  //
2557  // Workitem is queued.
2558  //
2559  DO_NOTHING();
2560  } else {
2563  }
2564 
2565  Unlock(irql);
2566 
2567  return;
2568 }
2569 
2570 NTSTATUS
2573  __in KIRQL PreviousIrql
2574  )
2575 /*++
2576 
2577  Routine Description:
2578 
2579  Purpose of this function is to insert the request that's dispatched
2580  by the IoPkg into FxIrpQueue. This function has been added to improve
2581  the performance of queueing logic. Prior to version 1.7, when a
2582  request is dispatched to a queue, it was first inserted into queue,
2583  various checks for the readiness of queue made, and then the request
2584  is removed from the queue to be presented to the driver.
2585 
2586  To improve the I/O performance, dispatching logic has been changed
2587  such that the request will not be inserted into the queue if the queue
2588  is ready to dispatch the request. If the queue is not ready or if there
2589  are other events to be dispatched before dispatching the new incoming request,
2590  we will queue the request first using this function before releasing the lock
2591  so that we don't change the ordering of requests in the queue.
2592 
2593 --*/
2594 {
2595  NTSTATUS status;
2596 
2597  status = (*Request)->InsertTailIrpQueue(&m_Queue, NULL);
2598 
2599  if (!NT_SUCCESS(status)) {
2600  //
2601  // Request was never presented to the driver
2602  // so there is no need to call CancelForQueue
2603  // in this case.
2604  //
2606 
2608 
2609  (*Request)->CompleteWithInformation(status, 0);
2610 
2611  (*Request)->RELEASE(FXREQUEST_COMPLETE_TAG);
2612 
2613  Lock(&PreviousIrql);
2614  }
2615  else {
2616  (*Request)->SetCurrentQueue(this);
2617 
2618  // Check if went from no requests to have requests
2620  }
2621 
2622  //
2623  // Request is either inserted into the queue or completed. Clear
2624  // the field to prevent touching the request.
2625  //
2626  *Request = NULL;
2627 
2628  return status;
2629 }
2630 
2632 BOOLEAN
2634  __in KIRQL PreviousIrql
2635  )
2636 /*++
2637 
2638  Routine Description:
2639 
2640  Dispatch events and requests from the queue to the driver.
2641 
2642  The IoQueue object lock must be held on entry. This routine
2643  should not drop and reacquire the lock to ensure the request
2644  is not queued out of order.
2645 
2646  Returns:
2647 
2648  TRUE - if the thread meets all the sychronization and
2649  execution contraints to dispatch the events.
2650  FALSE - if the dispatching of events to be defered to
2651  another thread - either DPC or workitem.
2652 --*/
2653 {
2654  //
2655  // If the current irql is not at passive-level and the queue is configured
2656  // to receive events only at passive-level then we should queue a
2657  // workitem to defer the processing.
2658  //
2662  "Current thread 0x%p is not at the passive-level"
2663  " %!irql!, posting to worker thread for WDFQUEUE"
2664  " 0x%p",
2666  PreviousIrql,
2667  GetObjectHandle());
2668  //
2669  // We only need to post this once
2670  //
2671  if (m_WorkItemQueued == FALSE) {
2672 
2674 
2676  ASSERT(FALSE);
2678  }
2679  }
2680 
2681  return FALSE;
2682  }
2683 
2684  //
2685  // If the current thread is holding the presentation lock, we
2686  // must defer to a DPC or work item.
2687  // This is the result of the device driver calling
2688  // WdfRequestForwardToIoQueue, or WdfIoQueueStart/Stop from
2689  // within I/O dispatch handler. This can also occur if a driver
2690  // attempts to forward a request among a circular series of Queues
2691  // that are configured to have locking constraints.
2692  //
2694 
2696  "Presentation lock for WDFQUEUE 0x%p is "
2697  "already held, deferring to dpc or workitem",
2698  GetObjectHandle());
2699 
2700  if (m_PassiveLevel) {
2701 
2702  if(m_WorkItemQueued == FALSE) {
2703 
2705 
2707  ASSERT(FALSE);
2709  }
2710  }
2711  }
2712  else {
2713  //
2714  // We only need to post this once
2715  //
2716  if (m_DpcQueued == FALSE) {
2717 
2718  m_DpcQueued = TRUE;
2719 
2720  InsertQueueDpc();
2721  }
2722  }
2723 
2724  return FALSE;
2725  }
2726 
2727  return TRUE;
2728 }
2729 
2730 _Releases_lock_(this->m_SpinLock.m_Lock)
2732 BOOLEAN
2733 FxIoQueue::DispatchEvents(
2734  __in __drv_restoresIRQL KIRQL PreviousIrql,
2735  __in_opt FxRequest* NewRequest
2736  )
2737 /*++
2738 
2739  Routine Description:
2740 
2741  Dispatch events and requests from the queue to the driver.
2742 
2743  The IoQueue object lock must be held on entry, but this routine can release
2744  and re-acquire the lock multiple times while processing.
2745 
2746  It returns to the caller with the lock released, but queue state may have
2747  changed.
2748 
2749  The main processing loop checks for various Queue state change events
2750  delivering them to the driver, and then finally any WDFREQUEST objects
2751  that are pending in the Queue.
2752 
2753  The design also handles the recursive case with the m_Dispatching
2754  field so that a driver that completes requests from within the
2755  callback does not cause a stack or lock recursion.
2756 
2757  All event callbacks to the device driver are provided though the
2758  FxCallback object which manages lock acquire and release as required
2759  by the locking model.
2760 
2761  In addition these may be passive or dispatch level locks.
2762  If configured for passive level callbacks,
2763  must defer to a work item if current thread is DISPATCH_LEVEL
2764  when not owning the current FxIoQueue lock
2765 
2766  Arguments:
2767 
2768  NewRequest - This is a new incoming request from the driver above.
2769  It will be either presented to the driver or saved into
2770  a queue if the conditions are not right to dispatch.
2771 
2772  Returns:
2773 
2774  FALSE if the queue is in a deleted state else TRUE.
2775  Caller should check for return value only if it's waiting
2776  on the some events to be invoked by this call.
2777 
2778 --*/
2779 {
2781  ULONG totalIoCount;
2782  NTSTATUS status;
2783  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
2784 
2785  if (m_Deleted) {
2786  ASSERT(NewRequest == NULL);
2787  Unlock(PreviousIrql);
2788  return FALSE;
2789  }
2790 
2791  //
2792  // The design of the I/O Queue allows all "events" to notify the driver of
2793  // to be deferred until the opportune time to deliver them.
2794  // Depending on the drivers configured locking and threading
2795  // mode, this may have to be deferred to a worker thread or a DPC
2796  // to be in a compatible IRQL level, or to prevent a lock recursion
2797  // when a parent objects lock is in effect.
2798  //
2799 
2800  if (CanThreadDispatchEventsLocked(PreviousIrql) == FALSE) {
2801  //
2802  // Previous workitem or Dpc might be running the DispatchEvents right now.
2803  // But it may be at a point where it might miss out to process the event
2804  // that we have been asked to dispatch. This is possible because the
2805  // DispatchEvent is reentrant as it acquires and drops lock along
2806  // the way. So we make a note of this, so that when the current Dpc or
2807  // workItem runs to completion, it will requeue itself to handle our message.
2808  //
2809  m_RequeueDeferredDispatcher = TRUE;
2810 
2811  //
2812  // Queue the request in to FxIrpQueue and return.
2813  //
2814  InsertNewRequest(&NewRequest, PreviousIrql);
2815  Unlock(PreviousIrql);
2816  return TRUE;
2817  }
2818 
2819  //
2820  // This must be incremented before attempting to deliver any
2821  // events to the driver. This prevents recursion on the presentation lock,
2822  // and limits the stack depth in a Start/Complete/Start/... recursion
2823  //
2824  m_Dispatching++;
2825 
2827  "Thread %p is processing WDFQUEUE 0x%p",
2829 
2830  //
2831  // At this point all constaints such as IRQL level, locks held,
2832  // and stack recursion protection has been satisfied, and we can
2833  // make callbacks into the device driver.
2834  //
2835  // Process events and requests until we either have an empty queue,
2836  // the driver stops taking requests, or some queue state does not
2837  // allow the driver to take new requests
2838  //
2839  #pragma warning(disable:4127)
2840  while (TRUE) {
2841  #pragma warning(default:4127)
2842  //
2843  // totoalIoCount is sum of requests pending in the queue and requests
2844  // currently owned by the driver.
2845  //
2846  totalIoCount = m_Queue.GetRequestCount() + m_DriverIoCount;
2847 
2848  //
2849  // Increment the count if there is a new request to be dispatched.
2850  //
2851  totalIoCount += ((NewRequest != NULL) ? 1 : 0);
2852 
2853  if (!IsListEmpty(&this->m_Cancelled)) {
2854  status = InsertNewRequest(&NewRequest, PreviousIrql);
2855  if (!NT_SUCCESS(status)) {
2856  continue; // totalIoCount may be zero now.
2857  }
2858 
2859  //
2860  // This can drop and re-acquire the queue lock
2861  // ProcessCancelledRequests returns FALSE if the queue is
2862  // notifying driver about power state changes.
2863  //
2864  if(ProcessCancelledRequests(&PreviousIrql)) {
2865  continue;
2866  }
2867  }
2868 
2869  if (!IsListEmpty(&this->m_CanceledOnQueueList)) {
2870  status = InsertNewRequest(&NewRequest, PreviousIrql);
2871  if (!NT_SUCCESS(status)) {
2872  continue; // totalIoCount may be zero now.
2873  }
2874 
2875  //
2876  // This can drop and re-acquire the queue lock
2877  // ProcessCancelledRequests returns FALSE if the queue is
2878  // notifying driver about power state changes.
2879  //
2880  if (ProcessCancelledRequestsOnQueue(&PreviousIrql)) {
2881  continue;
2882  }
2883  }
2884 
2885  if (m_IdleComplete.Method != NULL &&
2886  m_Dispatching == 1L &&
2887  m_DriverIoCount == 0L) {
2888 
2889  InsertNewRequest(&NewRequest, PreviousIrql);
2890 
2891  // no more driver owned requests, we can clear the following flag:
2892  m_CancelDispatchedRequests = FALSE;
2893 
2894  // This can drop and re-acquire the queue lock
2895  ProcessIdleComplete(&PreviousIrql);
2896  continue;
2897  }
2898 
2899  if (m_PurgeComplete.Method != NULL &&
2900  totalIoCount == 0L &&
2901  m_Dispatching == 1L) {
2902 
2903  InsertNewRequest(&NewRequest, PreviousIrql);
2904 
2905  // no more driver owned requests, we can clear the following flag:
2906  m_CancelDispatchedRequests = FALSE;
2907 
2908  // This can drop and re-acquire the queue lock
2909  ProcessPurgeComplete(&PreviousIrql);
2910  continue;
2911  }
2912 
2913  if (m_IsDevicePowerPolicyOwner &&
2914  m_PowerManaged &&
2915  m_PowerReferenced &&
2916  totalIoCount == 0L &&
2917  m_Dispatching == 1L) {
2918 
2919  //
2920  // Queue has no requests, and is going idle. Notify
2921  // PNP/Power.
2922  //
2923  m_Device->m_PkgPnp->PowerDereference();
2924  m_PowerReferenced = FALSE;
2925  continue;
2926  }
2927 
2928  //
2929  // Look for power state transitions
2930  //
2931  if (m_PowerState != FxIoQueuePowerOn &&
2932  m_PowerState != FxIoQueuePowerOff) {
2933 
2935  "WDFQUEUE 0x%p Power Transition State "
2936  "%!FxIoQueuePowerState!", GetObjectHandle(),
2937  m_PowerState);
2938 
2939  status = InsertNewRequest(&NewRequest, PreviousIrql);
2940  if (!NT_SUCCESS(status)) {
2941  continue; // totalIoCount may be zero now.
2942  }
2943 
2944  // Process intermediate power state
2945  // This can drop and re-acquire the queue lock
2946  if (ProcessPowerEvents(&PreviousIrql)) {
2947  continue;
2948  }
2949  else {
2950 
2951  //
2952  // Return, awaiting some response from the driver
2953  //
2954  goto Done;
2955  }
2956  }
2957  else {
2958  // Queue is either in PowerOn or PowerOff state
2959  DO_NOTHING();
2960  }
2961 
2962  //
2963  // Check for queue disposing should be made after processing all
2964  // the events.
2965  //
2966  if (m_Disposing &&
2967  totalIoCount == 0L &&
2968  m_Dispatching == 1L) {
2969 
2970  m_Deleted = TRUE;
2971 
2972  //
2973  // After this point, no other thread will be able to dispatch
2974  // events from this queue. Also threads that are about to call
2975  // this function as soon as we drop the lock below should have
2976  // a reference on the queue to prevent queue object from being
2977  // freed when we signal the dispose thread to run through.
2978  //
2979  Unlock(PreviousIrql);
2980 
2981  m_FinishDisposing.Set();
2982  return TRUE;
2983  }
2984 
2985 
2986  //
2987  // Return if power is off, can't deliver any request oriented events
2988  // to the driver.
2989  //
2990  if (m_PowerState == FxIoQueuePowerOff) {
2991  status = InsertNewRequest(&NewRequest, PreviousIrql);
2992  if (!NT_SUCCESS(status)) {
2993  continue; // totalIoCount may be zero now.
2994  }
2995 
2996  goto Done;
2997  }
2998 
2999  //
3000  // See if the queue is (still) processing requests
3001  //
3002  if (!IsState(WdfIoQueueDispatchRequests)) {
3003 
3005  "WDFQUEUE 0x%p not in dispatching state, "
3006  "current state is %!WDF_IO_QUEUE_STATE!",
3007  GetObjectHandle(), m_QueueState);
3008 
3009  status = InsertNewRequest(&NewRequest, PreviousIrql);
3010  if (!NT_SUCCESS(status)) {
3011  continue; // totalIoCount may be zero now.
3012  }
3013 
3014  goto Done;
3015  }
3016 
3017  //
3018  // A manual dispatch queue can have a request ready notification
3019  //
3020  if (m_Type == WdfIoQueueDispatchManual) {
3021 
3022  status = InsertNewRequest(&NewRequest, PreviousIrql);
3023  if (!NT_SUCCESS(status)) {
3024  continue; // totalIoCount may be zero now.
3025  }
3026 
3027  if (m_ReadyNotify.Method != NULL && m_TransitionFromEmpty) {
3028 
3029  // This can drop and re-acquire the lock to callback to the driver
3030  ProcessReadyNotify(&PreviousIrql);
3031  continue;
3032  }
3033 
3034  goto Done;
3035  }
3036 
3037  if (m_Type == WdfIoQueueDispatchSequential && m_DriverIoCount > 0) {
3038  status = InsertNewRequest(&NewRequest, PreviousIrql);
3039  if (!NT_SUCCESS(status)) {
3040  continue; // totalIoCount may be zero now.
3041  }
3042 
3043  goto Done;
3044  }
3045 
3046  //
3047  // For counted Queue's dont dispatch request to driver if the
3048  // m_DriverIoCount exceeds the one set by the driver writer.
3049  //
3050  if (m_Type == WdfIoQueueDispatchParallel &&
3051  (ULONG)m_DriverIoCount >= m_MaxParallelQueuePresentedRequests) {
3052  status = InsertNewRequest(&NewRequest, PreviousIrql);
3053  if (!NT_SUCCESS(status)) {
3054  continue; // totalIoCount may be zero now.
3055  }
3056 
3057  goto Done;
3058  }
3059 
3060  //
3061  // If there is a request in the queue, then retrieve that.
3062  //
3063  pRequest = NULL;
3064  if (m_Queue.GetRequestCount() > 0L) {
3065  pRequest = FxRequest::GetNextRequest(&m_Queue);
3066  }
3067 
3068  //
3069  // The request from the queue should be dispatched first
3070  // to preserve the ordering.
3071  //
3072  if (pRequest != NULL) {
3073  InsertNewRequest(&NewRequest, PreviousIrql);
3074  }
3075  else {
3076  //
3077  // If there is no request in the queue then dispatch
3078  // the incoming one.
3079  //
3080  pRequest = NewRequest;
3081  if (pRequest != NULL) {
3082  pRequest->SetCurrentQueue(this);
3083  SetTransitionFromEmpty();
3084  NewRequest = NULL;
3085  }
3086  else {
3087  goto Done;
3088  }
3089  }
3090 
3091  //
3092  // pRequest is not cancellable now
3093  //
3094  InsertInDriverOwnedList(pRequest);
3095 
3096  Unlock(PreviousIrql);
3097 
3098  DispatchRequestToDriver(pRequest);
3099 
3100  Lock(&PreviousIrql);
3101  }
3102 
3103 Done:
3104  m_Dispatching--;
3105  Unlock(PreviousIrql);
3106  return TRUE;
3107 }
3108 
3109 VOID
3112  )
3113 
3114 /*++
3115 
3116  Routine Description:
3117 
3118  Dispatch the next request to the driver.
3119 
3120  The IoQueue object lock is *not* held.
3121 
3122  It returns to the caller with the lock *not* held.
3123 
3124  This is called by DispatchRequests(), and should not be
3125  called directly in order to maintain queue processing model.
3126 
3127  Arguments:
3128 
3129  Returns:
3130 
3131 --*/
3132 
3133 {
3134  PFX_DRIVER_GLOBALS FxDriverGlobals;
3135  NTSTATUS Status;
3136  FxRequestCompletionState oldState;
3137  WDFREQUEST hRequest;
3138  FxIrp* pIrp;
3139 
3140  FxDriverGlobals = GetDriverGlobals();
3141 
3142 
3143 
3144 
3145 
3146  (VOID)pRequest->GetCurrentIrpStackLocation();
3147 
3148  pIrp = pRequest->GetFxIrp();
3149 
3150  // The Irp does not have a cancel function right now
3151 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
3153 #endif
3154 
3155  //
3156  // Set our completion callback on the request now before
3157  // calling the driver since the driver can complete the
3158  // request in the callback handler, and to avoid races with
3159  // the drivers completion thread.
3160  //
3161  // This takes a reference on the request object.
3162  //
3163  oldState = pRequest->SetCompletionState(FxRequestCompletionStateQueue);
3164  ASSERT(oldState == FxRequestCompletionStateNone);
3165  UNREFERENCED_PARAMETER(oldState);
3166 
3167  if (FxDriverGlobals->FxVerifierOn) {
3168  //
3169  // If the verifier is on, we do not release the extra
3170  // reference so we can mark the request as no longer
3171  // being dispatched to the driver on return from the
3172  // event callback to the driver
3173  //
3174 
3175  ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) == 0);
3176 
3177  // Mark the request as being "owned" by the driver
3178  pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED |
3180  }
3181  else {
3182 
3183  //
3184  // Release our original reference. The FxRequest::Complete
3185  // will release the final one since we have registered a completion
3186  // callback handler
3187  //
3188  // We now have one reference count on the FxRequest object until
3189  // its completion routine runs since the completion event made
3190  // an extra reference, and will dereference it when it fires, or
3191  // its canceled.
3192  //
3193 
3194  pRequest->RELEASE(FXREQUEST_STATE_TAG);
3195  }
3196 
3197  //
3198  // Attempt to dispatch it to the driver
3199  //
3200 
3201  //
3202  // Note: A driver that changes its callback pointers at runtime
3203  // could run into a race here since we released the queue
3204  // lock. Currently, changing parameters on a processing
3205  // queue is undefined.
3206  //
3207  // The C DDI's force the callbacks to be registered at
3208  // queue creation time and avoid this race.
3209  //
3210 
3211  hRequest = pRequest->GetHandle();
3212 
3214 
3215  if ((majorFunction == IRP_MJ_READ) && m_IoRead.Method) {
3216  ULONG readLength = pIrp->GetParameterReadLength();
3217 
3218  //
3219  // Complete zero length reads with STATUS_SUCCESS unless the
3220  // driver specified it wants them delivered.
3221  //
3222  if ((readLength == 0) &&
3224 
3226  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
3227  "Zero length WDFREQUEST 0x%p completed automatically "
3228  "by WDFQUEUE 0x%p", hRequest, GetObjectHandle());
3229 
3230  pRequest->Complete(STATUS_SUCCESS);
3231  if (FxDriverGlobals->FxVerifierOn) {
3232  //
3233  // Release the reference taken in the call to SetCompletionState
3234  // at the top of the function.
3235  //
3236  pRequest->RELEASE(FXREQUEST_STATE_TAG);
3237  }
3238  return;
3239  }
3240 
3241  pRequest->SetPresented();
3242 
3244  "Calling driver EvtIoRead for WDFREQUEST 0x%p",
3245  hRequest);
3246 
3247  m_IoRead.Invoke(
3248  GetHandle(),
3249  hRequest,
3250  readLength
3251  );
3252  }
3253  else if ((majorFunction == IRP_MJ_WRITE) && m_IoWrite.Method) {
3254  ULONG writeLength = pIrp->GetParameterWriteLength();
3255 
3256  //
3257  // Complete zero length writes with STATUS_SUCCESS unless the
3258  // driver specified it wants them delivered.
3259  //
3260  if ((writeLength == 0) &&
3262 
3264  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
3265  "Zero length WDFREQUEST 0x%p completed automatically "
3266  "by WDFQUEUE 0x%p", hRequest, GetObjectHandle());
3267 
3268  pRequest->Complete(STATUS_SUCCESS);
3269 
3270  if (FxDriverGlobals->FxVerifierOn) {
3271  //
3272  // Release the reference taken in the call to SetCompletionState
3273  // at the top of the function.
3274  //
3275  pRequest->RELEASE(FXREQUEST_STATE_TAG);
3276  }
3277  return;
3278  }
3279 
3280  pRequest->SetPresented();
3281 
3283  "Calling driver EvtIoWrite for WDFREQUEST 0x%p",
3284  pRequest->GetObjectHandle());
3285 
3286  m_IoWrite.Invoke(
3287  GetHandle(),
3288  hRequest,
3289  writeLength
3290  );
3291  }
3293 
3294  pRequest->SetPresented();
3295 
3297  "Calling driver EvtIoDeviceControl for "
3298  "WDFREQUEST 0x%p", hRequest);
3299 
3301  GetHandle(),
3302  hRequest,
3306  );
3307  }
3308 
3310 
3311  pRequest->SetPresented();
3312 
3314  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
3315  "Calling driver EvtIoInternalDeviceControl for WDFREQUEST 0x%p",
3316  hRequest);
3317 
3319  GetHandle(),
3320  hRequest,
3324  );
3325  }
3326  else {
3327 
3328  //
3329  // If we have an IoStart registered, call it
3330  //
3331  if (m_IoDefault.Method) {
3332 
3334  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
3335  "Calling driver EvtIoDefault for WDFREQUEST 0x%p", hRequest);
3336 
3337 
3338  //
3339  // If we don't allow zero length requests, we must dig in whether
3340  // its a read or a write
3341  //
3343 
3344  if (majorFunction == IRP_MJ_READ) {
3345 
3346  if (pIrp->GetParameterReadLength() == 0) {
3347 
3349  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
3350  "Zero length WDFREQUEST 0x%p completed automatically "
3351  "by WDFQUEUE 0x%p", hRequest, GetObjectHandle());
3352 
3353  pRequest->Complete(STATUS_SUCCESS);
3354  if (FxDriverGlobals->FxVerifierOn) {
3355  //
3356  // Release the reference taken in the call to SetCompletionState
3357  // at the top of the function.
3358  //
3359  pRequest->RELEASE(FXREQUEST_STATE_TAG);
3360  }
3361  return;
3362  }
3363  }
3364  else if (majorFunction == IRP_MJ_WRITE) {
3365 
3366  if (pIrp->GetParameterWriteLength() == 0) {
3367 
3368  pRequest->Complete(STATUS_SUCCESS);
3369 
3371  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
3372  "Zero length WDFREQUEST 0x%p completed automatically "
3373  "by WDFQUEUE 0x%p", hRequest, GetObjectHandle());
3374 
3375  if (FxDriverGlobals->FxVerifierOn) {
3376  //
3377  // Release the reference taken in the call to SetCompletionState
3378  // at the top of the function.
3379  //
3380  pRequest->RELEASE(FXREQUEST_STATE_TAG);
3381  }
3382  return;
3383  }
3384  }
3385  }
3386 
3387  pRequest->SetPresented();
3388 
3389  m_IoDefault.Invoke(GetHandle(), hRequest);
3390  }
3391  else {
3393 
3395  "Driver has no event callback "
3396  "for %!WDF_REQUEST_TYPE!, completing WDFREQUEST 0x%p with "
3397  "%!STATUS!",
3398  majorFunction,
3399  pRequest,
3400  Status);
3401 
3402  pRequest->Complete(Status);
3403 
3404  if (FxDriverGlobals->FxVerifierOn) {
3405  //
3406  // Release our extra verifier reference now
3407  //
3408  // Release the reference taken in the call to SetCompletionState
3409  // at the top of the function.
3410  //
3411  pRequest->RELEASE(FXREQUEST_STATE_TAG);
3412  }
3413 
3414  return;
3415  }
3416  }
3417 
3418  // ******************************
3419  // Request may now be a freed object unless verifier is on. Only touch
3420  // request if verifier is on.
3421  // ******************************
3422 
3423  if (FxDriverGlobals->FxVerifierOn) {
3424 
3425  //
3426  // If the request has been forwarded, don't clear this
3427  // since the new queue may already be dispatching in a new thread or DPC
3428  //
3429  if ((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_FORWARDED) == 0x0) {
3430  pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_DISPATCH);
3431  }
3432 
3433  //
3434  // Release our extra verifier reference now
3435  //
3436  // Release the reference taken in the call to SetCompletionState
3437 
3438  // at the top of the function.
3439  //
3440  pRequest->RELEASE(FXREQUEST_STATE_TAG);
3441  }
3442 
3443  // Driver accepted a request
3444  return;
3445 }
3446 
3447 
3448 //
3449 // Register a callback when the Queue has a request.
3450 //
3451 // Only valid for a manual Queue.
3452 //
3454 NTSTATUS
3458  )
3459 {
3460  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
3461  KIRQL irql;
3462  NTSTATUS status;
3463 
3464  // Only valid for a manually dispatched Queue
3468  "WDFQUEUE 0x%p is "
3469  "not a Manual queue, ReadyNotify is only valid "
3470  "on a manual Queue, %!STATUS!",
3471  GetObjectHandle(), status);
3472  FxVerifierDbgBreakPoint(FxDriverGlobals);
3473  return status;
3474  }
3475 
3476  Lock(&irql);
3477 
3478  // If the queue is deleted, requests will not be serviced anymore
3479  if (m_Deleted) {
3480  Unlock(irql);
3481  return STATUS_DELETE_PENDING;
3482  }
3483 
3484  if (QueueReady != NULL) {
3485 
3486  //
3487  // Only one ReadyNotify registration per Queue is allowed
3488  //
3489  if (m_ReadyNotify.Method != NULL) {
3492  "WDFQUEUE 0x%p "
3493  "already has a ReadyNotify callback 0x%p"
3494  "registered, %!STATUS!",GetObjectHandle(),
3495  &m_ReadyNotify, status);
3496  FxVerifierDbgBreakPoint(FxDriverGlobals);
3497  Unlock(irql);
3498  return status;
3499  }
3500 
3503  }
3504  else {
3505 
3506  //
3507  // A request to cancel ready notifications
3508  //
3509 
3510  // If already cancelled, the driver is confused, notify it
3511  if (m_ReadyNotify.Method == NULL) {
3514  "WDFQUEUE 0x%p "
3515  "does not have a ReadyNotify to cancel, %!STATUS!",
3516  GetObjectHandle(), status);
3517  FxVerifierDbgBreakPoint(FxDriverGlobals);
3518  Unlock(irql);
3519  return status;
3520  }
3521 
3522  //
3523  // The queue should be stopped from dispatching requests to
3524  // avoid missing state transistions between clear and set.
3525  //
3529  "WDFQUEUE 0x%p "
3530  "should be stopped before clearing ReadyNotify callback "
3531  "0x%p registered, %!STATUS!",GetObjectHandle(),
3532  &m_ReadyNotify, status);
3533  FxVerifierDbgBreakPoint(FxDriverGlobals);
3534  Unlock(irql);
3535  return status;
3536 
3537  }
3538 
3541  }
3542 
3543  //
3544  // Check for ready notification since there may already be an event
3545  //
3546  DispatchEvents(irql);
3547 
3548  return STATUS_SUCCESS;
3549 }
3550 
3551 VOID
3553  )
3554 {
3555  KIRQL irql;
3556 
3557  Lock(&irql);
3558 
3560 
3561  //
3562  // We should set the flag to notify the driver on queue start in case
3563  // the driver stops the queue while the ReadyNotify callback is executing.
3564  // If that happens, the request will be left in the manual queue with
3565  // m_TransitionFromEmpty cleared.
3566  //
3567  if (m_Queue.GetRequestCount() > 0L) {
3570  }
3571 
3572  //
3573  // We may have transitioned to a status that resumes
3574  // processing, so call dispatch function.
3575  //
3576 
3577  DispatchEvents(irql);
3578 
3579  return;
3580 }
3581 
3583 NTSTATUS
3585  __in BOOLEAN CancelRequests,
3586  __in_opt PFN_WDF_IO_QUEUE_STATE IdleComplete,
3588  )
3589 
3590 /*++
3591 
3592 Routine Description:
3593 
3594  Idle (stop) the Queue.
3595 
3596  If CancelRequests == TRUE,
3597  1) any requests in the Queue that have not been presented to the device driver are
3598  completed with STATUS_CANCELLED.
3599  2) any requests that the driver is operating on that are cancelable will have an
3600  I/O Cancel done on them.
3601  3) any forward progress queued IRPs are completed with STATUS_CANCELLED.
3602 
3603 Arguments:
3604 
3605 Returns:
3606 
3607 --*/
3608 
3609 {
3611  KIRQL irql;
3612  NTSTATUS status;
3613  LIST_ENTRY fwrIrpList = {0};
3614  FxRequest* request;
3615 
3616 
3617  Lock(&irql);
3618 
3619  // If the queue is deleted, requests will not be serviced anymore
3620  if (m_Deleted) {
3623  "WDFQUEUE 0x%p is already deleted, %!STATUS!",
3624  GetObjectHandle(), status);
3625  Unlock(irql);
3626 
3627  return status;
3628  }
3629 
3630  //
3631  // If a IdleComplete callback is supplied, we must register it up
3632  // front since a transition empty could occur in another thread.
3633  //
3634  if (IdleComplete != NULL) {
3635 
3636  //
3637  // Only one Idle or Purge Complete callback can be outstanding
3638  // at a time per Queue
3639  //
3640  if (m_IdleComplete.Method != NULL) {
3643  "WDFQUEUE 0x%p already has a "
3644  "IdleComplete callback registered 0x%p, "
3645  "%!STATUS!", GetObjectHandle(),
3647  status);
3648  Unlock(irql);
3649 
3650  return status;
3651  }
3652 
3653  m_IdleComplete.Method = IdleComplete;
3655  }
3656 
3657  // Set Accept request and Clear dispatch requests
3659 
3660  //
3661  // Get ready to cancel current queued requests. Note that we don't want to
3662  // prevent new requests from being queue, i.e., it is legal for an upper
3663  // driver can resend another request in its completion routine.
3664  //
3665  if (CancelRequests) {
3666  //
3667  // Driver wants to abort/complete all queued request and cancel or
3668  // wait for all requests the driver is currently handling. Thus we must
3669  // prevent the driver from requeuing stale requests.
3670  // The 'cancel driver requests' field gives us this ability.
3671  // It is set here, and cleared when:
3672  // (a) Driver doesn't own any more requests, or
3673  // (b) the driver calls WdfIoQueueStart again (dispatch gate is opened).
3674  // When set, the framework automatically deletes any request that the
3675  // driver requeues.
3676  //
3678 
3679  request = NULL; // Initial tag used by PeekRequest.
3680  #pragma warning(disable:4127)
3681  while (TRUE) {
3682  #pragma warning(default:4127)
3683  status = FxRequest::PeekRequest(&m_Queue, // in:queue
3684  request, // in:tag.
3685  NULL, // in:file_obj
3686  NULL, // out:parameters
3687  &request); // out:request.
3688  if (status != STATUS_SUCCESS) {
3690  break;
3691  }
3692 
3693  //
3694  // Tag this request and release the extra ref that Peek() takes.
3695  //
3696  request->m_Canceled = TRUE;
3697 
3698 #pragma prefast(suppress:__WARNING_PASSING_FUNCTION_UNEXPECTED_NULL, "This is the tag value used in the ADDREF of Peek()")
3699  request->RELEASE(NULL);
3700  }
3701 
3702  //
3703  // Move forward progress IRPs to a temp list; we use this logic to
3704  // allow new IRPs to be pended to the original list.
3705  //
3706  if (IsForwardProgressQueue()) {
3707  InitializeListHead(&fwrIrpList);
3708  GetForwardProgressIrps(&fwrIrpList, NULL);
3709  }
3710  }
3711 
3712  // Unlock queue lock
3713  Unlock(irql);
3714 
3715  if (CancelRequests) {
3716  #pragma warning(disable:4127)
3717  while (TRUE) {
3718  #pragma warning(default:4127)
3719  //
3720  // Get the next FxRequest from the cancel safe queue
3721  //
3722  Lock(&irql);
3724  if (request == NULL) {
3727  "All WDFQUEUE 0x%p requests cancelled",
3728  GetObjectHandle());
3729  Unlock(irql);
3730  break;
3731  }
3732 
3733  // Irp is not cancellable now
3734 
3735  //
3736  // Make sure to purged requests only if:
3737  // (a) the request was present when we started this operation.
3738  // (b) any following request that is marked as cancelled.
3739  //
3740  if (request->IsCancelled() == FALSE) {
3741  status = request->InsertHeadIrpQueue(&m_Queue, NULL);
3742  if (NT_SUCCESS(status)) {
3743  Unlock(irql);
3744  break;
3745  }
3746 
3748  }
3751  "Cancelling WDFREQUEST 0x%p, WDFQUEUE 0x%p",
3752  request->GetHandle(),GetObjectHandle());
3753 
3754  //
3755  // We must add a reference since the CancelForQueue path
3756  // assumes we were on the FxIrpQueue with the extra reference
3757  //
3758  request->ADDREF(FXREQUEST_QUEUE_TAG);
3759 
3760  //
3761  // Mark the request as cancelled, place it on the cancel list,
3762  // and schedule the cancel event to the driver
3763  //
3764  CancelForQueue(request, irql);
3765  }
3766 
3767  //
3768  // Walk the driver cancelable list cancelling the requests.
3769  //
3770  #pragma warning(disable:4127)
3771  while (TRUE) {
3772  #pragma warning(default:4127)
3773  //
3774  // Get the next request of driver cancelable requests
3775  //
3776  Lock(&irql);
3778  if (request == NULL) {
3781  "All driver cancellable requests cancelled "
3782  " in WDFQUEUE 0x%p",
3783  GetObjectHandle());
3784  Unlock(irql);
3785  break;
3786  }
3787 
3788  request->m_Canceled = TRUE;
3789 
3790  Unlock(irql);
3791 
3792  //
3793  // If the driver follows the pattern of removing cancel status
3794  // from the request before completion, then there is no race
3795  // with this routine since we will not be able to retrieve any
3796  // requests the driver has made non-cancellable in preparation
3797  // for completion.
3798  //
3799  request->ADDREF(FXREQUEST_QUEUE_TAG);
3800 
3802 
3803  // The request could have been completed and released by the driver
3804  }
3805 
3806  //
3807  // Cleanup forward progress IRP list.
3808  //
3809  if (IsForwardProgressQueue()) {
3810  CancelIrps(&fwrIrpList);
3811  }
3812  }
3813 
3814  //
3815  // Since we set that no new requests may be dispatched,
3816  // if both m_Queue.GetRequestCount(), m_DriverIoCount == 0, and
3817  // m_Dispatch == 0, right now the queue is completely idle.
3818  //
3819 
3820  //
3821  // We check if our m_PurgeComplete callback is still set
3822  // since it may have been called by another thread when
3823  // we dropped the lock above
3824  //
3825  Lock(&irql);
3826  DispatchEvents(irql);
3827 
3828  //
3829  // If the driver registered an IdleComplete callback, and it was
3830  // not idle in the above check, it will be called when the final
3831  // callback handler from the device driver returns.
3832  //
3833  return STATUS_SUCCESS;
3834 }
3835 
3837 NTSTATUS
3839  __in BOOLEAN CancelRequests
3840  )
3841 /*++
3842 
3843 Routine Description:
3844 
3845  Idle the Queue and wait for the driver-owned requests to complete.
3846 
3847 Arguments:
3848 
3849  CancelRequests - If TRUE, functions tries to cancel outstanding requests.
3850 
3851 Returns:
3852 
3853 --*/
3854 {
3855  NTSTATUS status;
3856 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
3857  MxEvent* event = this->m_RequestWaitEventUm.GetSelfPointer();
3858 #else
3859  MxEvent eventOnStack;
3860  //
3861  // Note that initialize always succeeds in KM so return is not checked.
3862  //
3863  eventOnStack.Initialize(NotificationEvent, FALSE);
3864  MxEvent* event = eventOnStack.GetSelfPointer();
3865 #endif
3866 
3867  status = QueueIdle(CancelRequests, _IdleComplete, event->GetSelfPointer());
3868 
3869  if(NT_SUCCESS(status)) {
3870 
3872  "Waiting for %d requests to complete "
3873  "on WDFQUEUE 0x%p",
3875  GetObjectHandle());
3876 
3877  Mx::MxEnterCriticalRegion();
3878 
3879  GetDriverGlobals()->WaitForSignal(event->GetSelfPointer(),
3880  "waiting for queue to stop, WDFQUEUE", GetHandle(),
3883 
3884 
3885  Mx::MxLeaveCriticalRegion();
3886  }
3887 
3888  return status;
3889 
3890 }
3891 
3893 NTSTATUS
3895  __in BOOLEAN CancelQueueRequests,
3896  __in BOOLEAN CancelDriverRequests,
3899  )
3900 /*++
3901 
3902 Routine Description:
3903 
3904  Purge the Queue.
3905 
3906  If CancelQueueRequests == TRUE, any requests in the
3907  Queue that have not been presented to the device driver are
3908  completed with STATUS_CANCELLED.
3909 
3910  If CancelDriverRequests == TRUE, any requests that the
3911  driver is operating on that are cancelable will have an
3912  I/O Cancel done on them.
3913 
3914 Arguments:
3915 
3916 Returns:
3917 
3918 --*/
3919 {
3921  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
3922  KIRQL irql;
3923  NTSTATUS status;
3924 
3925  Lock(&irql);
3926 
3927  //
3928  // If the Queue is deleted, there can't be any requests
3929  // to purge, and the queue is no longer executing its
3930  // event dispatch loop, so we would stop responding if we
3931  // registered now.
3932  //
3933  // We could try and silently succeed this, but if we do, we
3934  // must invoke the PurgeComplete callback, and without our
3935  // queue state machine excuting, we can not ensure any
3936  // callback constraints are handled such as locking, queueing
3937  // to passive level, etc. So we just fail to indicate to the
3938  // driver we *will not* be invoking its PurgeComplete function.
3939  //
3940  if (m_Deleted) {
3943  "WDFQUEUE 0x%p is already deleted %!STATUS!",
3944  GetObjectHandle(), status);
3945  Unlock(irql);
3946 
3947  return status;
3948  }
3949 
3950  //
3951  // If a PurgeComplete callback is supplied, we must register it up
3952  // front since a transition empty could occur in another thread.
3953  //
3954  if (PurgeComplete != NULL) {
3955 
3956  //
3957  // Only one PurgeComplete callback can be outstanding
3958  // at a time per Queue
3959  //
3960  if (m_PurgeComplete.Method != NULL) {
3963  "WDFQUEUE 0x%p already has a "
3964  "PurgeComplete callback registered 0x%p "
3965  "%!STATUS!", GetObjectHandle(),
3967  Unlock(irql);
3968 
3969  return status;
3970  }
3971 
3974  }
3975 
3976  // Clear accept requests
3978 
3979  if (CancelQueueRequests && CancelDriverRequests &&
3980  FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) {
3981  //
3982  // Driver wants to abort/complete all queued request and cancel or
3983  // wait for all requests the driver is currently handling. Thus we must
3984  // prevent the driver from requeuing stale requests.
3985  // This flag is set here, and cleared when:
3986  // (a) Driver doesn't own any more requests, or
3987  // (b) the driver calls WdfIoQueueStart again (dispatch gate is opened).
3988  // When set, the framework automatically deletes any request that the
3989  // driver requeues.
3990  // For compatibility we do this only for drivers v1.11 and above.
3991  //
3993  }
3994 
3995  // Unlock queue lock
3996  Unlock(irql);
3997 
3998  if (CancelQueueRequests) {
3999  #pragma warning(disable:4127)
4000  while (TRUE) {
4001  #pragma warning(default:4127)
4002  //
4003  // Get the next FxRequest from the cancel safe queue
4004  //
4005  Lock(&irql);
4007  if (pRequest == NULL) {
4009  "All WDFQUEUE 0x%p requests cancelled",
4010  GetObjectHandle());
4011  Unlock(irql);
4012  break;
4013  }
4014 
4015  // Irp is not cancellable now
4016 
4018  "Cancelling WDFREQUEST 0x%p, WDFQUEUE 0x%p",
4019  pRequest->GetHandle(),GetObjectHandle());
4020 
4021  //
4022  // We must add a reference since the CancelForQueue path
4023  // assumes we were on the FxIrpQueue with the extra reference
4024  pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
4025 
4026  //
4027  // Mark the request as cancelled, place it on the cancel list,
4028  // and schedule the cancel event to the driver
4029  //
4030  CancelForQueue(pRequest, irql);
4031 
4032  }
4033  }
4034 
4035  if (CancelDriverRequests) {
4036 
4037  //
4038  // Walk the driver cancelable list cancelling
4039  // the requests.
4040  //
4041  #pragma warning(disable:4127)
4042  while (TRUE) {
4043  #pragma warning(default:4127)
4044  //
4045  // Get the next request of driver cancelable requests
4046  //
4047  Lock(&irql);
4049  if (pRequest == NULL) {
4051  "All driver cancellable requests cancelled "
4052  " in WDFQUEUE 0x%p",
4053  GetObjectHandle());
4054  Unlock(irql);
4055  break;
4056  }
4057 
4058  pRequest->m_Canceled = TRUE;
4059 
4060  Unlock(irql);
4061 
4062  //
4063  // If the driver follows the pattern of removing cancel status
4064  // from the request before completion, then there is no race
4065  // with this routine since we will not be able to retrieve any
4066  // requests the driver has made non-cancellable in preparation
4067  // for completion.
4068  //
4069  pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
4070 
4072 
4073  // The request could have been completed and released by the driver
4074  }
4075  }
4076 
4077  if (IsForwardProgressQueue()) {
4079  }
4080 
4081  //
4082  // Since we set that no new requests may be enqueued,
4083  // if both m_Queue.GetRequestCount() and m_DriverIoCount == 0 right
4084  // now the queue is completely purged.
4085  //
4086 
4087  //
4088  // We check if our m_PurgeComplete callback is still set
4089  // since it may have been called by another thread when
4090  // we dropped the lock above
4091  //
4092  Lock(&irql);
4093 
4094  DispatchEvents(irql);
4095 
4096  //
4097  // If the driver registered a PurgeComplete callback, and it was
4098  // not empty in the above check, it will be called when a
4099  // request complete from the device driver completes the
4100  // final request.
4101  //
4102  return STATUS_SUCCESS;
4103 }
4104 
4106 NTSTATUS
4108  )
4109 /*++
4110 
4111 Routine Description:
4112 
4113  Purge the queue and wait for it to complete.
4114  When this call returns, there are no requests in the queue or device
4115  driver and the queue state is set to reject new requests.
4116 
4117 --*/
4118 {
4119  NTSTATUS status;
4120 
4121 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
4122  MxEvent* event = this->m_RequestWaitEventUm.GetSelfPointer();
4123 #else
4124  MxEvent eventOnStack;
4125  //
4126  // Note that initialize always succeeds in KM so return is not checked.
4127  //
4128  eventOnStack.Initialize(NotificationEvent, FALSE);
4129  MxEvent* event = eventOnStack.GetSelfPointer();
4130 #endif
4131 
4132  status = QueuePurge(TRUE, TRUE, _PurgeComplete, event->GetSelfPointer());
4133 
4134  if(NT_SUCCESS(status)) {
4135 
4137  "Waiting for %d requests to complete "
4138  "on WDFQUEUE 0x%p",
4140  GetObjectHandle());
4141 
4142  Mx::MxEnterCriticalRegion();
4143 
4144  GetDriverGlobals()->WaitForSignal(event->GetSelfPointer(),
4145  "waiting for queue to purge, WDFQUEUE", GetHandle(),
4148 
4149  Mx::MxLeaveCriticalRegion();
4150  }
4151 
4152  return status;
4153 
4154 }
4155 
4157 NTSTATUS
4161  )
4162 {
4163  //
4164  // We drain the queue by calling QueuePurge with CancelQueueRequests
4165  // and CancelDriverRequests == FALSE. The Queue will reject new
4166  // requests, but allow the device driver to continue processing
4167  // requests currently on the Queue. The DrainComplete callback is
4168  // invoked when there are no requests in Queue or device driver.
4169  //
4170 
4172 
4173 }
4174 
4176 NTSTATUS
4178  )
4179 /*++
4180 
4181 Routine Description:
4182 
4183  Drain the queue and wait for it to complete.
4184  When this call returns, there are no requests in the queue or device
4185  driver and the queue state is set to reject new requests.
4186 
4187 --*/
4188 {
4189  NTSTATUS status;
4190 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
4191  MxEvent* event = this->m_RequestWaitEventUm.GetSelfPointer();
4192 #else
4193  MxEvent eventOnStack;
4194  //
4195  // Note that initialize always succeeds in KM so return is not checked.
4196  //
4197  eventOnStack.Initialize(NotificationEvent, FALSE);
4198  MxEvent* event = eventOnStack.GetSelfPointer();
4199 #endif
4200 
4201  status = QueueDrain(_PurgeComplete, event->GetSelfPointer());
4202 
4203  if(NT_SUCCESS(status)) {
4204 
4206  "Waiting for %d requests to complete "
4207  "on WDFQUEUE 0x%p",
4209  GetObjectHandle());
4210 
4211  Mx::MxEnterCriticalRegion();
4212 
4213  GetDriverGlobals()->WaitForSignal(event->GetSelfPointer(),
4214  "waiting for queue to drain, WDFQUEUE", GetHandle(),
4217 
4218  Mx::MxLeaveCriticalRegion();
4219  }
4220 
4221  return status;
4222 
4223 }
4224 
4225 
4226 VOID
4228  __out_opt PULONG pQueuedRequests,
4229  __out_opt PULONG pDriverPendingRequests
4230  )
4231 /*++
4232 
4233 Routine Description:
4234 
4235  Return the count of requests currently on the queue
4236  and owned by the driver.
4237 
4238 Arguments:
4239 
4240 Returns:
4241 
4242 --*/
4243 {
4244  if (pQueuedRequests != NULL) {
4245  *pQueuedRequests = m_Queue.GetRequestCount();
4246  }
4247 
4248  if (pDriverPendingRequests != NULL) {
4249  *pDriverPendingRequests = m_DriverIoCount;
4250  }
4251 
4252  return;
4253 }
4254 
4255 VOID
4258  )
4259 /*++
4260 
4261 Routine Description:
4262 
4263  Scan the queue and cancel all the requests that have
4264  the same fileobject as the input argument.
4265 
4266  This function is called when the IoPkg receives a
4267  IRP_MJ_CLEANUP requests.
4268 
4269  Additional reference is already taken on the object by the caller
4270  to prevent the queue from being deleted.
4271 
4272 Return Value:
4273 
4274 --*/
4275 {
4276  FxRequest* pRequest = NULL;
4277  NTSTATUS status;
4278  KIRQL irql;
4279 
4280  if (IsForwardProgressQueue()) {
4282  }
4283 
4284  Lock(&irql);
4285 
4286  #pragma warning(disable:4127)
4287  while (TRUE) {
4288  #pragma warning(default:4127)
4289 
4290  //
4291  // Get the next FxRequest from the cancel safe queue
4292  //
4295  break;
4296  }
4297  if(!NT_SUCCESS(status)) {
4298  ASSERTMSG("GetNextRequest failed\n", FALSE);
4299  break;
4300  }
4301 
4302  //
4303  // We must add a reference since the CancelForQueue path
4304  // assumes we were on the FxIrpQueue with the extra reference
4305  //
4306  pRequest->ADDREF(FXREQUEST_QUEUE_TAG);
4307 
4308  //
4309  // Mark the request as cancelled, place it on the cancel list,
4310  // and schedule the cancel event to the driver
4311  //
4312  CancelForQueue(pRequest, irql);
4313 
4314  //
4315  // Reacquire the lock because CancelForQueue visits the dispatch-loop
4316  // and releases the lock.
4317  //
4318  Lock(&irql);
4319  }
4320 
4321  DispatchEvents(irql);
4322 
4323  return;
4324 
4325 }
4326 
4327 _Releases_lock_(this->m_SpinLock.m_Lock)
4328 VOID
4329 FxIoQueue::CancelForQueue(
4331  __in __drv_restoresIRQL KIRQL PreviousIrql
4332  )
4333 /*++
4334 
4335  Routine Description:
4336 
4337  This routine performs the actions when notified of a cancel
4338  on a request that has not been presented to the driver
4339 
4340  Return Value:
4341 
4342  NTSTATUS
4343 
4344 --*/
4345 {
4346  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4347  FxRequestCompletionState oldState;
4348 
4349  // This is not an error, but want to make sure cancel testing works
4350  if (FxDriverGlobals->FxVerifierOn) {
4351 
4352  // Clear cancellable status, otherwise verifier in FxRequest::Complete will complain
4353  pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE);
4354 
4356  "WDFREQUEST 0x%p "
4357  "was cancelled while on WDFQUEUE 0x%p",
4358  pRequest->GetHandle(),GetObjectHandle());
4359  }
4360 
4361  pRequest->m_Canceled = TRUE;
4362 
4363  pRequest->MarkRemovedFromIrpQueue();
4364 
4365  //
4366  // Drop the extra reference taken when it was added to the queue
4367  // because the request is now leaving the queue.
4368  //
4369  pRequest->RELEASE(FXREQUEST_QUEUE_TAG);
4370 
4371  //
4372  // If the driver has registered m_CanceledOnQueue callback, and if
4373  // the request was ever presented to the driver then we need to
4374  // notify the driver
4375  //
4376  if(m_IoCanceledOnQueue.Method && pRequest->m_Presented) {
4377 
4378  //
4379  // Set the state to indicate the request has come from a queue.
4380  //
4381  oldState = pRequest->SetCompletionState(FxRequestCompletionStateQueue);
4382  ASSERT(oldState == FxRequestCompletionStateNone);
4383  UNREFERENCED_PARAMETER(oldState);
4384 
4385  // Insert it on the driver owned list
4386  InsertInDriverOwnedList(pRequest);
4387 
4388  if (FxDriverGlobals->FxVerifierOn) {
4389  ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) == 0);
4390  pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED);
4391  }
4392 
4393  //
4394  // Also insert the request in to m_CanceledOnQueueList so
4395  // that we can notify the driver when we visit the DispatchEvents
4396  //
4397  InsertTailList(&m_CanceledOnQueueList, pRequest->GetListEntry(FxListEntryQueueOwned));
4398 
4399  //
4400  // Release the reference taken in the call to SetCompletionState.
4401  //
4402  pRequest->RELEASE(FXREQUEST_STATE_TAG);
4403  } else {
4404 
4405  Unlock(PreviousIrql);
4406 
4407  // Its gone from our list, so complete it cancelled
4408  pRequest->CompleteWithInformation(STATUS_CANCELLED, 0);
4409 
4410  // Dereference the request objects final reference
4411  pRequest->RELEASE(FXREQUEST_COMPLETE_TAG);
4412 
4413  Lock(&PreviousIrql);
4414  }
4415 
4416  // This may have caused the queue to be emptied
4417  DispatchInternalEvents(PreviousIrql);
4418 
4419  return;
4420 }
4421 
4422 VOID
4425  __in MdIrp Irp,
4426  __in PMdIoCsqIrpContext CsqContext,
4427  __in KIRQL Irql
4428  )
4429 /*++
4430 
4431 Routine Description:
4432  This is our Cancel Safe Queue Callback from FxIrpQueue notifying us of an
4433  I/O cancellation on the main (pre driver) Queue.
4434 
4435  Note this callback is called with the queue lock held.
4436 
4437 Arguments:
4438  IrpQueue - Queue the request was on
4439 
4440  Irp - the irp being cancelled
4441 
4442  CsqContext - the context associated with the irp
4443 
4444 Return Value:
4445  None
4446 
4447  --*/
4448 {
4449  FxIoQueue* ioQueue;
4451 
4454 
4455  //
4456  // Must reference the queue since this could be the final
4457  // request on a deleting queue
4458  //
4459  ioQueue->ADDREF(Irp);
4460 
4461  //
4462  // We cannot drop the lock here because we may have to insert the
4463  // request in the driver owned list if the driver has registered
4464  // for canceled-on-queue callback. If we drop the lock and if the request
4465  // happens to be last request, the delete will run thru and put
4466  // the state of the queue to deleted state and prevent further dispatching
4467  // of requests.
4468  //
4469  ioQueue->CancelForQueue(pRequest, Irql);
4470 
4471  ioQueue->RELEASE(Irp);
4472 }
4473 
4474 VOID
4475 FX_VF_METHOD(FxIoQueue, VerifyValidateCompletedRequest)(
4476  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
4478  )
4479 {
4480  UNREFERENCED_PARAMETER(FxDriverGlobals);
4481 
4483 
4485  KIRQL irql;
4486 
4487  Request->Lock(&irql);
4488 
4489  (VOID) Request->VerifyRequestIsDriverOwned(FxDriverGlobals);
4490  Request->ClearVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED);
4491 
4492  Request->Unlock(irql);
4493 
4494  // Driver no longer owns it once completed
4495 
4496  // Request can't be on a cancel list
4497  pEntry = Request->GetListEntry(FxListEntryQueueOwned);
4500  GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO,
4501  "WDFREQUEST 0x%p is on a cancellation list for WDFQUEUE 0x%p",
4502  Request->GetHandle(), GetObjectHandle());
4503  FxVerifierDbgBreakPoint(GetDriverGlobals());
4504  }
4505 }
4506 
4507 VOID
4508 FX_VF_METHOD(FxIoQueue, VerifyCancelForDriver) (
4509  _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
4511  )
4512 {
4514 
4516 
4518  "WDFREQUEST 0x%p "
4519  "was cancelled in driver for WDFQUEUE 0x%p",
4520  Request->GetHandle(), GetObjectHandle());
4521 
4522  // Verifier code assures this is available to the cancel processing
4523  pEntry = Request->GetListEntry(FxListEntryQueueOwned);
4524  if (!IsListEmpty(pEntry)) {
4526  "WDFREQUEST 0x%p is "
4527  "already on list, FxRequest::m_ListEntry is busy!, "
4528  "WDFQUEUE 0x%p",
4529  Request->GetHandle(), GetObjectHandle());
4530  FxVerifierDbgBreakPoint(FxDriverGlobals);
4531  }
4532 }
4533 
4534 VOID
4537  )
4538 /*++
4539 
4540 Routine Description:
4541 
4542  This is called when a driver-owned cancelable request is canceled.
4543  This routine will add the request to m_Canceled list so that the
4544  dispatcher and call the driver cancel-routine to notify the driver.
4545 
4546  Queue lock is not held.
4547 
4548 Arguments:
4549 
4550  pRequest - is a driver owned cancelable request.
4551 
4552 Return Value:
4553 
4554 --*/
4555 {
4556  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4557  KIRQL irql;
4558 
4559  // This is not an error, but want to make sure cancel testing works
4560  VerifyCancelForDriver(FxDriverGlobals, pRequest);
4561 
4562  //
4563  // We are called with no locks held, but
4564  // can be in arbitrary thread context from
4565  // a cancel occuring from another driver within
4566  // a driver stack.
4567  //
4568 
4569  //
4570  // The Csq has removed this request from the driver pending
4571  // queue, and it no longer has a cancel function if the
4572  // driver does not accept the cancel right now.
4573  //
4574  // When callside eventually goes to remove it from the queue
4575  // by CsqContext, the Csq's will return NULL.
4576  //
4577  // Irp and FxRequest is still valid until the driver calls
4578  // WdfRequestComplete either as a result of this cancel
4579  // callback, or at its leasure if it chooses to ignore it.
4580  //
4581  // The insert of FxRequest onto the FxIrpQueue took out a
4582  // reference, and when an IRP gets cancelled, we are responsible
4583  // for this final dereference after calling into the driver.
4584  //
4585 
4586  //
4587  // Cancellations are dispatched as events to the device driver
4588  // using the standard DispatchEvents processing loop. In order
4589  // to support this, we must defer it by linking this request
4590  // into a list of cancelled requests.
4591  //
4592  // The requests will be removed from this list and cancel notified
4593  // to the device driver by the processing loop.
4594  //
4595 
4596  pRequest->MarkRemovedFromIrpQueue();
4597 
4598  //
4599  // Queue it on the cancelled list
4600  //
4601  Lock(&irql);
4602 
4604 
4605  //
4606  // Visit the event dispatcher
4607  //
4608  DispatchInternalEvents(irql);
4609 
4610  return;
4611 }
4612 
4613 VOID
4616  __in MdIrp Irp,
4617  __in PMdIoCsqIrpContext CsqContext,
4618  __in KIRQL Irql
4619  )
4620 /*++
4621 
4622 Routine Description:
4623  This is our Cancel Safe Queue Callback from FxIrpQueue notifying us of an
4624  I/O cancellation on a driver owned request (driver queue)
4625 
4626  Note this callback is called with the queue lock held.
4627 
4628 Arguments:
4629  IrpQueue - Queue the request was on
4630 
4631  Irp - the irp being cancelled
4632 
4633  CsqContext - the context associated with the irp
4634 
4635 
4636 Return Value:
4637  None
4638 
4639  --*/
4640 {
4641  FxIoQueue* ioQueue;
4643 
4646 
4647  pRequest->m_Canceled = TRUE;
4648 
4649  //
4650  // Must reference the queue since this could be the final
4651  // request on a deleting queue.
4652  //
4653  ioQueue->ADDREF(Irp);
4654 
4655  //
4656  // We can drop the lock because this request is a driver owned request and
4657  // it is tracked by m_DriverIoCount. As a result delete will be blocked
4658  // until the request is completed.
4659  //
4660  ioQueue->Unlock(Irql);
4661 
4662  ioQueue->CancelForDriver(pRequest);
4663 
4664  ioQueue->RELEASE(Irp);
4665 }
4666 
4668 VOID
4669 FxIoQueue::ProcessIdleComplete(
4670  __out PKIRQL PreviousIrql
4671  )
4672 /*++
4673 
4674 Routine Description:
4675 
4676  Handle IdleComplete.
4677  Calls back the driver if conditions are met.
4678  Called with Queue lock held, but can drop and re-acquire
4679  it when delivering the event callback to the device driver.
4680 
4681 Arguments:
4682  IrpQueue - Queue the request was on
4683 
4684  Irp - the irp being cancelled
4685 
4686  CsqContext - the context associated with the irp
4687 
4688 Return Value:
4689  None
4690 
4691  --*/
4692 {
4693  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4694  WDFCONTEXT ctx;
4696 
4697 
4700 
4703 
4704  Unlock(*PreviousIrql);
4705 
4707  "WDFQUEUE 0x%p is idle, calling driver callback",
4708  GetHandle());
4709 
4710  // Notify driver by callback
4711  if (callback.Method != NULL) {
4712  callback.Invoke(GetHandle(), ctx);
4713  }
4714 
4715  Lock(PreviousIrql);
4716 
4717  return;
4718 }
4719 
4721 VOID
4722 FxIoQueue::ProcessPurgeComplete(
4723  __out PKIRQL PreviousIrql
4724  )
4725 /*++
4726 
4727 Routine Description:
4728 
4729 
4730  Handle PurgeComplete.
4731 
4732  Calls back the driver if conditions are met.
4733 
4734  Called with Queue lock held, but can drop and re-acquire
4735  it when delivering the event callback to the device driver.
4736 
4737 
4738 Arguments:
4739 
4740 Return Value:
4741  None
4742 
4743  --*/
4744 {
4745  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4746  WDFCONTEXT ctx;
4748 
4751 
4754 
4755  Unlock(*PreviousIrql);
4756 
4758  "WDFQUEUE 0x%p is purged, calling driver callback",
4759  GetObjectHandle());
4760 
4761  // Notify driver by callback
4762  if (callback.Method != NULL) {
4763  callback.Invoke(GetHandle(), ctx);
4764  }
4765 
4766  Lock(PreviousIrql);
4767 
4768  return;
4769 }
4770 
4772 VOID
4773 FxIoQueue::ProcessReadyNotify(
4774  __out PKIRQL PreviousIrql
4775  )
4776 /*++
4777 
4778 Routine Description:
4779 
4780  Callback the driver for a Queue ready notify
4781  Called with the Queue lock held, and may release
4782  and re-acquire it in calling back the driver
4783 
4784 Arguments:
4785 
4786 Return Value:
4787  None
4788 
4789  --*/
4790 {
4791  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4792  WDFCONTEXT ctx;
4794 
4795  //
4796  // A callback to the driver "consumes" the notification.
4797  // Since we drop the lock when we call the driver, there is
4798  // a chance for the queue to be stopped or powered-off before
4799  // the driver tries to retrieve the request. So make sure
4800  // to set this flag when you power-on or start the queue to
4801  // avoid abandoning the requests in the queue.
4802  //
4804 
4805  //
4806  // Save a local copy since another thread could
4807  // cancel the ready notification out from under us
4808  // when we drop the lock
4809  //
4811 
4813 
4814  Unlock(*PreviousIrql);
4815 
4816  if (callback.Method != NULL) {
4817  callback.Invoke(GetHandle(), ctx);
4818  }
4819  else {
4820  if (FxDriverGlobals->FxVerifierOn) {
4822  "ReadyNotify notify method is NULL "
4823  "on WDFQUEUE 0x%p", GetObjectHandle());
4824  FxVerifierDbgBreakPoint(FxDriverGlobals);
4825  }
4826  }
4827 
4828  Lock(PreviousIrql);
4829 
4830  return;
4831 }
4832 
4834 BOOLEAN
4835 FxIoQueue::ProcessCancelledRequests(
4836  __out PKIRQL PreviousIrql
4837  )
4838 /*++
4839 
4840  Routine Description:
4841 
4842  Process any cancelled requests
4843  Called with the Queue lock held
4844  Can drop and re-acquire the queue lock
4845  Returns with the Queue lock held
4846 
4847  Arguments:
4848 
4849  Return Value:
4850  None
4851 
4852  --*/
4853 {
4856 
4857  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4858 
4860  //
4861  // We will not process cancelled request while the driver is being
4862  // notified to stop processing request to avoid double completion
4863  // of the request.
4864  //
4865  return FALSE;
4866  }
4867 
4868  while (!IsListEmpty(&m_Cancelled)) {
4870 
4872 
4873  // FxRequest ensures its not on any list on checked builds
4875 
4877 
4879  "Calling CancelRoutine routine "
4880  "for WDFREQUEST 0x%p on WDFQUEUE 0x%p",
4881  pRequest->GetHandle(), GetObjectHandle());
4882 
4883  if (FxDriverGlobals->FxVerifierOn) {
4884 
4885  // Set cancelled status, otherwise verifier in FxRequest::Complete will complain
4886  pRequest->SetVerifierFlags(FXREQUEST_FLAG_CANCELLED);
4887  }
4888 
4889  Unlock(*PreviousIrql);
4890 
4891  if (FxDriverGlobals->FxVerifierOn) {
4892  ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) != 0);
4893  }
4894 
4895  //
4896  // Notify the driver of cancel desire
4897  //
4898  pRequest->m_CancelRoutine.InvokeCancel(
4900  pRequest->GetHandle()
4901  );
4902 
4903  //
4904  // Release the reference that FxRequest took out on itself
4905  // when it was placed onto the FxIrpQueue. It is now leaving
4906  // the FxIrpQueue due to cancel, and we own this final
4907  // release.
4908  //
4909  pRequest->RELEASE(FXREQUEST_QUEUE_TAG);
4910 
4911  Lock(PreviousIrql);
4912  }
4913 
4914  return TRUE;
4915 }
4916 
4918 BOOLEAN
4919 FxIoQueue::ProcessCancelledRequestsOnQueue(
4920  __out PKIRQL PreviousIrql
4921  )
4922 /*++
4923 
4924  Routine Description:
4925 
4926  Process any cancelled requests
4927  Called with the Queue lock held
4928  Can drop and re-acquire the queue lock
4929  Returns with the Queue lock held
4930 
4931  Arguments:
4932 
4933  Return Value:
4934  None
4935 
4936  --*/
4937 {
4940 
4941  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4942 
4944  //
4945  // We will not process cancelled request while the driver is being
4946  // notified to stop/resume processing request to avoid double
4947  // completion of the request.
4948  //
4949  return FALSE;
4950  }
4951 
4952  while (!IsListEmpty(&m_CanceledOnQueueList)) {
4954 
4956 
4957  // FxRequest ensures its not on any list on checked builds
4959 
4961 
4963  "Calling CanceledOnQueue routine "
4964  "for WDFREQUEST 0x%p on WDFQUEUE 0x%p",
4965  pRequest->GetHandle(), GetObjectHandle());
4966 
4967  if (FxDriverGlobals->FxVerifierOn) {
4968 
4969  // Set cancelled status, otherwise verifier in FxRequest::Complete will complain
4970  pRequest->SetVerifierFlags(FXREQUEST_FLAG_CANCELLED);
4971  }
4972 
4973  Unlock(*PreviousIrql);
4974 
4975  if (FxDriverGlobals->FxVerifierOn) {
4976  ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) != 0);
4977  }
4978 
4979  //
4980  // Notify the driver
4981  //
4982  m_IoCanceledOnQueue.Invoke(GetHandle(), pRequest->GetHandle());
4983 
4984  Lock(PreviousIrql);
4985  }
4986 
4987  return TRUE;
4988 }
4989 
4991 BOOLEAN
4992 FxIoQueue::ProcessPowerEvents(
4993  __out PKIRQL PreviousIrql
4994  )
4995 /*++
4996 
4997 Routine Description:
4998 
4999  Processes the power state machine for I/O queues.
5000 
5001  Called with Queue lock held, but can drop and re-acquire
5002  it when it has to deliver event callbacks to the device driver.
5003 
5004  This can modify queue state as it transits the state machine, and
5005  is called from the main event processing loop DispatchEvents().
5006 
5007  Handling "in-flight" I/O requests in the device driver due
5008  to a power state transition (stopping) is tricky, and
5009  involves a complex state machine.
5010 
5011  The device driver must ensure that all in-flight I/O is stopped
5012  before it can release the thread calling into the driver to
5013  perform the power state transition, otherwise a system crash
5014  can result from accessing hardware after resources have been removed.
5015 
5016  In WDF, this burden is placed on FxIoQueue, so that the device driver
5017  does not have to implement the more complex aspects of this code,
5018  but can rely on notifications from the queue serialized under the
5019  IRQL level and locking it has configured.
5020 
5021 
5022  Implementation of FxIoQueue Power state machine:
5023  ------------------------------------------
5024 
5025  Since we must drop our lock to callback into the device
5026  driver for power notifications, the processing must occur
5027  as a state machine with three lists.
5028 
5029  On entry to the power stop state, any "in-flight" I/O requests
5030  are recorded on the m_DriverOwned list using
5031  FxRequest::FxListEntryDriverOwned for linkage.
5032 
5033  All of the requests on m_DriverOwned are moved to m_PowerNotify
5034  while holding the lock, with m_DriverOwned cleared. The state is changed
5035  to indicate that the driver is now being notified of requests.
5036 
5037  While in the driver notification state, requests are taken from the
5038  m_PowerNotify list, and moved on to the m_PowerDriverNotified list while
5039  under the lock, and the request is notified to the device driver
5040  by the callback while dropping the lock and re-acquiring the lock.
5041 
5042  As the driver acknowledges the power notification, it calls
5043  WdfRequestStopAcknowledge (FxIoQueue::StopAcknowledge) which moves the
5044  request from the m_PowerDriverNotified list back to the m_DriverOwned
5045  list.
5046 
5047  The device driver could also complete requests, in which case they
5048  just dis-appear from the lists by the completion code doing
5049  a RemoveEntryList on FxRequest::FxListEntryDriverOwned.
5050 
5051  This occurs until the m_PowerNotify list is empty, in which case
5052  the state is changed to driver notified.
5053 
5054  While in the driver notified state, the queue event processing continues
5055  until the m_PowerDriverNotified list is empty, and when it is, the
5056  stopped state is set, and the event m_PowerIdle is set. This releases
5057  the thread waiting on the power state transition in which all of the
5058  device drivers "in-flight" I/O has been stopped and accounted for.
5059 
5060  State Transitions:
5061  --------------
5062 
5063  During Stop:
5064 
5065  FxIoQueuePowerOn
5066  --> FxIoQueuePowerStartingTransition
5067  --> FxIoQueuePowerStopping
5068  --> FxIoQueuePowerStoppingNotifyingDriver
5069  --> FxIoQueuePowerStoppingDriverNotified
5070  --> FxIoQueuePowerOff
5071 
5072  During Purge:
5073 
5074  FxIoQueuePowerPurge
5075  --> FxIoQueuePowerPurgeNotifyingDriver
5076  --> FxIoQueuePowerPurgeDriverNotified
5077  --> FxIoQueuePowerOff
5078 
5079 
5080  During Resume:
5081 
5082  FxIoQueuePowerOff
5083  --> FxIoQueuePowerRestarting
5084  --> FxIoQueuePowerRestartingNotifyingDriver
5085  --> FxIoQueuePowerRestartingDriverNotified
5086  --> FxIoQueuePowerOn
5087 
5088 Arguments:
5089 
5090 Return Value:
5091 
5092  TRUE - Continue processing the event loop
5093  FALSE - Stop processing event loop
5094 
5095 --*/
5096 {
5099 
5100  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
5101 
5102  switch(m_PowerState) {
5103 
5105  if (m_Dispatching == 1) {
5106 
5107  //
5108  // If we are the last routine actively dispatching callbacks to
5109  // the device driver under a Power stop, then we must set the
5110  // event specifying no more callbacks are active.
5111  //
5112  m_PowerIdle.Set();
5113  }
5114 
5115  return FALSE;
5116 
5118  //
5119  // Set state to FxIoQueuePowerPurgeNotifyingDriver
5120  //
5122 
5123  // This should be empty on entry to this state
5124  ASSERT(IsListEmpty(&this->m_PowerNotify));
5125 
5126  if (!IsListEmpty(&m_DriverOwned)) {
5127 
5129  "Power Stop: WDFQUEUE 0x%p is powering off "
5130  "with in-flight requests",
5131  GetObjectHandle());
5132 
5133 
5134  // Ensure the logic of m_DriverOwned is correct
5137 
5138  //
5139  // Move all requests on m_DriverOwned to m_PowerNotify
5140  //
5143  m_PowerNotify.Flink->Blink = &m_PowerNotify;
5144  m_PowerNotify.Blink->Flink = &m_PowerNotify;
5145 
5146  // This is now empty
5148  }
5149  else {
5151  "Power Stop: WDFQUEUE 0x%p is powering off without "
5152  "in-flight requests",GetObjectHandle());
5153  }
5154 
5155  //
5156  // Return to main processing loop which will callback to
5157  // process notifications
5158  //
5159  return TRUE;
5160 
5161  case FxIoQueuePowerPurge:
5162  //
5163  // Set state to FxIoQueuePowerPurgeNotifyingDriver
5164  //
5166 
5167  // This should be empty on entry to this state
5168  ASSERT(IsListEmpty(&this->m_PowerNotify));
5169 
5170  if (!IsListEmpty(&m_DriverOwned)) {
5171 
5173  "Power Stop: WDFQUEUE 0x%p is purging with "
5174  "in-flight requests",GetObjectHandle());
5175 
5176  // Ensure the logic of m_DriverOwned is correct
5179 
5180  //
5181  // Move all requests on m_DriverOwned to m_PowerNotify
5182  //
5185  m_PowerNotify.Flink->Blink = &m_PowerNotify;
5186  m_PowerNotify.Blink->Flink = &m_PowerNotify;
5187 
5188  // This is now empty
5190  }
5191  else {
5193  "Power purge: WDFQUEUE 0x%p is purging without "
5194  "in-flight requests", GetObjectHandle());
5195  }
5196 
5197  //
5198  // Return to main processing loop which will callback to
5199  // process notifications
5200  //
5201  return TRUE;
5202 
5204 
5205  FxIoQueueIoStop stopCallback;
5206 
5207  //
5208  // If the list of requests to notify the driver about is
5209  // empty, change to the notified state.
5210  //
5211  if (IsListEmpty(&m_PowerNotify)) {
5213 
5214  //
5215  // Return to main processing loop which will callback to
5216  // process the wait/signaling for the driver to acknowledge
5217  // all stops.
5218  //
5219  return TRUE;
5220  }
5221 
5222  //
5223  // Notify each entry in m_PowerNotify into the driver
5224  //
5225 
5226  // Remove from the notify list, place it on the driver notified list
5228 
5230 
5231  // Retrieve the FxRequest
5233 
5234  stopCallback = m_IoStop;
5235 
5236  //
5237  // Notify driver by callback.
5238  //
5239  // If no callback is registered, the power thread will in effect
5240  // wait until the driver completes or cancels all requests.
5241  //
5242  if (stopCallback.Method != NULL && pRequest->m_Canceled == FALSE) {
5244 
5245  if(pRequest->IsInIrpQueue(&m_DriverCancelable)) {
5247  }
5248 
5250  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
5251  "Power Stop Notifying Driver, WDFQUEUE 0x%p, WDFREQUEST 0x%p",
5252  GetObjectHandle(), pRequest->GetObjectHandle());
5253 
5254  // Driver could be calling RequestComplete as we attempt to stop
5255  pRequest->ADDREF(FXREQUEST_HOLD_TAG);
5256 
5257  Unlock(*PreviousIrql);
5258 
5259  if (FxDriverGlobals->FxVerifierOn) {
5261  }
5262 
5263  stopCallback.Invoke(GetHandle(), pRequest->GetHandle(), ActionFlags);
5264 
5265  pRequest->RELEASE(FXREQUEST_HOLD_TAG);
5266 
5267  Lock(PreviousIrql);
5268  }
5269 
5270  //
5271  // As they are acknowledged, they will move back to m_DriverOwned.
5272  //
5273  // If the driver completes them, they go away.
5274  //
5275 
5276  // Return to main processing loop and continue processing notifications
5277  return TRUE;
5278  }
5279 
5281 
5282  FxIoQueueIoStop stopCallback;
5283 
5284  //
5285  // If the list of requests to notify the driver about is
5286  // empty, change to the notified state.
5287  //
5288  if (IsListEmpty(&m_PowerNotify)) {
5290 
5291  //
5292  // Return to main processing loop which will callback to
5293  // process the wait/signaling for the driver to acknowledge
5294  // all stops.
5295  //
5296  return TRUE;
5297  }
5298 
5299  //
5300  // Notify each entry in m_PowerNotify into the driver
5301  //
5302 
5303  // Remove from the notify list, place it on the driver notified list
5305 
5307 
5308  // Retrieve the FxRequest
5310 
5311  stopCallback = m_IoStop;
5312 
5313  //
5314  // Make sure power stop state is cleared before invoking the stop callback.
5315  //
5316  pRequest->ClearPowerStopState();
5317 
5318  //
5319  // Notify driver by callback.
5320  //
5321  // If no callback is registered, the power thread will in effect
5322  // wait until the driver completes or cancels all requests.
5323  //
5324  if (stopCallback.Method != NULL && pRequest->m_Canceled == FALSE) {
5326 
5327  if(pRequest->IsInIrpQueue(&m_DriverCancelable)) {
5329  }
5330 
5332  "Power Purge Notifying Driver "
5333  "WDFQUEUE 0x%p, WDFREQUEST 0x%p",
5334  GetObjectHandle(),pRequest->GetHandle());
5335 
5336  // Driver could be calling RequestComplete as we attempt to stop
5337  pRequest->ADDREF(FXREQUEST_HOLD_TAG);
5338 
5339  Unlock(*PreviousIrql);
5340 
5341  if (FxDriverGlobals->FxVerifierOn) {
5343  }
5344 
5345  stopCallback.Invoke(GetHandle(), pRequest->GetHandle(), ActionFlags);
5346 
5347  pRequest->RELEASE(FXREQUEST_HOLD_TAG);
5348 
5349  Lock(PreviousIrql);
5350  }
5351 
5352  //
5353  // As they are acknowledged, they will move back to m_DriverOwned.
5354  //
5355  // If the driver completes them, they go away.
5356  //
5357 
5358  // Return to main processing loop and continue processing notifications
5359  return TRUE;
5360  }
5361 
5364 
5365  PLIST_ENTRY thisEntry, nextEntry, listHead;
5366  LIST_ENTRY acknowledgedList;
5367  BOOLEAN continueProcessing = FALSE;
5368 
5369  InitializeListHead(&acknowledgedList);
5370 
5371  //
5372  // First move all the acknowledged requests to local list and then
5373  // process the local list. We have do that in two steps because
5374  // ProcessAcknowledgedRequests drops and reacquires the lock.
5375  //
5376  listHead = &m_PowerDriverNotified;
5377 
5378  for (thisEntry = listHead->Flink;
5379  thisEntry != listHead;
5380  thisEntry = nextEntry) {
5381 
5382  // Retrieve the FxRequest
5384 
5385  nextEntry = thisEntry->Flink;
5386 
5387  if (pRequest->IsPowerStopAcknowledged()) {
5388  RemoveEntryList(thisEntry);
5389  InsertTailList(&acknowledgedList, thisEntry);
5390  }
5391  }
5392 
5393  //
5394  // Process all the acknowledged request from the local list.
5395  //
5396  while (!IsListEmpty(&acknowledgedList))
5397  {
5398  thisEntry = RemoveHeadList(&acknowledgedList);
5400  ProcessAcknowledgedRequests(pRequest, PreviousIrql);
5401 
5402  //
5403  // When this function drops the lock, other threads may attempt
5404  // to dispatch but fail since we are currently dispatching.
5405  // We need to be sure to process any pending events that other
5406  // threads initiated but could not be dispatch. The acknowledged
5407  // list will eventually be cleared out, allowing exit paths from
5408  // this function to return control to the driver.
5409  //
5410  continueProcessing = TRUE;
5411  }
5412 
5413  //
5414  // Check to see if there are any unacknowledged requests.
5415  //
5417 
5418  //
5419  // If there are still entries on the list, we potentially return
5420  // FALSE to tell the main event dispatching loop to return to
5421  // the device driver, since we are awaiting response from
5422  // the driver while in this state.
5423  //
5424 
5426  "Power Stop: Waiting for Driver to complete or "
5427  "acknowledge in-flight requests on WDFQUEUE 0x%p",
5428  GetObjectHandle());
5429 
5430  return continueProcessing;
5431  }
5432 
5433  //
5434  // Check to see if there are any requests in the middle of two-phase-completion.
5435  // If so, bail out and wait.
5436  //
5437  if (m_TwoPhaseCompletions != 0) {
5438 
5440  "Power Stop: Waiting for Driver to complete or "
5441  "acknowledge in-flight requests on WDFQUEUE 0x%p",
5442  GetObjectHandle());
5443 
5444  return continueProcessing;
5445  }
5446 
5447  //
5448  // All the requests are acknowledged. We will signal the pnp thread waiting
5449  // in StopProcessingForPower to continue if we are the last one to visit
5450  // the dispatch event loop.
5451  //
5452  //
5453  if ( m_Dispatching == 1) {
5454 
5455  //
5456  // If we are the last routine actively dispatching callbacks to
5457  // the device driver under a Power stop, then we must set the
5458  // event specifying no more callbacks are active.
5459  //
5460 
5462  "Power Stop: WDFQUEUE 0x%p is now powered off with no "
5463  "in-flight requests",GetObjectHandle());
5464 
5466 
5467  m_PowerIdle.Set();
5468 
5469  return TRUE;
5470  }
5471 
5472  //
5473  // The driver has acknowledged all requests, and the
5474  // notification list is empty. But, there are still outstanding
5475  // dispatch calls into the driver (m_Dispatching != 1), so we potentially
5476  // return false here to hopefully unwind to the final dispatch routine,
5477  // which will set the power off state.
5478  //
5479 
5481  "Power Stop: Driver has acknowledged all in-flight "
5482  "requests, but WDFQUEUE 0x%p has outstanding callbacks",
5483  GetObjectHandle());
5484 
5485  return continueProcessing;
5486  }
5488 
5489  //
5490  // Power is being resumed to the device. We notify the
5491  // device driver by an event callback for all driver
5492  // owned requests that it has idled due to a previous
5493  // power stop.
5494  //
5496 
5497  // This should be empty on entry to this state
5498  ASSERT(IsListEmpty(&this->m_PowerNotify));
5499 
5500  if (!IsListEmpty(&m_DriverOwned)) {
5501 
5503  "Power Resume: Driver has power paused requests "
5504  "on WDFQUEUE 0x%p",GetObjectHandle());
5505 
5506  // Ensure the logic of m_DriverOwned is correct
5509 
5510  //
5511  // Move all requests on m_DriverOwned to m_PowerNotify
5512  //
5515  m_PowerNotify.Flink->Blink = &m_PowerNotify;
5516  m_PowerNotify.Blink->Flink = &m_PowerNotify;
5517 
5518  // This is now empty
5520  }
5521  else {
5523  "Power Resume: Driver has no power paused requests "
5524  "on WDFQUEUE 0x%p", GetObjectHandle());
5525  }
5526 
5527  //
5528  // Return to main processing loop which will callback to
5529  // process notifications
5530  //
5531  return TRUE;
5532 
5533 
5535 
5536  FxIoQueueIoResume resumeCallback;
5537 
5538  //
5539  // If the list of requests to notify the driver about is
5540  // empty, change to the notified state.
5541  //
5542  if (IsListEmpty(&m_PowerNotify)) {
5543 
5545 
5546  //
5547  // Return to main processing loop which will callback to
5548  // process the next state
5549  //
555