ReactOS 0.4.15-dev-8393-g61b7fb9
fxioqueue.cpp
Go to the documentation of this file.
1/*++
2
3Copyright (c) Microsoft Corporation
4
5Module Name:
6
7 FxIoQueue.cpp
8
9Abstract:
10
11 This module implements the FxIoQueue object and C interfaces
12
13Author:
14
15
16
17
18Revision History:
19
20
21
22
23--*/
24
25#include "ioprivshared.hpp"
26#include "fxioqueue.hpp"
27
28extern "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 ) :
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
91
94
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
123
125
127
131
134
138
139 return;
140}
141
143{
145
146 if (m_PkgIo != NULL) {
147 m_PkgIo = NULL;
148 }
149
160}
161
168 __in_opt FxDriver* Caller,
169 __in FxPkgIo* PkgIo,
170 __in BOOLEAN InitialPowerStateOn,
172 )
173{
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 //
194 Caller,
195 InitialPowerStateOn);
196 if (!NT_SUCCESS(status)) {
198 "Could not configure queue: %!STATUS!", status);
199 goto Done;
200 }
201Done:
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
220 __in_opt FxDriver* Caller,
221 __in BOOLEAN InitialPowerStateOn
222 )
223
224/*++
225
226Routine Description:
227
228 Initialize the IoQueue after creating.
229
230 This creates the handle required for passing to the driver.
231
232Arguments:
233
234Returns:
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,
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);
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!",
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!",
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
443
444 return STATUS_SUCCESS;
445}
446
449 )
450/*++
451
452Routine 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
457Arguments:
458
459Returns:
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
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(),
518 GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
520
521
523
526
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) {
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 //
562End:
563
564 FxNonPagedObject::Dispose(); // __super call
565
566 return TRUE;
567}
568
573 __in_opt FxDriver* Caller
574 )
575
576/*++
577
578Routine 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
584Arguments:
585
586Returns:
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
804VOID
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",
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) {
849 }
850 else {
851 DoTraceLevelMessage(FxDriverGlobals,
853 "WDFQUEUE 0x%p is shut down, preventing queue "
854 "from accepting requests",
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
881FX_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);
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)",
932
933 FxVerifierDbgBreakPoint(FxDriverGlobals);
934
935 // Allow them to continue, though this is a race condition in their driver
936 }
938
940}
941
942VOID
943FX_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
965 __deref_out FxRequest** pOutRequest
966 )
967/*++
968
969Routine 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
979Arguments:
980
981Returns:
982
983 NTSTATUS
984
985--*/
986{
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 //
1005 "Cannot be called on a parallel WDFQUEUE 0x%p, %!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!",
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!",
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 //
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
1086
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",
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",
1112
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 //
1148 UNREFERENCED_PARAMETER(oldState);
1149
1150 //
1151 // Track that we have given the request to the driver
1152 //
1153 VerifyGetRequestRestoreFlags(pFxDriverGlobals, pRequest);
1154
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
1178FX_VF_METHOD(FxIoQueue, VerifyPeekRequest) (
1179 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1181 )
1182{
1184 KIRQL irql;
1185
1187
1188 TagRequest->Lock(&irql);
1189 status = TagRequest->VerifyRequestIsTagRequest(FxDriverGlobals);
1191
1192 return status;
1193}
1194
1201 __deref_out FxRequest** pOutRequest
1202 )
1203/*++
1204
1205Routine 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
1225Arguments:
1226
1227Returns:
1228
1229 NTSTATUS
1230
1231--*/
1232
1233{
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 //
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 //
1310 }
1311
1312 // Return it to the driver
1313 *pOutRequest = pRequest;
1314
1315 return status;
1316}
1317
1318SHORT
1319FX_VF_METHOD(FxIoQueue, VerifyForwardRequestUpdateFlags) (
1320 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1322 )
1323{
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
1357 )
1358{
1360 FxRequestCompletionState oldState;
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 //
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);
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
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
1474FX_VF_METHOD(FxIoQueue, VerifyForwardRequestToParent) (
1475 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1478 )
1479{
1480 KIRQL irql;
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
1563Done:
1564 return status;
1565}
1566
1573 )
1574
1575/*++
1576
1577Routine 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
1598Arguments:
1599
1600Returns:
1601
1602 NTSTATUS
1603
1604--*/
1605{
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
1665FX_VF_METHOD(FxIoQueue, VerifyForwardRequest) (
1666 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1669 )
1670{
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!",
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
1715 )
1716/*++
1717
1718Routine 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
1739Arguments:
1740
1741Returns:
1742
1743 NTSTATUS
1744
1745--*/
1746{
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
1762FX_VF_METHOD(FxIoQueue, VerifyQueueDriverCreatedRequest) (
1763 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1766 )
1767{
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
1793 __in BOOLEAN ParentQueue
1794 )
1795/*++
1796
1797Routine 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
1814Arguments:
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
1821Returns:
1822
1823 NTSTATUS
1824
1825--*/
1826{
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
1904FX_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
1935 )
1936{
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 //
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 //
1968
1969 // Cancel the request complete callback (deletes a reference)
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 //
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 //
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
2046FX_VF_METHOD(FxIoQueue, VerifyRequestCancelable) (
2047 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
2050 )
2051{
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
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
2086Done:
2087 pRequest->Unlock(irql);
2088 return status;
2089}
2090
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{
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) {
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
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 {
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
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 //
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
2198
2199 //
2200 // Let the caller complete the request with STATUS_CANCELLED.
2201 //
2202 Unlock(irql);
2203
2204 if (FxDriverGlobals->FxVerifierOn) {
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);
2218
2219 if (NT_SUCCESS(status)) {
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)) {
2236 }
2237 }
2238
2239 return status;
2240 }
2241}
2242
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{
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()) {
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," : "",
2303
2304 // Must release IoQueue object Lock
2305 Unlock(irql);
2306
2308
2309 // Complete it with error
2311
2312 // Dereference request object
2314
2315 return Status;
2316 }
2317
2319 "Queuing WDFREQUEST 0x%p on WDFQUEUE 0x%p",
2321
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
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{
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," : "",
2396
2397 Unlock(irql);
2398
2399 return status;
2400 }
2401#if FX_VERBOSE_TRACE
2403 "Queuing WDFREQUEST 0x%p on WDFQUEUE 0x%p",
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 //
2423
2424 if (!NT_SUCCESS(status)) {
2425
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 //
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 {
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
2474VOID
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
2497
2499
2500 DispatchEvents(irql);
2501
2502 //
2503 // DispatchEvents drops the lock before returning. So reacquire the lock.
2504 //
2505 Lock(&irql);
2506
2509 } else {
2512 }
2513
2514 Unlock(irql);
2515
2516 return;
2517}
2518
2519VOID
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
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{
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
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
2632BOOLEAN
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",
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
2721 }
2722 }
2723
2724 return FALSE;
2725 }
2726
2727 return TRUE;
2728}
2729
2730_Releases_lock_(this->m_SpinLock.m_Lock)
2732BOOLEAN
2733FxIoQueue::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;
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) {
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
3103Done:
3104 m_Dispatching--;
3105 Unlock(PreviousIrql);
3106 return TRUE;
3107}
3108
3109VOID
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;
3136 FxRequestCompletionState oldState;
3137 WDFREQUEST hRequest;
3138 FxIrp* pIrp;
3139
3140 FxDriverGlobals = GetDriverGlobals();
3141
3142
3143
3144
3145
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 //
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
3176
3177 // Mark the request as being "owned" by the driver
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
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
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
3242
3244 "Calling driver EvtIoRead for WDFREQUEST 0x%p",
3245 hRequest);
3246
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
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
3281
3283 "Calling driver EvtIoWrite for WDFREQUEST 0x%p",
3285
3287 GetHandle(),
3288 hRequest,
3289 writeLength
3290 );
3291 }
3293
3295
3297 "Calling driver EvtIoDeviceControl for "
3298 "WDFREQUEST 0x%p", hRequest);
3299
3301 GetHandle(),
3302 hRequest,
3306 );
3307 }
3308
3310
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
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
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
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!",
3399 pRequest,
3400 Status);
3401
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 //
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//
3458 )
3459{
3460 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
3461 KIRQL irql;
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!",
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(),
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!",
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(),
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
3551VOID
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
3585 __in BOOLEAN CancelRequests,
3586 __in_opt PFN_WDF_IO_QUEUE_STATE IdleComplete,
3588 )
3589
3590/*++
3591
3592Routine 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
3603Arguments:
3604
3605Returns:
3606
3607--*/
3608
3609{
3611 KIRQL irql;
3613 LIST_ENTRY fwrIrpList = {0};
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!",
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 //
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 //
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
3839 __in BOOLEAN CancelRequests
3840 )
3841/*++
3842
3843Routine Description:
3844
3845 Idle the Queue and wait for the driver-owned requests to complete.
3846
3847Arguments:
3848
3849 CancelRequests - If TRUE, functions tries to cancel outstanding requests.
3850
3851Returns:
3852
3853--*/
3854{
3856#if (FX_CORE_MODE==FX_CORE_USER_MODE)
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(),
3881 GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
3883
3884
3885 Mx::MxLeaveCriticalRegion();
3886 }
3887
3888 return status;
3889
3890}
3891
3895 __in BOOLEAN CancelQueueRequests,
3896 __in BOOLEAN CancelDriverRequests,
3899 )
3900/*++
3901
3902Routine 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
3914Arguments:
3915
3916Returns:
3917
3918--*/
3919{
3921 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
3922 KIRQL irql;
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!",
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",
4020
4021 //
4022 // We must add a reference since the CancelForQueue path
4023 // assumes we were on the FxIrpQueue with the extra reference
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
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 //
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
4108 )
4109/*++
4110
4111Routine 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{
4120
4121#if (FX_CORE_MODE==FX_CORE_USER_MODE)
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(),
4146 GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
4148
4149 Mx::MxLeaveCriticalRegion();
4150 }
4151
4152 return status;
4153
4154}
4155
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
4178 )
4179/*++
4180
4181Routine 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{
4190#if (FX_CORE_MODE==FX_CORE_USER_MODE)
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(),
4215 GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec,
4217
4218 Mx::MxLeaveCriticalRegion();
4219 }
4220
4221 return status;
4222
4223}
4224
4225
4226VOID
4228 __out_opt PULONG pQueuedRequests,
4229 __out_opt PULONG pDriverPendingRequests
4230 )
4231/*++
4232
4233Routine Description:
4234
4235 Return the count of requests currently on the queue
4236 and owned by the driver.
4237
4238Arguments:
4239
4240Returns:
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
4255VOID
4258 )
4259/*++
4260
4261Routine 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
4272Return Value:
4273
4274--*/
4275{
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 //
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)
4328VOID
4329FxIoQueue::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);
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
4412
4413 Lock(&PreviousIrql);
4414 }
4415
4416 // This may have caused the queue to be emptied
4417 DispatchInternalEvents(PreviousIrql);
4418
4419 return;
4420}
4421
4422VOID
4425 __in MdIrp Irp,
4426 __in PMdIoCsqIrpContext CsqContext,
4428 )
4429/*++
4430
4431Routine 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
4437Arguments:
4438 IrpQueue - Queue the request was on
4439
4440 Irp - the irp being cancelled
4441
4442 CsqContext - the context associated with the irp
4443
4444Return 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
4474VOID
4475FX_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
4507VOID
4508FX_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
4534VOID
4537 )
4538/*++
4539
4540Routine 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
4548Arguments:
4549
4550 pRequest - is a driver owned cancelable request.
4551
4552Return 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
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
4613VOID
4616 __in MdIrp Irp,
4617 __in PMdIoCsqIrpContext CsqContext,
4619 )
4620/*++
4621
4622Routine 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
4628Arguments:
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
4636Return Value:
4637 None
4638
4639 --*/
4640{
4641 FxIoQueue* ioQueue;
4643
4646
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
4668VOID
4669FxIoQueue::ProcessIdleComplete(
4670 __out PKIRQL PreviousIrql
4671 )
4672/*++
4673
4674Routine 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
4681Arguments:
4682 IrpQueue - Queue the request was on
4683
4684 Irp - the irp being cancelled
4685
4686 CsqContext - the context associated with the irp
4687
4688Return Value:
4689 None
4690
4691 --*/
4692{
4693 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4696
4697
4700
4703
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
4716
4717 return;
4718}
4719
4721VOID
4722FxIoQueue::ProcessPurgeComplete(
4723 __out PKIRQL PreviousIrql
4724 )
4725/*++
4726
4727Routine 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
4738Arguments:
4739
4740Return Value:
4741 None
4742
4743 --*/
4744{
4745 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4748
4751
4754
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
4767
4768 return;
4769}
4770
4772VOID
4773FxIoQueue::ProcessReadyNotify(
4774 __out PKIRQL PreviousIrql
4775 )
4776/*++
4777
4778Routine 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
4784Arguments:
4785
4786Return Value:
4787 None
4788
4789 --*/
4790{
4791 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
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
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
4829
4830 return;
4831}
4832
4834BOOLEAN
4835FxIoQueue::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",
4882
4883 if (FxDriverGlobals->FxVerifierOn) {
4884
4885 // Set cancelled status, otherwise verifier in FxRequest::Complete will complain
4887 }
4888
4890
4891 if (FxDriverGlobals->FxVerifierOn) {
4893 }
4894
4895 //
4896 // Notify the driver of cancel desire
4897 //
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
4912 }
4913
4914 return TRUE;
4915}
4916
4918BOOLEAN
4919FxIoQueue::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
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",
4966
4967 if (FxDriverGlobals->FxVerifierOn) {
4968
4969 // Set cancelled status, otherwise verifier in FxRequest::Complete will complain
4971 }
4972
4974
4975 if (FxDriverGlobals->FxVerifierOn) {
4977 }
4978
4979 //
4980 // Notify the driver
4981 //
4983
4985 }
4986
4987 return TRUE;
4988}
4989
4991BOOLEAN
4992FxIoQueue::ProcessPowerEvents(
4993 __out PKIRQL PreviousIrql
4994 )
4995/*++
4996
4997Routine 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
5088Arguments:
5089
5090Return 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
5125
5126 if (!IsListEmpty(&m_DriverOwned)) {