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