ReactOS 0.4.15-dev-7942-gd23573b
fxobjectstatemachine.cpp
Go to the documentation of this file.
1/*++
2
3Copyright (c) Microsoft Corporation
4
5Module Name:
6
7 FxObjectStateMachine.cpp
8
9Abstract:
10
11 This module contains the implementation of the base object's state machine.
12
13Author:
14
15
16
17
18
19Environment:
20
21 Both kernel and user mode
22
23Revision History:
24
25
26
27
28
29
30
31
32--*/
33
34#include "fxobjectpch.hpp"
35
36extern "C" {
37
38#if defined(EVENT_TRACING)
39#include "FxObjectStateMachine.tmh"
40#endif
41
42}
43
44VOID
46 VOID
47 )
48/*++
49
50Routine Description:
51 This is a public method that is called on an object to request that it Delete.
52
53Arguments:
54 None
55
56Returns:
57 NTSTATUS
58
59--*/
60{
62 KIRQL oldIrql;
64
65 m_SpinLock.Acquire(&oldIrql);
66
68
69 // This method should only be called once per object
71 UNREFERENCED_PARAMETER(result); //for fre build
72
73 //
74 // Perform the right action based on the objects current state
75 //
76 switch(m_ObjectState) {
78 //
79 // If we have a parent object, notify it of our deletion
80 //
81 if (m_ParentObject != NULL) {
82 //
83 // We call this holding our spinlock, the hierachy is child->parent
84 // when the lock is held across calls
85 //
87
89
90 //
91 // We won the race to ourselves (still FxObjectStateCreated),
92 // but lost the race on the parent who is going to try and
93 // dispose us through the ParentDeleteEvent().
94 //
95 // This is OK since the state machine protects us from
96 // doing improper actions, but we must not rundown and
97 // release our reference count till the parent object
98 // eventually calls our ParentDeleteEvent().
99 //
100 // So we note the state, and return waiting for the
101 // parent to dispose us.
102 //
103
104 //
105 // Wait for our parent to come in and dispose us through
106 // the ParentDeleteEvent().
107 //
109 m_SpinLock.Release(oldIrql);
110 break;
111 }
112 else {
113 //
114 // We no longer have a parent object
115 //
117 }
118 }
119
120 //
121 // Start Dispose, do delete state machine
122 // returns with m_SpinLock released
123 //
124 DeleteWorkerAndUnlock(oldIrql, TRUE);
125 break;
126
128
129 if (m_ParentObject != NULL) {
131
134 m_SpinLock.Release(oldIrql);
135 break;
136 }
137 else {
138 //
139 // We no longer have a parent object
140 //
142 }
143 }
144
145 //
146 // This will release the spinlock
147 //
148 DeletedAndDisposedWorkerLocked(oldIrql);
149 break;
150
153 case FxObjectStateDeletedDisposing: // Do nothing, workitem will move into disposed and deleted
154 case FxObjectStateDeletedAndDisposed: // Do nothing, already deleted
156 m_SpinLock.Release(oldIrql);
157 break;
158
159 // These are bad states for this event
163 default:
165 // Bad state
166 ASSERT(FALSE);
167 m_SpinLock.Release(oldIrql);
168 }
169}
170
171VOID
173 VOID
174 )
175/*++
176
177Routine Description:
178 Deletes an object which has already been explicitly early disposed.
179
180Arguments:
181 None
182
183Return Value:
184 None
185
186 --*/
187{
189
192
194 ASSERT(result);
195 UNREFERENCED_PARAMETER(result); //for fre build
196
197 if (m_ParentObject != NULL) {
199 KIRQL irql;
200
201 m_SpinLock.Acquire(&irql);
202
203 if (m_ParentObject != NULL) {
205
208 m_SpinLock.Release(irql);
209 return;
210 }
211 else {
212 //
213 // We no longer have a parent object
214 //
216 }
217 }
218
219 m_SpinLock.Release(irql);
220 }
221
222 //
223 // This will release the spinlock
224 //
225 DeletedAndDisposedWorkerLocked(PASSIVE_LEVEL, FALSE);
226}
227
230 VOID
231 )
232/*++
233
234Routine Description:
235 This is a virtual function overriden by sub-classes if they want
236 Dispose notifications.
237
238Arguments:
239 None
240
241Returns:
242 TRUE if the registered cleanup routines on this object should be called
243 when this funciton returns
244
245--*/
246{
247 return TRUE;
248}
249
250VOID
252 VOID
253 )
254{
255 FxTagTracker* pTagTracker;
256
257 //
258 // Set the debug info to NULL so that we don't use it after the
259 // SelfDestruct call. Setting the DestroyFunction to NULL
260 // will also prevent reuse of the REF_OBJ after it has been destroyed.
261 //
262 pTagTracker = GetTagTracker();
263
264 //
265 // We will free debug info later. It useful to hang on to the debug
266 // info after the destructor has been called for debugging purposes.
267 //
268 if (pTagTracker != NULL) {
269 pTagTracker->CheckForAbandondedTags();
270 }
271
272 //
273 // Call the destroy callback *before* any desctructor is called. This
274 // way the callback has access to a full fledged object that hasn't been
275 // cleaned up yet.
276 //
277 // We only do this for committed objects. A non committed object will
278 // *NOT* have additional contexts to free.
279 //
280 if (m_ObjectSize > 0 && IsCommitted()) {
281 FxContextHeader* pHeader, *pNext;
282 WDFOBJECT h;
284
285 //
286 // We are getting the object handle when the ref count is zero. We
287 // don't want to ASSERT in this case.
288 //
290
291
292
293
294
295
296
297
298
299
300
301
302
303 for (pHeader = GetContextHeader();
304 pHeader != NULL;
306
307 //
308 // Cleanup *may* have been called earlier in the objects
309 // destruction, and in this case the EvtCleanupCallback will
310 // be set to NULL. Ensuring its always called provides
311 // symmetry to the framework.
312 //
313
314 //
315 // No need to interlockexchange out the value of
316 // EvtCleanupCallback because any codepath that might be calling
317 // CallCleanup must have a valid reference and no longer have
318 // any outstanding references
319 //
323 }
324
328 }
329 }
330
331 first = TRUE;
332 for (pHeader = GetContextHeader(); pHeader != NULL; pHeader = pNext) {
333
334 pNext = pHeader->NextHeader;
335
336 //
337 // The first header is embedded, so it will be freed with the
338 // object
339 //
340 if (first == FALSE) {
342 }
343
344 first = FALSE;
345 }
346 }
347
348
349
350
351
352
353
354
355
356
357 //
358 // NOTE: The delete of the tag tracker *MUST* occur before the SelfDestruct()
359 // of this object. The tag tracker has a back pointer to this object which
360 // it dereferences in its own destructor. If SelfDestruct() is called
361 // first, then ~FxTagTracker will touch freed pool and bugcheck.
362 //
363 if (pTagTracker != NULL) {
365 delete pTagTracker;
366 }
367
368 //
369 // See NOTE above.
370 //
371 SelfDestruct();
372}
373
376 VOID
377 )
378/*++
379
380Routine Description:
381 Public early dipose functionality. Removes the object from the parent's
382 list of children. This assumes the caller or someone else will eventually
383 invoke DeleteObject() on this object.
384
385Arguments:
386 None
387
388Return Value:
389 BOOLEAN - same semantic as DisposeChildrenWorker.
390 TRUE - dispose of this object and its children occurred synchronously in
391 this call
392 FALSE - the dispose was pended to a work item
393
394 --*/
395{
397 KIRQL oldIrql;
399
400 //
401 // By default, we assume a synchronous diposal
402 //
403 result = TRUE;
404
405 m_SpinLock.Acquire(&oldIrql);
406
407 switch(m_ObjectState) {
409 //
410 // If we have a parent object, notify it of our deletion
411 //
412 if (m_ParentObject != NULL) {
413 //
414 // We call this holding our spinlock, the hierachy is child->parent
415 // when the lock is held across calls
416 //
418
420
421 //
422 // We won the race to ourselves (still FxObjectStateCreated),
423 // but lost the race on the parent who is going to try and
424 // dispose us through the PerformEarlyDipose().
425 //
426 // This is OK since the state machine protects us from
427 // doing improper actions, but we must not rundown and
428 // release our reference count till the parent object
429 // eventually calls our ParentDeleteEvent().
430 //
431 // So we note the state, and return waiting for the
432 // parent to dispose us.
433 //
434
435 //
436 // Wait for our parent to come in and dispose us through
437 // the PerformEarlyDipose().
438 //
440 m_SpinLock.Release(oldIrql);
441
442 return FALSE;
443 }
444 else {
445 //
446 // We no longer have a parent object
447 //
449 }
450 }
451
452 //
453 // Mark that this object was early disposed externally wrt the
454 // state machine.
455 //
457
458 //
459 // Start the dispose path. This call will release the spinlock.
460 //
461 result = PerformEarlyDisposeWorkerAndUnlock(oldIrql, TRUE);
462 break;
463
464 default:
465 //
466 // Not in the right state for an early dispose
467 //
468 result = FALSE;
469 m_SpinLock.Release(oldIrql);
470 }
471
472 return result;
473}
474
477 VOID
478 )
479/*++
480
481Routine Description:
482 Allows Dispose() processing on an object to occur before calling DeleteObject().
483
484Arguments:
485 CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are
486 incorrect. If FALSE, the caller has guaranteed that we are at
487 the correct IRQL
488
489Returns:
490 None
491
492--*/
493{
494 KIRQL oldIrql;
496
497 //
498 // By default we assume that the dispose was synchronous
499 //
500 result = TRUE;
501
502
503 //
504 // It's OK for an object to already be disposing due to
505 // a parent delete call.
506 //
507 // To check for verifier errors in which two calls to
508 // PerformEarlyDispose() occur, a separate flag is used
509 // rather than complicating the state machine.
510 //
511 m_SpinLock.Acquire(&oldIrql);
512
513 //
514 // Perform the right action based on the objects current state
515 //
516 switch(m_ObjectState) {
518 //
519 // Start dispose, move into Disposing state
520 // returns with m_SpinLock released
521 //
522 result = PerformEarlyDisposeWorkerAndUnlock(oldIrql, FALSE);
523 break;
524
526 //
527 // Start the dispose path.
528 //
529 result = PerformEarlyDisposeWorkerAndUnlock(oldIrql, FALSE);
530 break;
531
533 //
534 // We should only get an early dispose in this state once we have thunked
535 // to passive level via the dispose list.
536 //
537 result = PerformDisposingDisposeChildrenLocked(oldIrql, FALSE);
538 break;
539
540 case FxObjectStateWaitingForParentDeleteAndDisposed: // Do nothing, parent object will delete and dispose
541 case FxObjectStateDisposed: // Do nothing
542 case FxObjectStateDisposingEarly: // Do nothing
543 case FxObjectStateDeletedDisposing: // Do nothing, workitem will moved into disposed
546 m_SpinLock.Release(oldIrql);
547 break;
548
549 // These are bad states for this event
552
553 default:
555 // Bad state
556 ASSERT(FALSE);
557 m_SpinLock.Release(oldIrql);
558 break;
559 }
560
561 return result;
562}
563
567 VOID
568 )
569/*++
570
571Routine Description:
572 Remove the current objects ParentObject.
573
574Arguments:
575 None
576
577Returns:
578 NTSTATUS of action
579
580--*/
581{
582 KIRQL oldIrql;
584
585 m_SpinLock.Acquire(&oldIrql);
586
587 //
588 // Object is already being deleted, this object will be removed as a child
589 // by the parents Dispose()
590 //
593 m_SpinLock.Release(oldIrql);
595 }
596
597 // We should have a parent
599
601 if (NT_SUCCESS(status)) {
603 }
604
605 m_SpinLock.Release(oldIrql);
606
607 return status;
608}
609
610VOID
612 VOID
613 )
614/*++
615
616Routine Description:
617
618 This is invoked by the parent object when it is Dispose()'ing us.
619
620Arguments:
621 None
622
623Returns:
624 None
625
626--*/
627{
628 KIRQL oldIrql;
629
630 //
631 // Note: It's ok for an object to already be in the delete
632 // state since there can be an allowed race between
633 // parent disposing an object, and the DeleteObject()
634 // call on the object itself.
635 //
636 m_SpinLock.Acquire(&oldIrql);
637
638 //
639 // We no longer have a parent object
640 //
642
643 //
644 // Perform the right action based on the objects current state
645 //
646 switch(m_ObjectState) {
649 //
650 // This will release the spinlock
651 //
652 DeletedAndDisposedWorkerLocked(oldIrql, TRUE);
653 break;
654
656 //
657 // Do nothing, workitem will move into disposed
658 //
660 m_SpinLock.Release(oldIrql);
661 break;
662
663 case FxObjectStateDeletedAndDisposed: // Do nothing, already deleted
664 m_SpinLock.Release(oldIrql);
665 break;
666
668 //
669 // In the process of deleting, ignore it
670 //
671 m_SpinLock.Release(oldIrql);
672 break;
673
674 // These are bad states for this event
675
676
677
678
679
682
685 default:
686 //
687 // Bad state
688 //
689 ASSERT(FALSE);
690 m_SpinLock.Release(oldIrql);
691 break;
692 }
693}
694
695VOID
697 VOID
698 )
699/*++
700
701Routine Description:
702 Invoked by deferred dispose workitem. This is invoked at PASSIVE_LEVEL,
703 and returns at PASSIVE_LEVEL
704
705Arguments:
706 None
707
708Return Value:
709 None
710
711 --*/
712{
713 KIRQL oldIrql;
715
716 destroy = FALSE;
717
718 m_SpinLock.Acquire(&oldIrql);
719
720 ASSERT(oldIrql == PASSIVE_LEVEL);
721
722 //
723 // Perform the right action based on the objects current state
724 //
725 // DisposeChildrenWorker return result can be ignored because we are
726 // guaranteed to be calling it at PASSIVE.
727 //
728 switch (m_ObjectState) {
730 //
731 // This will drop the spinlock and move the object to the right state
732 // before returning.
733 //
734 result = PerformDisposingDisposeChildrenLocked(oldIrql, FALSE);
735
736 //
737 // The substree should never defer to the dispose list if we pass FALSE.
738 //
739 ASSERT(result);
740 UNREFERENCED_PARAMETER(result); //for fre build
741
742 return;
743
746 result = DisposeChildrenWorker(FxObjectStateDeferedDeleting, oldIrql, FALSE);
747 ASSERT(result);
748 UNREFERENCED_PARAMETER(result); //for fre build
749
750 //
751 // This will release the spinlock
752 //
753 DeletedAndDisposedWorkerLocked(oldIrql, FALSE);
754 return;
755
757 // Perform final destroy actions now that we are at passive level
758 destroy = TRUE;
759 break;
760
761 // These are bad states for this event
762 case FxObjectStateDeletedAndDisposed: // Do nothing
769
770 default:
771 // Bad state
772 ASSERT(FALSE);
773 break;
774 }
775
776 m_SpinLock.Release(oldIrql);
777
778 if (destroy) {
780 }
781}
782
783_Releases_lock_(this->m_SpinLock.m_Lock)
786FxObject::PerformDisposingDisposeChildrenLocked(
788 __in BOOLEAN CanDefer
789 )
790/*++
791
792Routine Description:
793 This is entered with m_SpinLock held, and returns with it released.
794
795Arguments:
796 OldIrql - the IRQL before m_SpinLock was acquired
797
798 CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are
799 incorrect. If FALSE, the caller has guaranteed that we are at
800 the correct IRQL
801
802Return Value:
803 BOOLEAN - same semantic as DisposeChildrenWorker.
804 TRUE - delete of this object and its children occurred synchronously in
805 this call
806 FALSE - the delete was pended to a work item
807
808 --*/
809{
810 static const USHORT edFlags = (FXOBJECT_FLAGS_DELETECALLED |
812
813 SetObjectStateLocked(FxObjectStateDisposingDisposeChildren);
814
815 if (DisposeChildrenWorker(FxObjectStateDeferedDisposing, OldIrql, CanDefer)) {
816 //
817 // Upon returning TRUE, the lock is still held
818 //
819
820 //
821 // If this object was early disposed externally, destroy the children
822 // immediately (FxRequest relies on this so that the WDFMEMORYs created
823 // for probed and locked buffers are freed before the request is
824 // completed.)
825 //
826 // Otherwise, wait for DeleteObject or ParentDeleteEvent() to occur.
827 //
828 if ((m_ObjectFlags & edFlags) == edFlags) {
829 //
830 // This will drop the lock
831 //
832 DeletedAndDisposedWorkerLocked(OldIrql, FALSE);
833 }
834 else {
835 //
836 // Will wait for the parent deleted event
837 //
838 SetObjectStateLocked(FxObjectStateDisposed);
839 }
840
841 return TRUE;
842 }
843 else {
844 //
845 // Upon return FALSE, the lock was released and a work item was
846 // queued to dispose of children at passive level
847 //
848 DO_NOTHING();
849
850 return FALSE;
851 }
852}
853
854_Releases_lock_(this->m_SpinLock.m_Lock)
857FxObject::PerformEarlyDisposeWorkerAndUnlock(
859 __in BOOLEAN CanDefer
860 )
861/*++
862
863Routine Description:
864 This is entered with m_SpinLock held, and returns with it released.
865
866Arguments:
867 OldIrql - the previous IRQL before the object lock was acquired
868
869 CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are
870 incorrect. If FALSE, the caller has guaranteed that we are at
871 the correct IRQL
872
873Return Value:
874 BOOLEAN - same semantic as DisposeChildrenWorker.
875 TRUE - delete of this object and its children occurred synchronously in
876 this call
877 FALSE - the delete was pended to a work item
878
879 --*/
880{
881 ASSERT(m_ObjectState == FxObjectStateCreated ||
882 m_ObjectState == FxObjectStateWaitingForEarlyDispose);
883
884 SetObjectStateLocked(FxObjectStateDisposingEarly);
885
886 if (CanDefer && ShouldDeferDisposeLocked(&OldIrql)) {
887 QueueDeferredDisposeLocked(FxObjectStateDeferedDisposing);
888 m_SpinLock.Release(OldIrql);
889
890 return FALSE;
891 }
892 else {
893 return PerformDisposingDisposeChildrenLocked(OldIrql, CanDefer);
894 }
895}
896
897_Releases_lock_(this->m_SpinLock.m_Lock)
900FxObject::DeleteWorkerAndUnlock(
902 __in BOOLEAN CanDefer
903 )
904/*++
905
906Routine Description:
907 This is entered with m_SpinLock held, and returns with it released.
908
909
910Arguments:
911 OldIrql - the IRQL before m_SpinLock was acquired
912
913 CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are
914 incorrect. If FALSE, the caller has guaranteed that we are at
915 the correct IRQL
916
917Return Value:
918 BOOLEAN - same semantic as DisposeChildrenWorker.
919 TRUE - delete of this object and its children occurred synchronously in
920 this call
921 FALSE - the delete was pended to a work item
922
923 --*/
924{
925 ASSERT(m_ObjectState == FxObjectStateCreated);
926 // m_ObjectState == FxObjectStateWaitingForParentDelete);
927
928 if (CanDefer && ShouldDeferDisposeLocked(&OldIrql)) {
929 QueueDeferredDisposeLocked(FxObjectStateDeferedDeleting);
930 m_SpinLock.Release(OldIrql);
931
932 return FALSE;
933 }
934 else {
935 SetObjectStateLocked(FxObjectStateDeletedDisposing);
936
937 if (DisposeChildrenWorker(FxObjectStateDeferedDeleting, OldIrql, CanDefer)) {
938 //
939 // This will release the spinlock
940 //
941 DeletedAndDisposedWorkerLocked(OldIrql, FALSE);
942
943 return TRUE;
944 }
945 else {
946 //
947 // Upon return FALSE, the lock was released and a work item was
948 // queued to dispose of children at passive level
949 //
950 DO_NOTHING();
951
952 return FALSE;
953 }
954 }
955}
956
957VOID
959 __in FxObjectState NewDeferedState
960 )
961/*++
962
963Routine Description:
964 Queues this object onto a work item list which will dispose it at passive
965 level. The work item will be owned by the parent device or driver.
966
967 This is called with the object's m_SpinLock held.
968
969 NOTE: This function only looks at this object and the parent to attempt to
970 find the owning FxDeviceBase*. If this is a deeper hierarchy, the deeply
971 rooted FxDeviceBase will not be used.
972
973Arguments:
974 Parent - the parent of this objec (it may have already been removed from
975 m_ParentObject, so we can't use that field
976
977Return Value:
978 None
979
980 --*/
981{
982 //
983 // Queue workitem, which will run DisposeChildrenWorker()
984 //
987
988 SetObjectStateLocked(NewDeferedState);
989
990 //FxToObjectItf::FxAddToDisposeList(m_DeviceBase, m_Globals, this);
991 if (m_DeviceBase != NULL) {
993 }
994 else {
996 }
997}
998
999_Releases_lock_(this->m_SpinLock.m_Lock)
1001BOOLEAN
1002FxObject::DisposeChildrenWorker(
1003 __in FxObjectState NewDeferedState,
1005 __in BOOLEAN CanDefer
1006 )
1007
1008/*++
1009
1010Routine Description:
1011
1012 Rundown list of child objects removing their entries and invoking
1013 their ParentDeleteEvent() on them.
1014
1015 This is called with the m_SpinLock held and upon returning the lock is
1016 released.
1017
1018Arguments:
1019 NewDeferedState - If the state transition requires defering to a dispose
1020 list, this is the new state to move to
1021
1022 OldIrql - the previous IRQL when the caller acquired the object's lock
1023
1024 CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are
1025 incorrect. If FALSE, the caller has guaranteed that we are at
1026 the correct IRQL
1027
1028Returns:
1029 TRUE: Dispose is completed in this function.
1030 FALSE: Dispose is deferred either to a workitem (if CanDefer is TRUE) or will
1031 be done later in the current thread (if CanDefer is FALSE).
1032
1033 In either case lock is released.
1034
1035 If the OldIrql == PASSIVE_LEVEL, TRUE is guaranteed to be returned
1036
1037Comments:
1038
1039 This routine is entered with the spinlock held, and may return with it released.
1040
1041 The state machine ensures that this is only invoked once in
1042 an objects lifetime, regardless of races between PerformEarlyDispose,
1043 DeleteObject, or a ParentDeleteEvent. If there are requirements for passive
1044 level dispose and the previous IRQL is != PASSIVE, this function will be
1045 called twice, the first at IRQL > PASSIVE, the second at PASSIVE.
1046
1047 Top level code has ensured this is invoked under the right IRQL level
1048 for the object to perform the Dispose() callbacks.
1049
1050--*/
1051{
1052 LIST_ENTRY *ple;
1053 FxObject* childObject;
1054
1055 //
1056 // Called from:
1057 //
1058 // DeferredDisposeWorkItem (will complete, and release in current thread)
1059 // PerformDisposeWorkerAndUnlock(PerformEarlyDispose), no release, but possible thread deferral
1060 // DeleteWorkerAndUnlock (will release, but may defer, its logic must change!)
1061 //
1062
1063 ASSERT((m_ObjectState == FxObjectStateDisposingDisposeChildren) ||
1064 (m_ObjectState == FxObjectStateDeletedDisposing));
1065
1066 //
1067 // This routine will attempt to dispose as many children as possible
1068 // in the current thread. It may have to stop if the thread is
1069 // not at PASSIVE_LEVEL when the object spinlock was acquired, and
1070 // a child object is marked as a passive level object.
1071 //
1072 // If this occurs, dispose processing is suspended and resumed in
1073 // a passive level workitem, which calls this routine back to
1074 // complete the processing.
1075 //
1076 // Once all child object's Dispose() callback has returned, we then
1077 // can call Dispose() on the parent object.
1078 //
1079 // This must be done in this order to guarantee the contract with the
1080 // device driver (and internal object system) that all child
1081 // EvtObjectCleanup callbacks have returned before their parents
1082 // EvtObjectCleanup event.
1083 //
1084 // This is important to avoid extra references
1085 // when child objects expect their parent object to be valid until
1086 // EvtObjectCleanup is called.
1087 //
1088
1089 // Rundown list removing entries and calling Dispose on child objects
1090
1091 //
1092 // If this object requires being forced onto the dispose thread, do it now
1093 //
1094 if (IsForceDisposeThreadLocked() && OldIrql != PASSIVE_LEVEL) {
1095 //
1096 // Workitem will re-run this function at PASSIVE_LEVEL
1097 //
1098 if (CanDefer) {
1099 QueueDeferredDisposeLocked(NewDeferedState);
1100 }
1101 else {
1102 SetObjectStateLocked(NewDeferedState);
1103 }
1104
1105 m_SpinLock.Release(OldIrql);
1106
1107 return FALSE;
1108 }
1109
1110 for (ple = m_ChildListHead.Flink;
1111 ple != &m_ChildListHead;
1112 ple = ple->Flink) {
1113 //
1114 // Before removing the child object, we need to see if we need to defer
1115 // to a work item to dispose the child.
1116 //
1117 childObject = CONTAINING_RECORD(ple, FxObject, m_ChildEntry);
1118
1119 //
1120 // Should not associate with self
1121 //
1122 ASSERT(childObject != this);
1123
1124 //
1125 // If current threads IRQL before acquiring the spinlock is not
1126 // passive, and the child object is passive constrained, we must
1127 // defer the current disposal processing to a workitem.
1128 //
1129 // We stay in the Disposing state, which this routine will continue
1130 // processing when called back from the workitem.
1131 //
1132 // This code is re-entered at the proper passive_level to complete
1133 // processing where it left off (at the head of the m_ChildListHead).
1134 //
1135 if (OldIrql != PASSIVE_LEVEL && childObject->IsPassiveDisposeLocked()) {
1136 //
1137 // Workitem will re-run this function at PASSIVE_LEVEL
1138 //
1139 if (CanDefer) {
1140 QueueDeferredDisposeLocked(NewDeferedState);
1141 }
1142 else {
1143 SetObjectStateLocked(NewDeferedState);
1144 }
1145 m_SpinLock.Release(OldIrql);
1146
1147 return FALSE;
1148 }
1149 }
1150
1151 m_SpinLock.Release(OldIrql);
1152
1153 for (ple = m_ChildListHead.Flink; ple != &m_ChildListHead; ple = ple->Flink) {
1154 childObject = CONTAINING_RECORD(ple, FxObject, m_ChildEntry);
1155
1156 //
1157 // Inform child object of disposal. We will release the reference on
1158 // the child only after we have disposed ourself.
1159 //
1160 if (childObject->PerformEarlyDispose() == FALSE) {
1161
1162 m_SpinLock.Acquire(&OldIrql);
1163 if (CanDefer) {
1164 QueueDeferredDisposeLocked(NewDeferedState);
1165 }
1166 else {
1167 SetObjectStateLocked(NewDeferedState);
1168 }
1169 m_SpinLock.Release(OldIrql);
1170
1171 return FALSE;
1172 }
1173
1174 ASSERT(childObject->GetRefCnt() > 0);
1175 }
1176
1177 //
1178 // Call Dispose virtual callback on ourselves for benefit
1179 // of sub-classes if it is overridden.
1180 //
1181 if ((m_ObjectFlags & FXOBJECT_FLAGS_DISPOSE_OVERRIDE) == 0x00 || Dispose()) {
1182 //
1183 // Now call Cleanup on any handle context's exposed
1184 // to the device driver.
1185 //
1186 CallCleanup();
1187 }
1188
1189 return TRUE;
1190}
1191
1192//
1193// Despite the name this function may not always be called with lock held
1194// but if Unlock is TRUE, lock must be held.
1195//
1196_When_(Unlock, _Releases_lock_(this->m_SpinLock.m_Lock))
1198VOID
1199FxObject::DeletedAndDisposedWorkerLocked(
1202 )
1203{
1204 SetObjectStateLocked(FxObjectStateDeletedAndDisposed);
1205
1206 if (Unlock) {
1207 m_SpinLock.Release(OldIrql);
1208 }
1209
1210 DestroyChildren();
1211
1212 //
1213 // Release the final reference on the object
1214 //
1215 RELEASE(NULL);
1216}
1217
unsigned char BOOLEAN
void destroy(_Tp *__pointer)
Definition: _construct.h:278
LONG NTSTATUS
Definition: precomp.h:26
VOID AddToDisposeList(__inout FxObject *Object)
Definition: fxdevice.hpp:387
VOID Add(FxObject *object)
__inline FxDisposeList * GetDisposeList()
Definition: fxdriver.hpp:354
FxObjectDebugExtension * GetDebugExtension(VOID)
Definition: fxobject.hpp:401
USHORT m_ObjectState
Definition: fxobject.hpp:290
VOID QueueDeferredDisposeLocked(__in FxObjectState NewDeferedState)
USHORT m_ObjectSize
Definition: fxobject.hpp:254
PFX_DRIVER_GLOBALS m_Globals
Definition: fxobject.hpp:259
BOOLEAN MarkDeleteCalledLocked(VOID)
Definition: fxobject.hpp:1345
_Must_inspect_result_ NTSTATUS RemoveParentAssignment(VOID)
MxLock m_SpinLock
Definition: fxobject.hpp:296
VOID ParentDeleteEvent(VOID)
_Must_inspect_result_ NTSTATUS RemoveChildObjectInternal(__in FxObject *ChildObject)
Definition: fxobject.cpp:770
virtual VOID DeleteObject(VOID)
BOOLEAN IsPassiveDisposeLocked(VOID)
Definition: fxobject.hpp:1367
PVOID __inline GetObjectHandleUnchecked(VOID)
Definition: fxobject.hpp:446
USHORT m_ObjectFlags
Definition: fxobject.hpp:263
VOID DeferredDisposeWorkItem(VOID)
VOID __inline TraceDroppedEvent(__in FxObjectDroppedEvent Event)
Definition: fxobject.hpp:930
FxObject * m_ParentObject
Definition: fxobject.hpp:303
CfxDeviceBase * m_DeviceBase
Definition: fxobject.hpp:328
VOID DeleteEarlyDisposedObject(VOID)
LONG GetRefCnt(VOID)
Definition: fxobject.hpp:758
BOOLEAN EarlyDispose(VOID)
VOID ProcessDestroy(VOID)
virtual BOOLEAN Dispose(VOID)
FxTagTracker * GetTagTracker(VOID)
Definition: fxobject.hpp:766
__inline FxContextHeader * GetContextHeader(VOID)
Definition: fxobject.hpp:720
VOID __inline SetObjectStateLocked(__in FxObjectState NewState)
Definition: fxobject.hpp:369
BOOLEAN IsCommitted(VOID)
Definition: fxobject.hpp:1087
BOOLEAN PerformEarlyDispose(VOID)
virtual VOID SelfDestruct(VOID)
Definition: fxobject.hpp:437
VOID CheckForAbandondedTags(VOID)
#define _Releases_lock_(lock)
#define __in
Definition: dbghelp.h:35
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
KIRQL irql
Definition: wave.h:1
#define __drv_when(cond, annotes)
Definition: driverspecs.h:335
#define __drv_restoresIRQL
Definition: driverspecs.h:322
#define __drv_requiresIRQL(irql)
Definition: driverspecs.h:321
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
PSINGLE_LIST_ENTRY ple
FxObjectState
Definition: fxobject.hpp:158
@ FxObjectStateDeferedDeleting
Definition: fxobject.hpp:165
@ FxObjectStateDestroyed
Definition: fxobject.hpp:171
@ FxObjectStateCreated
Definition: fxobject.hpp:160
@ FxObjectStateDisposed
Definition: fxobject.hpp:161
@ FxObjectStateDisposingDisposeChildren
Definition: fxobject.hpp:163
@ FxObjectStateWaitingForEarlyDispose
Definition: fxobject.hpp:166
@ FxObjectStateDeletedDisposing
Definition: fxobject.hpp:168
@ FxObjectStateWaitingForParentDeleteAndDisposed
Definition: fxobject.hpp:167
@ FxObjectStateDeletedAndDisposed
Definition: fxobject.hpp:169
@ FxObjectStateDisposingEarly
Definition: fxobject.hpp:162
@ FxObjectStateDeferedDisposing
Definition: fxobject.hpp:164
@ FxObjectStateDeferedDestroy
Definition: fxobject.hpp:170
@ FxObjectStateInvalid
Definition: fxobject.hpp:159
@ FXOBJECT_FLAGS_DELETECALLED
Definition: fxobject.hpp:142
@ FXOBJECT_FLAGS_DISPOSE_OVERRIDE
Definition: fxobject.hpp:151
@ FXOBJECT_FLAGS_EARLY_DISPOSED_EXT
Definition: fxobject.hpp:148
@ FxObjectDroppedEventDeleteObject
Definition: fxobject.hpp:179
@ FxObjectDroppedEventParentDeleteEvent
Definition: fxobject.hpp:182
@ FxObjectDroppedEventPerformEarlyDispose
Definition: fxobject.hpp:180
@ FxObjectDroppedEventRemoveParentAssignment
Definition: fxobject.hpp:181
#define RELEASE(_tag)
Definition: fxobject.hpp:50
void FxPoolFree(__in_xcount(ptr is at an offset from AllocationStart) PVOID ptr)
Definition: wdfpool.cpp:361
const GLint * first
Definition: glext.h:5794
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
FxContextHeader * pHeader
Definition: handleapi.cpp:604
#define ASSERT(a)
Definition: mode.c:44
#define _Must_inspect_result_
Definition: ms_sal.h:558
#define _When_(expr, annos)
Definition: ms_sal.h:254
#define DO_NOTHING()
Definition: mxgeneral.h:32
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
@ Unlock
Definition: ntsecapi.h:294
#define STATUS_DELETE_PENDING
Definition: ntstatus.h:322
unsigned short USHORT
Definition: pedump.c:61
FxContextHeader * NextHeader
Definition: fxhandle.h:71
PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback
Definition: fxhandle.h:82
PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback
Definition: fxhandle.h:76
FxTagTracker * TagTracker
Definition: fxobject.hpp:208
FxDriver * Driver
Definition: fxglobals.h:374
Definition: typedefs.h:120
Definition: ps.c:97
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778