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     FxObject.cpp
8*8a978a17SVictor Perevertkin 
9*8a978a17SVictor Perevertkin Abstract:
10*8a978a17SVictor Perevertkin 
11*8a978a17SVictor Perevertkin     This module contains the implementation of the base object
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 --*/
35*8a978a17SVictor Perevertkin 
36*8a978a17SVictor Perevertkin #include "fxobjectpch.hpp"
37*8a978a17SVictor Perevertkin 
38*8a978a17SVictor Perevertkin extern "C" {
39*8a978a17SVictor Perevertkin 
40*8a978a17SVictor Perevertkin #if defined(EVENT_TRACING)
41*8a978a17SVictor Perevertkin #include "FxObject.tmh"
42*8a978a17SVictor Perevertkin #else
43*8a978a17SVictor Perevertkin ULONG DebugLevel = TRACE_LEVEL_INFORMATION;
44*8a978a17SVictor Perevertkin ULONG DebugFlag = 0xff;
45*8a978a17SVictor Perevertkin #endif
46*8a978a17SVictor Perevertkin 
47*8a978a17SVictor Perevertkin }
48*8a978a17SVictor Perevertkin 
FxObject(__in WDFTYPE Type,__in USHORT Size,__in PFX_DRIVER_GLOBALS FxDriverGlobals)49*8a978a17SVictor Perevertkin FxObject::FxObject(
50*8a978a17SVictor Perevertkin     __in WDFTYPE Type,
51*8a978a17SVictor Perevertkin     __in USHORT Size,
52*8a978a17SVictor Perevertkin     __in PFX_DRIVER_GLOBALS FxDriverGlobals
53*8a978a17SVictor Perevertkin     ) :
54*8a978a17SVictor Perevertkin     m_Type(Type),
55*8a978a17SVictor Perevertkin     m_ObjectSize((USHORT) WDF_ALIGN_SIZE_UP(Size, MEMORY_ALLOCATION_ALIGNMENT)),
56*8a978a17SVictor Perevertkin     m_Globals(FxDriverGlobals)
57*8a978a17SVictor Perevertkin #if FX_CORE_MODE==FX_CORE_USER_MODE
58*8a978a17SVictor Perevertkin #ifndef INLINE_WRAPPER_ALLOCATION
59*8a978a17SVictor Perevertkin     ,m_COMWrapper(NULL)
60*8a978a17SVictor Perevertkin #endif
61*8a978a17SVictor Perevertkin #endif
62*8a978a17SVictor Perevertkin {
63*8a978a17SVictor Perevertkin     ASSERT((((ULONG_PTR) this) & FxHandleFlagMask) == 0x0);
64*8a978a17SVictor Perevertkin 
65*8a978a17SVictor Perevertkin     Construct(FALSE);
66*8a978a17SVictor Perevertkin }
67*8a978a17SVictor Perevertkin 
FxObject(__in WDFTYPE Type,__in USHORT Size,__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxObjectType ObjectType)68*8a978a17SVictor Perevertkin FxObject::FxObject(
69*8a978a17SVictor Perevertkin     __in WDFTYPE Type,
70*8a978a17SVictor Perevertkin     __in USHORT Size,
71*8a978a17SVictor Perevertkin     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
72*8a978a17SVictor Perevertkin     __in FxObjectType ObjectType
73*8a978a17SVictor Perevertkin     ) :
74*8a978a17SVictor Perevertkin     m_Type(Type),
75*8a978a17SVictor Perevertkin     m_ObjectSize((USHORT) WDF_ALIGN_SIZE_UP(Size, MEMORY_ALLOCATION_ALIGNMENT)),
76*8a978a17SVictor Perevertkin     m_Globals(FxDriverGlobals)
77*8a978a17SVictor Perevertkin {
78*8a978a17SVictor Perevertkin      if (ObjectType != FxObjectTypeEmbedded) {
79*8a978a17SVictor Perevertkin          //
80*8a978a17SVictor Perevertkin          // only for non embedded objects
81*8a978a17SVictor Perevertkin          //
82*8a978a17SVictor Perevertkin          ASSERT((((ULONG_PTR) this) & FxHandleFlagMask) == 0x0);
83*8a978a17SVictor Perevertkin      }
84*8a978a17SVictor Perevertkin 
85*8a978a17SVictor Perevertkin     Construct(ObjectType == FxObjectTypeEmbedded ? TRUE : FALSE);
86*8a978a17SVictor Perevertkin }
87*8a978a17SVictor Perevertkin 
~FxObject()88*8a978a17SVictor Perevertkin FxObject::~FxObject()
89*8a978a17SVictor Perevertkin {
90*8a978a17SVictor Perevertkin     FxTagTracker *pTagTracker;
91*8a978a17SVictor Perevertkin 
92*8a978a17SVictor Perevertkin 
93*8a978a17SVictor Perevertkin 
94*8a978a17SVictor Perevertkin 
95*8a978a17SVictor Perevertkin 
96*8a978a17SVictor Perevertkin 
97*8a978a17SVictor Perevertkin 
98*8a978a17SVictor Perevertkin     pTagTracker = GetTagTracker();
99*8a978a17SVictor Perevertkin 
100*8a978a17SVictor Perevertkin     if (pTagTracker != NULL) {
101*8a978a17SVictor Perevertkin         delete pTagTracker;
102*8a978a17SVictor Perevertkin     }
103*8a978a17SVictor Perevertkin 
104*8a978a17SVictor Perevertkin     ASSERT(m_DisposeSingleEntry.Next == NULL);
105*8a978a17SVictor Perevertkin 
106*8a978a17SVictor Perevertkin     //
107*8a978a17SVictor Perevertkin     // We need to ensure there are no leaked child objects, or
108*8a978a17SVictor Perevertkin     // parent associations.
109*8a978a17SVictor Perevertkin     //
110*8a978a17SVictor Perevertkin     // This can occur if someone calls the C++ operator delete,
111*8a978a17SVictor Perevertkin     // or Release() to destroy the object.
112*8a978a17SVictor Perevertkin     //
113*8a978a17SVictor Perevertkin     // This is generally invalid in the framework, though certain
114*8a978a17SVictor Perevertkin     // objects may understand the underlying contract, but must
115*8a978a17SVictor Perevertkin     // make sure there are no left over un-Disposed associations.
116*8a978a17SVictor Perevertkin     //
117*8a978a17SVictor Perevertkin     // Embedded FxObject's also don't have delete called on them,
118*8a978a17SVictor Perevertkin     // and have to manually manage any child associations when
119*8a978a17SVictor Perevertkin     // their parent object disposes by calling PerformEarlyDispose.
120*8a978a17SVictor Perevertkin     //
121*8a978a17SVictor Perevertkin     // They don't have an associated lifetime parent since they
122*8a978a17SVictor Perevertkin     // are embedded.
123*8a978a17SVictor Perevertkin     //
124*8a978a17SVictor Perevertkin     if (m_ParentObject != NULL ||
125*8a978a17SVictor Perevertkin         !IsListEmpty(&m_ChildListHead) || !IsListEmpty(&m_ChildEntry)) {
126*8a978a17SVictor Perevertkin         PCSTR pHandleName;
127*8a978a17SVictor Perevertkin 
128*8a978a17SVictor Perevertkin         pHandleName = FxObjectTypeToHandleName(m_Type);
129*8a978a17SVictor Perevertkin         if (pHandleName == NULL) {
130*8a978a17SVictor Perevertkin             pHandleName = "WDFOBJECT";
131*8a978a17SVictor Perevertkin         }
132*8a978a17SVictor Perevertkin 
133*8a978a17SVictor Perevertkin         ASSERTMSG(
134*8a978a17SVictor Perevertkin             "Object was freed using WdfObjectDereference, not WdfObjectDelete\n",
135*8a978a17SVictor Perevertkin             m_ParentObject == NULL &&
136*8a978a17SVictor Perevertkin             IsListEmpty(&m_ChildEntry) &&
137*8a978a17SVictor Perevertkin             IsListEmpty(&m_ChildListHead)
138*8a978a17SVictor Perevertkin             );
139*8a978a17SVictor Perevertkin 
140*8a978a17SVictor Perevertkin         DoTraceLevelMessage(
141*8a978a17SVictor Perevertkin             GetDriverGlobals(), TRACE_LEVEL_FATAL, TRACINGOBJECT,
142*8a978a17SVictor Perevertkin             "Handle %s %p (raw object %p) was freed using "
143*8a978a17SVictor Perevertkin             "WdfObjectDereference(), not WdfObjectDelete()",
144*8a978a17SVictor Perevertkin             pHandleName, GetObjectHandleUnchecked(), this);
145*8a978a17SVictor Perevertkin 
146*8a978a17SVictor Perevertkin         FxVerifierBugCheck(GetDriverGlobals(),
147*8a978a17SVictor Perevertkin                            WDF_OBJECT_ERROR,
148*8a978a17SVictor Perevertkin                            (ULONG_PTR) GetObjectHandleUnchecked(),
149*8a978a17SVictor Perevertkin                            (ULONG_PTR) this);
150*8a978a17SVictor Perevertkin     }
151*8a978a17SVictor Perevertkin 
152*8a978a17SVictor Perevertkin     //
153*8a978a17SVictor Perevertkin     // This is called when the reference count goes to zero
154*8a978a17SVictor Perevertkin     //
155*8a978a17SVictor Perevertkin     SetObjectStateLocked(FxObjectStateDestroyed);
156*8a978a17SVictor Perevertkin }
157*8a978a17SVictor Perevertkin 
158*8a978a17SVictor Perevertkin 
159*8a978a17SVictor Perevertkin VOID
FX_VF_METHOD(FxObject,VerifyConstruct)160*8a978a17SVictor Perevertkin FX_VF_METHOD(FxObject, VerifyConstruct) (
161*8a978a17SVictor Perevertkin     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
162*8a978a17SVictor Perevertkin     _In_ BOOLEAN Embedded
163*8a978a17SVictor Perevertkin     )
164*8a978a17SVictor Perevertkin {
165*8a978a17SVictor Perevertkin     UNREFERENCED_PARAMETER(FxDriverGlobals);
166*8a978a17SVictor Perevertkin 
167*8a978a17SVictor Perevertkin #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
168*8a978a17SVictor Perevertkin     PAGED_CODE_LOCKED();
169*8a978a17SVictor Perevertkin #endif
170*8a978a17SVictor Perevertkin 
171*8a978a17SVictor Perevertkin     ASSERTMSG(
172*8a978a17SVictor Perevertkin         "this object's type is not listed in FxObjectsInfo\n",
173*8a978a17SVictor Perevertkin         FxVerifyObjectTypeInTable(m_Type));
174*8a978a17SVictor Perevertkin 
175*8a978a17SVictor Perevertkin     //
176*8a978a17SVictor Perevertkin     // If this is an embedded object, there is no possibility of having
177*8a978a17SVictor Perevertkin     // a debug extension, so do not set FXOBJECT_FLAGS_HAS_DEBUG *ever*
178*8a978a17SVictor Perevertkin     // in this case.
179*8a978a17SVictor Perevertkin     //
180*8a978a17SVictor Perevertkin     if (m_Globals->IsObjectDebugOn() && Embedded == FALSE) {
181*8a978a17SVictor Perevertkin         FxObjectDebugExtension* pExtension;
182*8a978a17SVictor Perevertkin 
183*8a978a17SVictor Perevertkin         m_ObjectFlags |= FXOBJECT_FLAGS_HAS_DEBUG;
184*8a978a17SVictor Perevertkin 
185*8a978a17SVictor Perevertkin         pExtension = GetDebugExtension();
186*8a978a17SVictor Perevertkin         ASSERT(pExtension->Signature == FxObjectDebugExtensionSignature);
187*8a978a17SVictor Perevertkin 
188*8a978a17SVictor Perevertkin         //
189*8a978a17SVictor Perevertkin         // Assume that zero is an invalid state.
190*8a978a17SVictor Perevertkin         //
191*8a978a17SVictor Perevertkin         WDFCASSERT(FxObjectStateInvalid == 0x0);
192*8a978a17SVictor Perevertkin         RtlZeroMemory(&pExtension->StateHistory[0],
193*8a978a17SVictor Perevertkin                       ARRAY_SIZE(pExtension->StateHistory));
194*8a978a17SVictor Perevertkin         pExtension->StateHistoryIndex = 0;
195*8a978a17SVictor Perevertkin 
196*8a978a17SVictor Perevertkin         //
197*8a978a17SVictor Perevertkin         // Setup the first slot to our new state.
198*8a978a17SVictor Perevertkin         //
199*8a978a17SVictor Perevertkin         pExtension->StateHistory[0] = FxObjectStateCreated;
200*8a978a17SVictor Perevertkin 
201*8a978a17SVictor Perevertkin         AllocateTagTracker(m_Type);
202*8a978a17SVictor Perevertkin     }
203*8a978a17SVictor Perevertkin }
204*8a978a17SVictor Perevertkin 
205*8a978a17SVictor Perevertkin 
206*8a978a17SVictor Perevertkin VOID
FinalRelease(VOID)207*8a978a17SVictor Perevertkin FxObject::FinalRelease(
208*8a978a17SVictor Perevertkin     VOID
209*8a978a17SVictor Perevertkin     )
210*8a978a17SVictor Perevertkin {
211*8a978a17SVictor Perevertkin 
212*8a978a17SVictor Perevertkin 
213*8a978a17SVictor Perevertkin 
214*8a978a17SVictor Perevertkin 
215*8a978a17SVictor Perevertkin 
216*8a978a17SVictor Perevertkin 
217*8a978a17SVictor Perevertkin 
218*8a978a17SVictor Perevertkin 
219*8a978a17SVictor Perevertkin 
220*8a978a17SVictor Perevertkin 
221*8a978a17SVictor Perevertkin 
222*8a978a17SVictor Perevertkin 
223*8a978a17SVictor Perevertkin     //
224*8a978a17SVictor Perevertkin     // No other access, OK to test flag without grabbing spinlock
225*8a978a17SVictor Perevertkin     // since it can only be set at create.
226*8a978a17SVictor Perevertkin     //
227*8a978a17SVictor Perevertkin     if (ShouldDeferDisposeLocked()) {
228*8a978a17SVictor Perevertkin         //
229*8a978a17SVictor Perevertkin         // If this is a passive level only object, ensure we only destroy
230*8a978a17SVictor Perevertkin         // it from passive level.  No need to hold the object lock when
231*8a978a17SVictor Perevertkin         // changing to this state since no other thread can change our
232*8a978a17SVictor Perevertkin         // state.
233*8a978a17SVictor Perevertkin         //
234*8a978a17SVictor Perevertkin         SetObjectStateLocked(FxObjectStateDeferedDestroy);
235*8a978a17SVictor Perevertkin 
236*8a978a17SVictor Perevertkin         //
237*8a978a17SVictor Perevertkin         // Note, we cannot be holding a lock while making this call b/c by
238*8a978a17SVictor Perevertkin         // the time it returns, it could have freed the object and the
239*8a978a17SVictor Perevertkin         // KeReleaseSpinLock call would have touched freed pool.
240*8a978a17SVictor Perevertkin         //
241*8a978a17SVictor Perevertkin 
242*8a978a17SVictor Perevertkin         //FxToObjectItf::FxAddToDriverDisposeList(m_Globals, this);
243*8a978a17SVictor Perevertkin 
244*8a978a17SVictor Perevertkin 
245*8a978a17SVictor Perevertkin         m_Globals->Driver->GetDisposeList()->Add(this);
246*8a978a17SVictor Perevertkin 
247*8a978a17SVictor Perevertkin     }
248*8a978a17SVictor Perevertkin     else {
249*8a978a17SVictor Perevertkin         ProcessDestroy();
250*8a978a17SVictor Perevertkin     }
251*8a978a17SVictor Perevertkin }
252*8a978a17SVictor Perevertkin 
253*8a978a17SVictor Perevertkin _Must_inspect_result_
254*8a978a17SVictor Perevertkin NTSTATUS
QueryInterface(__in FxQueryInterfaceParams * Params)255*8a978a17SVictor Perevertkin FxObject::QueryInterface(
256*8a978a17SVictor Perevertkin     __in FxQueryInterfaceParams* Params
257*8a978a17SVictor Perevertkin     )
258*8a978a17SVictor Perevertkin {
259*8a978a17SVictor Perevertkin     NTSTATUS status;
260*8a978a17SVictor Perevertkin 
261*8a978a17SVictor Perevertkin     if (Params->Type == FX_TYPE_OBJECT) {
262*8a978a17SVictor Perevertkin         *Params->Object = this;
263*8a978a17SVictor Perevertkin         status = STATUS_SUCCESS;
264*8a978a17SVictor Perevertkin     }
265*8a978a17SVictor Perevertkin     else {
266*8a978a17SVictor Perevertkin         status = STATUS_NOINTERFACE;
267*8a978a17SVictor Perevertkin     }
268*8a978a17SVictor Perevertkin 
269*8a978a17SVictor Perevertkin     return status;
270*8a978a17SVictor Perevertkin }
271*8a978a17SVictor Perevertkin 
272*8a978a17SVictor Perevertkin VOID
AllocateTagTracker(__in WDFTYPE Type)273*8a978a17SVictor Perevertkin FxObject::AllocateTagTracker(
274*8a978a17SVictor Perevertkin     __in WDFTYPE Type
275*8a978a17SVictor Perevertkin     )
276*8a978a17SVictor Perevertkin {
277*8a978a17SVictor Perevertkin     ASSERT(IsDebug());
278*8a978a17SVictor Perevertkin 
279*8a978a17SVictor Perevertkin     if (m_Globals->DebugExtension != NULL &&
280*8a978a17SVictor Perevertkin         m_Globals->DebugExtension->ObjectDebugInfo != NULL &&
281*8a978a17SVictor Perevertkin         FxVerifierGetTrackReferences(
282*8a978a17SVictor Perevertkin             m_Globals->DebugExtension->ObjectDebugInfo,
283*8a978a17SVictor Perevertkin             Type)) {
284*8a978a17SVictor Perevertkin         //
285*8a978a17SVictor Perevertkin         // Failure to CreateAndInitialize a tag tracker is no big deal, we just
286*8a978a17SVictor Perevertkin         // don't track references.
287*8a978a17SVictor Perevertkin         //
288*8a978a17SVictor Perevertkin 
289*8a978a17SVictor Perevertkin         (void) FxTagTracker::CreateAndInitialize(
290*8a978a17SVictor Perevertkin             &GetDebugExtension()->TagTracker,
291*8a978a17SVictor Perevertkin             m_Globals,
292*8a978a17SVictor Perevertkin             FxTagTrackerTypeHandle,
293*8a978a17SVictor Perevertkin             FALSE,
294*8a978a17SVictor Perevertkin             this
295*8a978a17SVictor Perevertkin             );
296*8a978a17SVictor Perevertkin 
297*8a978a17SVictor Perevertkin         //
298*8a978a17SVictor Perevertkin         // For now we overload the requirement of a tag tracker as also tracing
299*8a978a17SVictor Perevertkin         // state changes.
300*8a978a17SVictor Perevertkin         //
301*8a978a17SVictor Perevertkin         m_ObjectFlags |= FXOBJECT_FLAGS_TRACE_STATE;
302*8a978a17SVictor Perevertkin     }
303*8a978a17SVictor Perevertkin }
304*8a978a17SVictor Perevertkin 
305*8a978a17SVictor Perevertkin VOID
operator delete(__in PVOID Memory)306*8a978a17SVictor Perevertkin FxObject::operator delete(
307*8a978a17SVictor Perevertkin     __in PVOID Memory
308*8a978a17SVictor Perevertkin     )
309*8a978a17SVictor Perevertkin {
310*8a978a17SVictor Perevertkin     ASSERT(Memory != NULL);
311*8a978a17SVictor Perevertkin 
312*8a978a17SVictor Perevertkin 
313*8a978a17SVictor Perevertkin 
314*8a978a17SVictor Perevertkin 
315*8a978a17SVictor Perevertkin 
316*8a978a17SVictor Perevertkin 
317*8a978a17SVictor Perevertkin 
318*8a978a17SVictor Perevertkin 
319*8a978a17SVictor Perevertkin 
320*8a978a17SVictor Perevertkin 
321*8a978a17SVictor Perevertkin 
322*8a978a17SVictor Perevertkin 
323*8a978a17SVictor Perevertkin 
324*8a978a17SVictor Perevertkin     FxPoolFree(_GetBase((FxObject*) Memory));
325*8a978a17SVictor Perevertkin }
326*8a978a17SVictor Perevertkin 
327*8a978a17SVictor Perevertkin VOID
CallCleanupCallbacks(VOID)328*8a978a17SVictor Perevertkin FxObject::CallCleanupCallbacks(
329*8a978a17SVictor Perevertkin     VOID
330*8a978a17SVictor Perevertkin     )
331*8a978a17SVictor Perevertkin {
332*8a978a17SVictor Perevertkin     FxContextHeader* pHeader;
333*8a978a17SVictor Perevertkin     WDFOBJECT h;
334*8a978a17SVictor Perevertkin 
335*8a978a17SVictor Perevertkin     //
336*8a978a17SVictor Perevertkin     // Deleted before Commit or it is an internal object
337*8a978a17SVictor Perevertkin     //
338*8a978a17SVictor Perevertkin     if (IsCommitted() == FALSE) {
339*8a978a17SVictor Perevertkin         return;
340*8a978a17SVictor Perevertkin     }
341*8a978a17SVictor Perevertkin 
342*8a978a17SVictor Perevertkin     //
343*8a978a17SVictor Perevertkin     // We only should have an object handle when we have an external object
344*8a978a17SVictor Perevertkin     //
345*8a978a17SVictor Perevertkin     h = GetObjectHandle();
346*8a978a17SVictor Perevertkin 
347*8a978a17SVictor Perevertkin     for (pHeader = GetContextHeader();
348*8a978a17SVictor Perevertkin          pHeader != NULL;
349*8a978a17SVictor Perevertkin          pHeader = pHeader->NextHeader) {
350*8a978a17SVictor Perevertkin         if (pHeader->EvtCleanupCallback != NULL) {
351*8a978a17SVictor Perevertkin             pHeader->EvtCleanupCallback(h);
352*8a978a17SVictor Perevertkin             pHeader->EvtCleanupCallback = NULL;
353*8a978a17SVictor Perevertkin         }
354*8a978a17SVictor Perevertkin     }
355*8a978a17SVictor Perevertkin 
356*8a978a17SVictor Perevertkin     m_ObjectFlags &= ~FXOBJECT_FLAGS_HAS_CLEANUP;
357*8a978a17SVictor Perevertkin }
358*8a978a17SVictor Perevertkin 
359*8a978a17SVictor Perevertkin VOID
ClearEvtCallbacks(VOID)360*8a978a17SVictor Perevertkin FxObject::ClearEvtCallbacks(
361*8a978a17SVictor Perevertkin     VOID
362*8a978a17SVictor Perevertkin     )
363*8a978a17SVictor Perevertkin /*++
364*8a978a17SVictor Perevertkin 
365*8a978a17SVictor Perevertkin Routine Description:
366*8a978a17SVictor Perevertkin 
367*8a978a17SVictor Perevertkin     Clears out any assigned callbacks on the object.
368*8a978a17SVictor Perevertkin 
369*8a978a17SVictor Perevertkin Arguments:
370*8a978a17SVictor Perevertkin     None
371*8a978a17SVictor Perevertkin 
372*8a978a17SVictor Perevertkin Return Value:
373*8a978a17SVictor Perevertkin     None
374*8a978a17SVictor Perevertkin 
375*8a978a17SVictor Perevertkin   --*/
376*8a978a17SVictor Perevertkin {
377*8a978a17SVictor Perevertkin     FxContextHeader *pHeader;
378*8a978a17SVictor Perevertkin 
379*8a978a17SVictor Perevertkin     for (pHeader = GetContextHeader();
380*8a978a17SVictor Perevertkin          pHeader != NULL;
381*8a978a17SVictor Perevertkin          pHeader = pHeader->NextHeader) {
382*8a978a17SVictor Perevertkin 
383*8a978a17SVictor Perevertkin         pHeader->EvtDestroyCallback = NULL;
384*8a978a17SVictor Perevertkin         pHeader->EvtCleanupCallback = NULL;
385*8a978a17SVictor Perevertkin     }
386*8a978a17SVictor Perevertkin 
387*8a978a17SVictor Perevertkin     m_ObjectFlags &= ~FXOBJECT_FLAGS_HAS_CLEANUP;
388*8a978a17SVictor Perevertkin }
389*8a978a17SVictor Perevertkin 
390*8a978a17SVictor Perevertkin VOID
DeleteFromFailedCreate(VOID)391*8a978a17SVictor Perevertkin FxObject::DeleteFromFailedCreate(
392*8a978a17SVictor Perevertkin     VOID
393*8a978a17SVictor Perevertkin     )
394*8a978a17SVictor Perevertkin /*++
395*8a978a17SVictor Perevertkin 
396*8a978a17SVictor Perevertkin Routine Description:
397*8a978a17SVictor Perevertkin     Clears out any assigned callbacks on the object and then deletes it.  Clearing
398*8a978a17SVictor Perevertkin     out the callbacks are necessary so that the driver's callbacks are not called
399*8a978a17SVictor Perevertkin     on a buffer that they didn't initialize.
400*8a978a17SVictor Perevertkin 
401*8a978a17SVictor Perevertkin Arguments:
402*8a978a17SVictor Perevertkin     None
403*8a978a17SVictor Perevertkin 
404*8a978a17SVictor Perevertkin Return Value:
405*8a978a17SVictor Perevertkin     None
406*8a978a17SVictor Perevertkin 
407*8a978a17SVictor Perevertkin   --*/
408*8a978a17SVictor Perevertkin {
409*8a978a17SVictor Perevertkin     ClearEvtCallbacks();
410*8a978a17SVictor Perevertkin 
411*8a978a17SVictor Perevertkin     //
412*8a978a17SVictor Perevertkin     // After this call returns "this" is destroyed is not a valid pointer!
413*8a978a17SVictor Perevertkin     //
414*8a978a17SVictor Perevertkin     DeleteObject();
415*8a978a17SVictor Perevertkin 
416*8a978a17SVictor Perevertkin     //
417*8a978a17SVictor Perevertkin     // "this" is now freed memory, do not touch it!
418*8a978a17SVictor Perevertkin     //
419*8a978a17SVictor Perevertkin }
420*8a978a17SVictor Perevertkin 
421*8a978a17SVictor Perevertkin //
422*8a978a17SVictor Perevertkin // FxObject Parent/Child Rules:
423*8a978a17SVictor Perevertkin //
424*8a978a17SVictor Perevertkin // The FxObject state machine protects state transitions when
425*8a978a17SVictor Perevertkin // objects are being associated with each other, and races
426*8a978a17SVictor Perevertkin // that can occur when a child and parent object are being
427*8a978a17SVictor Perevertkin // deleted at the same time. This provides the backbone of
428*8a978a17SVictor Perevertkin // assurance on the objects state.
429*8a978a17SVictor Perevertkin //
430*8a978a17SVictor Perevertkin // While transiting object states, the following must be taken
431*8a978a17SVictor Perevertkin // into consideration:
432*8a978a17SVictor Perevertkin //
433*8a978a17SVictor Perevertkin // Reference counts:
434*8a978a17SVictor Perevertkin //
435*8a978a17SVictor Perevertkin //  When an object is created with operator new(), it has a reference count
436*8a978a17SVictor Perevertkin //  of one.
437*8a978a17SVictor Perevertkin //
438*8a978a17SVictor Perevertkin //  When a DeleteObject is done on it, the reference count is decremented
439*8a978a17SVictor Perevertkin //  after delete processing is done (which can include disposing children),
440*8a978a17SVictor Perevertkin //  and this results in the objects destruction.
441*8a978a17SVictor Perevertkin //
442*8a978a17SVictor Perevertkin //  When an object is created by operator new() and immediately associated
443*8a978a17SVictor Perevertkin //  with a parent object, its reference count remains one.
444*8a978a17SVictor Perevertkin //
445*8a978a17SVictor Perevertkin //  When either the DeleteObject() method is invoked, or the parent object
446*8a978a17SVictor Perevertkin //  disposes the child object with ParentDeleteEvent(), eventually the
447*8a978a17SVictor Perevertkin //  object will dereference itself after delete processing is done only
448*8a978a17SVictor Perevertkin //  once.
449*8a978a17SVictor Perevertkin //
450*8a978a17SVictor Perevertkin //  Even in the face of race conditions, the object state machine ensures that
451*8a978a17SVictor Perevertkin //  only one set of the proper delete conditions occur (dispose children, invoke
452*8a978a17SVictor Perevertkin //  driver and class dispose callbacks, dereference object).
453*8a978a17SVictor Perevertkin //
454*8a978a17SVictor Perevertkin //  An object is responsible for releasing its own reference count on its
455*8a978a17SVictor Perevertkin //  self when it goes into the FxObjectStateDeletedAndDisposed.
456*8a978a17SVictor Perevertkin //
457*8a978a17SVictor Perevertkin //  This has been *carefully* designed so that only the original object
458*8a978a17SVictor Perevertkin //  references are required for this automatic lifetime case to avoid
459*8a978a17SVictor Perevertkin //  extra interlocked operations in AddRef and Release frequently. These
460*8a978a17SVictor Perevertkin //  extra interlocked operations can have a big performance impact on
461*8a978a17SVictor Perevertkin //  the WDF main I/O paths, in which object relationship's are being used.
462*8a978a17SVictor Perevertkin //
463*8a978a17SVictor Perevertkin //  A simpler implementation may try and have the parent add a reference
464*8a978a17SVictor Perevertkin //  to the child, and the child add a reference to the parent, but this
465*8a978a17SVictor Perevertkin //  is a tightly coupled implementation controlled by the object state
466*8a978a17SVictor Perevertkin //  machine. A circular reference pattern is OK for objects that
467*8a978a17SVictor Perevertkin //  do not have a formal designed in relationship that can be expressed
468*8a978a17SVictor Perevertkin //  in the complex tear down contract implemented in the state machine.
469*8a978a17SVictor Perevertkin //
470*8a978a17SVictor Perevertkin // SpinLocks:
471*8a978a17SVictor Perevertkin //
472*8a978a17SVictor Perevertkin // The m_SpinLock field protects each indivdual objects m_ObjectState
473*8a978a17SVictor Perevertkin // variable, the list of child objects that it has, and the m_ParentObject
474*8a978a17SVictor Perevertkin // field.
475*8a978a17SVictor Perevertkin //
476*8a978a17SVictor Perevertkin // In addition, if any object associates itself with a parent object,
477*8a978a17SVictor Perevertkin // it effectively "lends" its m_ChildEntry field to the parent object,
478*8a978a17SVictor Perevertkin // and these are manipulated and protected by the parent objects m_SpinLock.
479*8a978a17SVictor Perevertkin //
480*8a978a17SVictor Perevertkin // Lock Order:
481*8a978a17SVictor Perevertkin //
482*8a978a17SVictor Perevertkin // Currently the lock order is Child -> Parent, meaning a child
483*8a978a17SVictor Perevertkin // can call the AddChildObjectInternal, RemoveChildObjectInternal, methods with
484*8a978a17SVictor Perevertkin // the child lock held.
485*8a978a17SVictor Perevertkin //
486*8a978a17SVictor Perevertkin // The parent object will not invoke any child object ParentDeleteEvent()
487*8a978a17SVictor Perevertkin // while holding the parents m_SpinLock.
488*8a978a17SVictor Perevertkin //
489*8a978a17SVictor Perevertkin // This order allows potential races between child DeleteObject and parent
490*8a978a17SVictor Perevertkin // Dispose to be resolved without extra reference counts and multiple
491*8a978a17SVictor Perevertkin // acquires and releases of the spinlocks in the normal cases.
492*8a978a17SVictor Perevertkin //
493*8a978a17SVictor Perevertkin //
494*8a978a17SVictor Perevertkin // AddChildObjectInternal/RemoveChildObjectInternal:
495*8a978a17SVictor Perevertkin //
496*8a978a17SVictor Perevertkin // When a child object is added to the parent, the parent can delete
497*8a978a17SVictor Perevertkin // the child object at any time when the parent object is deleted
498*8a978a17SVictor Perevertkin // or disposed.
499*8a978a17SVictor Perevertkin //
500*8a978a17SVictor Perevertkin // If a call to RemoveChildObjectInternal is made, the caller may not "win"
501*8a978a17SVictor Perevertkin // the inherent race with a parent object Dispose() occuring. This
502*8a978a17SVictor Perevertkin // is similar to the WDM IRP cancel race, and is handled in exactly
503*8a978a17SVictor Perevertkin // the same fashion.
504*8a978a17SVictor Perevertkin //
505*8a978a17SVictor Perevertkin // If an object is associated with a parent, and later removal
506*8a978a17SVictor Perevertkin // is desired, the return status of RemoveChildObjectInternal must be
507*8a978a17SVictor Perevertkin // tested, and if not success, the caller should not delete the
508*8a978a17SVictor Perevertkin // child object itself, since the parent is in the process
509*8a978a17SVictor Perevertkin // of doing so. The caller "lost the Dispose race".
510*8a978a17SVictor Perevertkin //
511*8a978a17SVictor Perevertkin //
512*8a978a17SVictor Perevertkin // m_ParentObject field:
513*8a978a17SVictor Perevertkin //
514*8a978a17SVictor Perevertkin // This field is set by the child object after it successfully
515*8a978a17SVictor Perevertkin // adds a parent object, and clear it when it is disposed by
516*8a978a17SVictor Perevertkin // the parent, or removes the parent association.
517*8a978a17SVictor Perevertkin //
518*8a978a17SVictor Perevertkin // It is protected by the childs m_SpinLock field.
519*8a978a17SVictor Perevertkin //
520*8a978a17SVictor Perevertkin 
521*8a978a17SVictor Perevertkin 
522*8a978a17SVictor Perevertkin 
523*8a978a17SVictor Perevertkin 
524*8a978a17SVictor Perevertkin 
525*8a978a17SVictor Perevertkin 
526*8a978a17SVictor Perevertkin 
527*8a978a17SVictor Perevertkin _Must_inspect_result_
528*8a978a17SVictor Perevertkin NTSTATUS
AssignParentObject(__in FxObject * ParentObject)529*8a978a17SVictor Perevertkin FxObject::AssignParentObject(
530*8a978a17SVictor Perevertkin     __in FxObject* ParentObject
531*8a978a17SVictor Perevertkin     )
532*8a978a17SVictor Perevertkin /*++
533*8a978a17SVictor Perevertkin 
534*8a978a17SVictor Perevertkin Routine Description:
535*8a978a17SVictor Perevertkin     Assign a parent to the current object.      The parent can not be the same
536*8a978a17SVictor Perevertkin     object.
537*8a978a17SVictor Perevertkin 
538*8a978a17SVictor Perevertkin Arguments:
539*8a978a17SVictor Perevertkin     ParentObject - Object to become the parent for this object
540*8a978a17SVictor Perevertkin 
541*8a978a17SVictor Perevertkin Returns:
542*8a978a17SVictor Perevertkin 
543*8a978a17SVictor Perevertkin Comments:
544*8a978a17SVictor Perevertkin 
545*8a978a17SVictor Perevertkin     The caller "passes" its initial object reference to us, so we
546*8a978a17SVictor Perevertkin     do not take an additional reference on the object.
547*8a978a17SVictor Perevertkin 
548*8a978a17SVictor Perevertkin     If we are deleted, Dispose() will be invoked on the object, and
549*8a978a17SVictor Perevertkin     its reference will be released.
550*8a978a17SVictor Perevertkin 
551*8a978a17SVictor Perevertkin     This provides automatic deletion of associated child objects if
552*8a978a17SVictor Perevertkin     the object does not keep any extra references.
553*8a978a17SVictor Perevertkin 
554*8a978a17SVictor Perevertkin --*/
555*8a978a17SVictor Perevertkin {
556*8a978a17SVictor Perevertkin     KIRQL oldIrql;
557*8a978a17SVictor Perevertkin     NTSTATUS status;
558*8a978a17SVictor Perevertkin 
559*8a978a17SVictor Perevertkin     m_SpinLock.Acquire(&oldIrql);
560*8a978a17SVictor Perevertkin 
561*8a978a17SVictor Perevertkin     //
562*8a978a17SVictor Perevertkin     // Can't add a parent if the current object is being deleted
563*8a978a17SVictor Perevertkin     //
564*8a978a17SVictor Perevertkin     if (m_ObjectState != FxObjectStateCreated) {
565*8a978a17SVictor Perevertkin         TraceDroppedEvent(FxObjectDroppedEventAssignParentObject);
566*8a978a17SVictor Perevertkin         m_SpinLock.Release(oldIrql);
567*8a978a17SVictor Perevertkin         return STATUS_DELETE_PENDING;
568*8a978a17SVictor Perevertkin     }
569*8a978a17SVictor Perevertkin 
570*8a978a17SVictor Perevertkin     //
571*8a978a17SVictor Perevertkin     // Current Object can't already have a parent, and can't
572*8a978a17SVictor Perevertkin     // be its own parent.
573*8a978a17SVictor Perevertkin     //
574*8a978a17SVictor Perevertkin     if (m_ParentObject != NULL) {
575*8a978a17SVictor Perevertkin         m_SpinLock.Release(oldIrql);
576*8a978a17SVictor Perevertkin         return STATUS_WDF_PARENT_ALREADY_ASSIGNED;
577*8a978a17SVictor Perevertkin     }
578*8a978a17SVictor Perevertkin 
579*8a978a17SVictor Perevertkin     if (m_ParentObject == this) {
580*8a978a17SVictor Perevertkin         m_SpinLock.Release(oldIrql);
581*8a978a17SVictor Perevertkin         return STATUS_WDF_PARENT_IS_SELF;
582*8a978a17SVictor Perevertkin     }
583*8a978a17SVictor Perevertkin 
584*8a978a17SVictor Perevertkin     //
585*8a978a17SVictor Perevertkin     // We don't allow a parent object to be assigned after
586*8a978a17SVictor Perevertkin     // FxObject::Commit().
587*8a978a17SVictor Perevertkin     //
588*8a978a17SVictor Perevertkin     ASSERTMSG("Parent object can not be assigned after Commit()\n", !IsCommitted());
589*8a978a17SVictor Perevertkin 
590*8a978a17SVictor Perevertkin     ASSERT(IsListEmpty(&this->m_ChildEntry));
591*8a978a17SVictor Perevertkin 
592*8a978a17SVictor Perevertkin     status = ParentObject->AddChildObjectInternal(this);
593*8a978a17SVictor Perevertkin 
594*8a978a17SVictor Perevertkin     if (NT_SUCCESS(status)) {
595*8a978a17SVictor Perevertkin         m_ParentObject = ParentObject;
596*8a978a17SVictor Perevertkin     }
597*8a978a17SVictor Perevertkin 
598*8a978a17SVictor Perevertkin     m_SpinLock.Release(oldIrql);
599*8a978a17SVictor Perevertkin 
600*8a978a17SVictor Perevertkin     return status;
601*8a978a17SVictor Perevertkin }
602*8a978a17SVictor Perevertkin 
603*8a978a17SVictor Perevertkin _Must_inspect_result_
604*8a978a17SVictor Perevertkin NTSTATUS
AddContext(__in FxContextHeader * Header,__in PVOID * Context,__in PWDF_OBJECT_ATTRIBUTES Attributes)605*8a978a17SVictor Perevertkin FxObject::AddContext(
606*8a978a17SVictor Perevertkin     __in FxContextHeader *Header,
607*8a978a17SVictor Perevertkin     __in PVOID* Context,
608*8a978a17SVictor Perevertkin     __in PWDF_OBJECT_ATTRIBUTES Attributes
609*8a978a17SVictor Perevertkin     )
610*8a978a17SVictor Perevertkin {
611*8a978a17SVictor Perevertkin     FxContextHeader *pCur, **ppLast;
612*8a978a17SVictor Perevertkin     NTSTATUS status;
613*8a978a17SVictor Perevertkin     KIRQL irql;
614*8a978a17SVictor Perevertkin 
615*8a978a17SVictor Perevertkin     status = STATUS_UNSUCCESSFUL;
616*8a978a17SVictor Perevertkin 
617*8a978a17SVictor Perevertkin     pCur = GetContextHeader();
618*8a978a17SVictor Perevertkin 
619*8a978a17SVictor Perevertkin     //
620*8a978a17SVictor Perevertkin     // This should never happen since all outward facing objects have a
621*8a978a17SVictor Perevertkin     // context header; framework never calls this function on internal
622*8a978a17SVictor Perevertkin     // objects.
623*8a978a17SVictor Perevertkin     //
624*8a978a17SVictor Perevertkin     ASSERT(pCur != NULL);
625*8a978a17SVictor Perevertkin 
626*8a978a17SVictor Perevertkin     //
627*8a978a17SVictor Perevertkin     // Acquire the lock to lock the object's state.  A side affect of grabbing
628*8a978a17SVictor Perevertkin     // the lock is that all updaters who want to add a context are serialized.
629*8a978a17SVictor Perevertkin     // All callers who want to find a context do not need to acquire the lock
630*8a978a17SVictor Perevertkin     // becuase they are not going to update the list, just read from it.
631*8a978a17SVictor Perevertkin     //
632*8a978a17SVictor Perevertkin     // Once a context has been added, it will not be removed until the object
633*8a978a17SVictor Perevertkin     // has been deleted.
634*8a978a17SVictor Perevertkin     //
635*8a978a17SVictor Perevertkin     m_SpinLock.Acquire(&irql);
636*8a978a17SVictor Perevertkin 
637*8a978a17SVictor Perevertkin     if (m_ObjectState == FxObjectStateCreated && pCur != NULL) {
638*8a978a17SVictor Perevertkin         //
639*8a978a17SVictor Perevertkin         // Iterate over the list of contexts already on this object and see if
640*8a978a17SVictor Perevertkin         // this type already is attached.
641*8a978a17SVictor Perevertkin         //
642*8a978a17SVictor Perevertkin         for (ppLast = &pCur->NextHeader;
643*8a978a17SVictor Perevertkin              pCur != NULL;
644*8a978a17SVictor Perevertkin              ppLast = &pCur->NextHeader, pCur = pCur->NextHeader) {
645*8a978a17SVictor Perevertkin 
646*8a978a17SVictor Perevertkin             if (pCur->ContextTypeInfo == Header->ContextTypeInfo) {
647*8a978a17SVictor Perevertkin                 //
648*8a978a17SVictor Perevertkin                 // Dupe found, return error but give the caller the context
649*8a978a17SVictor Perevertkin                 // pointer
650*8a978a17SVictor Perevertkin                 //
651*8a978a17SVictor Perevertkin                 if (Context != NULL) {
652*8a978a17SVictor Perevertkin                     *Context = &pCur->Context[0];
653*8a978a17SVictor Perevertkin                 }
654*8a978a17SVictor Perevertkin 
655*8a978a17SVictor Perevertkin                 status = STATUS_OBJECT_NAME_EXISTS;
656*8a978a17SVictor Perevertkin                 break;
657*8a978a17SVictor Perevertkin             }
658*8a978a17SVictor Perevertkin         }
659*8a978a17SVictor Perevertkin 
660*8a978a17SVictor Perevertkin         if (pCur == NULL) {
661*8a978a17SVictor Perevertkin             //
662*8a978a17SVictor Perevertkin             // By using the interlocked to update, we don't need to use a lock
663*8a978a17SVictor Perevertkin             // when walking the list to find the context.   The only reason
664*8a978a17SVictor Perevertkin             // we are holding the object lock is to lock the current state
665*8a978a17SVictor Perevertkin             // (m_ObjectState) of the object.
666*8a978a17SVictor Perevertkin             //
667*8a978a17SVictor Perevertkin             InterlockedExchangePointer((PVOID*) ppLast, Header);
668*8a978a17SVictor Perevertkin             status = STATUS_SUCCESS;
669*8a978a17SVictor Perevertkin 
670*8a978a17SVictor Perevertkin             if (Context != NULL) {
671*8a978a17SVictor Perevertkin                 *Context = &Header->Context[0];
672*8a978a17SVictor Perevertkin             }
673*8a978a17SVictor Perevertkin 
674*8a978a17SVictor Perevertkin             //
675*8a978a17SVictor Perevertkin             // FxContextHeaderInit does not set these callbacks.  If this were
676*8a978a17SVictor Perevertkin             // the creation of the object itself, FxObject::Commit would have done
677*8a978a17SVictor Perevertkin             // this assignment.
678*8a978a17SVictor Perevertkin             //
679*8a978a17SVictor Perevertkin             Header->EvtDestroyCallback = Attributes->EvtDestroyCallback;
680*8a978a17SVictor Perevertkin 
681*8a978a17SVictor Perevertkin             if (Attributes->EvtCleanupCallback != NULL) {
682*8a978a17SVictor Perevertkin                 Header->EvtCleanupCallback = Attributes->EvtCleanupCallback;
683*8a978a17SVictor Perevertkin                 m_ObjectFlags |= FXOBJECT_FLAGS_HAS_CLEANUP;
684*8a978a17SVictor Perevertkin             }
685*8a978a17SVictor Perevertkin 
686*8a978a17SVictor Perevertkin         }
687*8a978a17SVictor Perevertkin     }
688*8a978a17SVictor Perevertkin     else {
689*8a978a17SVictor Perevertkin         //
690*8a978a17SVictor Perevertkin         // Object is being torn down, adding a context is a bad idea because we
691*8a978a17SVictor Perevertkin         // cannot guarantee that the cleanup or destroy routines will be called
692*8a978a17SVictor Perevertkin         //
693*8a978a17SVictor Perevertkin         status = STATUS_DELETE_PENDING;
694*8a978a17SVictor Perevertkin     }
695*8a978a17SVictor Perevertkin 
696*8a978a17SVictor Perevertkin     m_SpinLock.Release(irql);
697*8a978a17SVictor Perevertkin 
698*8a978a17SVictor Perevertkin     return status;
699*8a978a17SVictor Perevertkin }
700*8a978a17SVictor Perevertkin 
701*8a978a17SVictor Perevertkin _Must_inspect_result_
702*8a978a17SVictor Perevertkin NTSTATUS
AddChildObjectInternal(__in FxObject * ChildObject)703*8a978a17SVictor Perevertkin FxObject::AddChildObjectInternal(
704*8a978a17SVictor Perevertkin     __in FxObject* ChildObject
705*8a978a17SVictor Perevertkin     )
706*8a978a17SVictor Perevertkin 
707*8a978a17SVictor Perevertkin /*++
708*8a978a17SVictor Perevertkin 
709*8a978a17SVictor Perevertkin Routine Description:
710*8a978a17SVictor Perevertkin     Called by an object to be added to this objects child list
711*8a978a17SVictor Perevertkin 
712*8a978a17SVictor Perevertkin Arguments:
713*8a978a17SVictor Perevertkin     ChildObject - Object to add this this objects child list
714*8a978a17SVictor Perevertkin 
715*8a978a17SVictor Perevertkin Returns:
716*8a978a17SVictor Perevertkin     NTSTATUS
717*8a978a17SVictor Perevertkin 
718*8a978a17SVictor Perevertkin Comments:
719*8a978a17SVictor Perevertkin     The caller "passes" its initial object reference to us, so we
720*8a978a17SVictor Perevertkin     do not take an additional reference on the object.
721*8a978a17SVictor Perevertkin 
722*8a978a17SVictor Perevertkin     If we are deleted, Dispose() will be invoked on the object, and
723*8a978a17SVictor Perevertkin     its reference will be released.
724*8a978a17SVictor Perevertkin 
725*8a978a17SVictor Perevertkin     This provides automatic deletion of associated child objects if
726*8a978a17SVictor Perevertkin     the object does not keep any extra references.
727*8a978a17SVictor Perevertkin 
728*8a978a17SVictor Perevertkin --*/
729*8a978a17SVictor Perevertkin {
730*8a978a17SVictor Perevertkin     KIRQL oldIrql;
731*8a978a17SVictor Perevertkin 
732*8a978a17SVictor Perevertkin     m_SpinLock.Acquire(&oldIrql);
733*8a978a17SVictor Perevertkin 
734*8a978a17SVictor Perevertkin     //
735*8a978a17SVictor Perevertkin     // Can't add child if the current object is being deleted
736*8a978a17SVictor Perevertkin     //
737*8a978a17SVictor Perevertkin     if (m_ObjectState != FxObjectStateCreated) {
738*8a978a17SVictor Perevertkin         TraceDroppedEvent(FxObjectDroppedEventAddChildObjectInternal);
739*8a978a17SVictor Perevertkin         m_SpinLock.Release(oldIrql);
740*8a978a17SVictor Perevertkin         return STATUS_DELETE_PENDING;
741*8a978a17SVictor Perevertkin     }
742*8a978a17SVictor Perevertkin 
743*8a978a17SVictor Perevertkin     //
744*8a978a17SVictor Perevertkin     // ChildObject can't already have a parent, and can't
745*8a978a17SVictor Perevertkin     // be its own parent.
746*8a978a17SVictor Perevertkin     //
747*8a978a17SVictor Perevertkin     ASSERT(ChildObject->m_ParentObject == NULL);
748*8a978a17SVictor Perevertkin     ASSERT(IsListEmpty(&ChildObject->m_ChildEntry));
749*8a978a17SVictor Perevertkin     ASSERT(ChildObject != this);
750*8a978a17SVictor Perevertkin 
751*8a978a17SVictor Perevertkin     //
752*8a978a17SVictor Perevertkin     // Add to our m_ChildList
753*8a978a17SVictor Perevertkin     //
754*8a978a17SVictor Perevertkin     InsertTailList(&m_ChildListHead, &ChildObject->m_ChildEntry);
755*8a978a17SVictor Perevertkin 
756*8a978a17SVictor Perevertkin     if (ChildObject->GetDeviceBase() == NULL) {
757*8a978a17SVictor Perevertkin         //
758*8a978a17SVictor Perevertkin         // Propagate the device base downward to the child
759*8a978a17SVictor Perevertkin         //
760*8a978a17SVictor Perevertkin         ChildObject->SetDeviceBase(GetDeviceBase());
761*8a978a17SVictor Perevertkin     }
762*8a978a17SVictor Perevertkin 
763*8a978a17SVictor Perevertkin     m_SpinLock.Release(oldIrql);
764*8a978a17SVictor Perevertkin 
765*8a978a17SVictor Perevertkin     return STATUS_SUCCESS;
766*8a978a17SVictor Perevertkin }
767*8a978a17SVictor Perevertkin 
768*8a978a17SVictor Perevertkin _Must_inspect_result_
769*8a978a17SVictor Perevertkin NTSTATUS
RemoveChildObjectInternal(__in FxObject * ChildObject)770*8a978a17SVictor Perevertkin FxObject::RemoveChildObjectInternal(
771*8a978a17SVictor Perevertkin     __in FxObject* ChildObject
772*8a978a17SVictor Perevertkin     )
773*8a978a17SVictor Perevertkin /*++
774*8a978a17SVictor Perevertkin 
775*8a978a17SVictor Perevertkin Routine Description:
776*8a978a17SVictor Perevertkin 
777*8a978a17SVictor Perevertkin     Remove a ChildObject from our child associations list.
778*8a978a17SVictor Perevertkin 
779*8a978a17SVictor Perevertkin     The ChildObject must exist in our list if we are not
780*8a978a17SVictor Perevertkin     otherwise disposing or deleting ourselves.
781*8a978a17SVictor Perevertkin 
782*8a978a17SVictor Perevertkin     If we are not disposing, the child is removed from the list
783*8a978a17SVictor Perevertkin     and its reference count is unmodified.
784*8a978a17SVictor Perevertkin 
785*8a978a17SVictor Perevertkin     If we are disposing, a failure is returned so that the caller
786*8a978a17SVictor Perevertkin     does not delete or dereference the child object itself, since
787*8a978a17SVictor Perevertkin     this is similar to a cancel IRP race condition.
788*8a978a17SVictor Perevertkin 
789*8a978a17SVictor Perevertkin Arguments:
790*8a978a17SVictor Perevertkin     ChildObject - the object to remove this object's list of children
791*8a978a17SVictor Perevertkin 
792*8a978a17SVictor Perevertkin Returns:
793*8a978a17SVictor Perevertkin 
794*8a978a17SVictor Perevertkin     STATUS_SUCCESS - Child was removed from the list, no parent Dispose()
795*8a978a17SVictor Perevertkin                      can occur.
796*8a978a17SVictor Perevertkin 
797*8a978a17SVictor Perevertkin     !STATUS_SUCCESS - Child can not be removed from the list, and is being
798*8a978a17SVictor Perevertkin                       Disposed by the parent. The caller must *not* delete
799*8a978a17SVictor Perevertkin                       the object itself.
800*8a978a17SVictor Perevertkin 
801*8a978a17SVictor Perevertkin --*/
802*8a978a17SVictor Perevertkin 
803*8a978a17SVictor Perevertkin {
804*8a978a17SVictor Perevertkin     KIRQL oldIrql;
805*8a978a17SVictor Perevertkin 
806*8a978a17SVictor Perevertkin     m_SpinLock.Acquire(&oldIrql);
807*8a978a17SVictor Perevertkin 
808*8a978a17SVictor Perevertkin     //
809*8a978a17SVictor Perevertkin     // Object is already being deleted, this object will be removed as a child
810*8a978a17SVictor Perevertkin     // by the parents Dispose()
811*8a978a17SVictor Perevertkin     //
812*8a978a17SVictor Perevertkin     if (m_ObjectState != FxObjectStateCreated) {
813*8a978a17SVictor Perevertkin         TraceDroppedEvent(FxObjectDroppedEventRemoveChildObjectInternal);
814*8a978a17SVictor Perevertkin         m_SpinLock.Release(oldIrql);
815*8a978a17SVictor Perevertkin         return STATUS_DELETE_PENDING;
816*8a978a17SVictor Perevertkin     }
817*8a978a17SVictor Perevertkin 
818*8a978a17SVictor Perevertkin     //
819*8a978a17SVictor Perevertkin     // We should be the child object's parent
820*8a978a17SVictor Perevertkin     //
821*8a978a17SVictor Perevertkin     ASSERT(ChildObject->m_ParentObject == this);
822*8a978a17SVictor Perevertkin 
823*8a978a17SVictor Perevertkin     //
824*8a978a17SVictor Perevertkin     // Child should be on our list
825*8a978a17SVictor Perevertkin     //
826*8a978a17SVictor Perevertkin     ASSERT(!IsListEmpty(&ChildObject->m_ChildEntry));
827*8a978a17SVictor Perevertkin 
828*8a978a17SVictor Perevertkin     //
829*8a978a17SVictor Perevertkin     // We should have entries if someone wants to remove from our list
830*8a978a17SVictor Perevertkin     //
831*8a978a17SVictor Perevertkin     ASSERT(!IsListEmpty(&m_ChildListHead));
832*8a978a17SVictor Perevertkin 
833*8a978a17SVictor Perevertkin     RemoveEntryList(&ChildObject->m_ChildEntry);
834*8a978a17SVictor Perevertkin 
835*8a978a17SVictor Perevertkin     //
836*8a978a17SVictor Perevertkin     // Mark it removed
837*8a978a17SVictor Perevertkin     //
838*8a978a17SVictor Perevertkin     InitializeListHead(&ChildObject->m_ChildEntry);
839*8a978a17SVictor Perevertkin 
840*8a978a17SVictor Perevertkin     //
841*8a978a17SVictor Perevertkin     // We did not take a reference on the child object when it
842*8a978a17SVictor Perevertkin     // was added to the list, so we do not dereference it
843*8a978a17SVictor Perevertkin     // on the remove call.
844*8a978a17SVictor Perevertkin     //
845*8a978a17SVictor Perevertkin     // Note: We only dereference child objects when we are deleted
846*8a978a17SVictor Perevertkin     //       ourselves, not when the child object manually breaks the
847*8a978a17SVictor Perevertkin     //       association by calling this method.
848*8a978a17SVictor Perevertkin     //
849*8a978a17SVictor Perevertkin     m_SpinLock.Release(oldIrql);
850*8a978a17SVictor Perevertkin 
851*8a978a17SVictor Perevertkin     return STATUS_SUCCESS;
852*8a978a17SVictor Perevertkin }
853*8a978a17SVictor Perevertkin 
854*8a978a17SVictor Perevertkin _Must_inspect_result_
855*8a978a17SVictor Perevertkin FxObject*
GetParentObjectReferenced(__in PVOID Tag)856*8a978a17SVictor Perevertkin FxObject::GetParentObjectReferenced(
857*8a978a17SVictor Perevertkin     __in PVOID Tag
858*8a978a17SVictor Perevertkin     )
859*8a978a17SVictor Perevertkin 
860*8a978a17SVictor Perevertkin /*++
861*8a978a17SVictor Perevertkin 
862*8a978a17SVictor Perevertkin Routine Description:
863*8a978a17SVictor Perevertkin      Return this objects parent, which could be NULL if
864*8a978a17SVictor Perevertkin      the object is not part of an association, or this or
865*8a978a17SVictor Perevertkin      the parent object is deleting.
866*8a978a17SVictor Perevertkin 
867*8a978a17SVictor Perevertkin      An extra reference is taken on the parent object which
868*8a978a17SVictor Perevertkin      must eventually be released by the caller.
869*8a978a17SVictor Perevertkin 
870*8a978a17SVictor Perevertkin Arguments:
871*8a978a17SVictor Perevertkin     Tag - Tag to use when referencing the parent
872*8a978a17SVictor Perevertkin 
873*8a978a17SVictor Perevertkin Returns:
874*8a978a17SVictor Perevertkin 
875*8a978a17SVictor Perevertkin     Parent object, otherwise NULL if no parent for this object
876*8a978a17SVictor Perevertkin 
877*8a978a17SVictor Perevertkin --*/
878*8a978a17SVictor Perevertkin 
879*8a978a17SVictor Perevertkin {
880*8a978a17SVictor Perevertkin     KIRQL oldIrql;
881*8a978a17SVictor Perevertkin     FxObject* parentObject;
882*8a978a17SVictor Perevertkin 
883*8a978a17SVictor Perevertkin     m_SpinLock.Acquire(&oldIrql);
884*8a978a17SVictor Perevertkin 
885*8a978a17SVictor Perevertkin     if (m_ObjectState == FxObjectStateCreated) {
886*8a978a17SVictor Perevertkin         parentObject = m_ParentObject;
887*8a978a17SVictor Perevertkin     }
888*8a978a17SVictor Perevertkin     else {
889*8a978a17SVictor Perevertkin         // Parent is disposing us, or we are being disposed
890*8a978a17SVictor Perevertkin         parentObject = NULL;
891*8a978a17SVictor Perevertkin     }
892*8a978a17SVictor Perevertkin 
893*8a978a17SVictor Perevertkin     if (parentObject != NULL) {
894*8a978a17SVictor Perevertkin         parentObject->ADDREF(Tag);
895*8a978a17SVictor Perevertkin     }
896*8a978a17SVictor Perevertkin 
897*8a978a17SVictor Perevertkin     m_SpinLock.Release(oldIrql);
898*8a978a17SVictor Perevertkin 
899*8a978a17SVictor Perevertkin     return parentObject;
900*8a978a17SVictor Perevertkin }
901*8a978a17SVictor Perevertkin 
902*8a978a17SVictor Perevertkin _Must_inspect_result_
903*8a978a17SVictor Perevertkin NTSTATUS
Commit(__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,__out_opt WDFOBJECT * ObjectHandle,__in_opt FxObject * Parent,__in BOOLEAN AssignDriverAsDefaultParent)904*8a978a17SVictor Perevertkin FxObject::Commit(
905*8a978a17SVictor Perevertkin     __in_opt    PWDF_OBJECT_ATTRIBUTES Attributes,
906*8a978a17SVictor Perevertkin     __out_opt   WDFOBJECT*             ObjectHandle,
907*8a978a17SVictor Perevertkin     __in_opt    FxObject* Parent,
908*8a978a17SVictor Perevertkin     __in        BOOLEAN  AssignDriverAsDefaultParent
909*8a978a17SVictor Perevertkin     )
910*8a978a17SVictor Perevertkin /*++
911*8a978a17SVictor Perevertkin 
912*8a978a17SVictor Perevertkin Routine Description:
913*8a978a17SVictor Perevertkin      Commit the object before returning the handle to the caller.
914*8a978a17SVictor Perevertkin 
915*8a978a17SVictor Perevertkin Arguments:
916*8a978a17SVictor Perevertkin      Attributes - PWDF_OBJECT_ATTRIBUTES to assign to this object
917*8a978a17SVictor Perevertkin 
918*8a978a17SVictor Perevertkin      ObjectHandle - Location to return the objects handle
919*8a978a17SVictor Perevertkin 
920*8a978a17SVictor Perevertkin Returns:
921*8a978a17SVictor Perevertkin      NTSTATUS of the result. STATUS_SUCCESS if success.
922*8a978a17SVictor Perevertkin 
923*8a978a17SVictor Perevertkin      Returns WDFOBJECT handle if success.
924*8a978a17SVictor Perevertkin 
925*8a978a17SVictor Perevertkin --*/
926*8a978a17SVictor Perevertkin {
927*8a978a17SVictor Perevertkin     NTSTATUS status;
928*8a978a17SVictor Perevertkin     WDFOBJECT object;
929*8a978a17SVictor Perevertkin     FxObject* parent;
930*8a978a17SVictor Perevertkin 
931*8a978a17SVictor Perevertkin     parent = NULL;
932*8a978a17SVictor Perevertkin 
933*8a978a17SVictor Perevertkin     if (m_ObjectSize == 0) {
934*8a978a17SVictor Perevertkin         ASSERTMSG("Only external objects can call Commit()\n",
935*8a978a17SVictor Perevertkin                   m_ObjectSize != 0);
936*8a978a17SVictor Perevertkin         return STATUS_INVALID_HANDLE;
937*8a978a17SVictor Perevertkin     }
938*8a978a17SVictor Perevertkin 
939*8a978a17SVictor Perevertkin     //
940*8a978a17SVictor Perevertkin     // For an object to be committed into a handle, it needs to have an object
941*8a978a17SVictor Perevertkin     // size.  Internal objects set their size to zero as the indication they
942*8a978a17SVictor Perevertkin     // are internal and will not be converted into handles.
943*8a978a17SVictor Perevertkin     //
944*8a978a17SVictor Perevertkin     ASSERT(m_ObjectSize != 0);
945*8a978a17SVictor Perevertkin 
946*8a978a17SVictor Perevertkin     //
947*8a978a17SVictor Perevertkin     // Caller has already validated basic WDF_OBJECT_ATTRIBUTES
948*8a978a17SVictor Perevertkin     // with FxValidateObjectAttributes
949*8a978a17SVictor Perevertkin     //
950*8a978a17SVictor Perevertkin 
951*8a978a17SVictor Perevertkin     //
952*8a978a17SVictor Perevertkin     // Set object execution level constraint if specified
953*8a978a17SVictor Perevertkin     //
954*8a978a17SVictor Perevertkin     if (Attributes != NULL &&
955*8a978a17SVictor Perevertkin         Attributes->ExecutionLevel == WdfExecutionLevelPassive) {
956*8a978a17SVictor Perevertkin         MarkPassiveCallbacks();
957*8a978a17SVictor Perevertkin     }
958*8a978a17SVictor Perevertkin 
959*8a978a17SVictor Perevertkin     //
960*8a978a17SVictor Perevertkin     // Assign parent if supplied
961*8a978a17SVictor Perevertkin     //
962*8a978a17SVictor Perevertkin     if (Parent != NULL) {
963*8a978a17SVictor Perevertkin         parent = Parent;
964*8a978a17SVictor Perevertkin     }
965*8a978a17SVictor Perevertkin     else if (Attributes != NULL && Attributes->ParentObject != NULL) {
966*8a978a17SVictor Perevertkin         FxObjectHandleGetPtr(
967*8a978a17SVictor Perevertkin             m_Globals,
968*8a978a17SVictor Perevertkin             Attributes->ParentObject,
969*8a978a17SVictor Perevertkin             FX_TYPE_OBJECT,
970*8a978a17SVictor Perevertkin             (PVOID*)&parent
971*8a978a17SVictor Perevertkin             );
972*8a978a17SVictor Perevertkin     }
973*8a978a17SVictor Perevertkin     else {
974*8a978a17SVictor Perevertkin 
975*8a978a17SVictor Perevertkin         //
976*8a978a17SVictor Perevertkin         // If the object already does not have a parent, and
977*8a978a17SVictor Perevertkin         // one has not been specified we default it to FxDriver.
978*8a978a17SVictor Perevertkin         //
979*8a978a17SVictor Perevertkin         // We check to ensure we are not FxDriver being created.
980*8a978a17SVictor Perevertkin         //
981*8a978a17SVictor Perevertkin         if (AssignDriverAsDefaultParent &&
982*8a978a17SVictor Perevertkin             m_ParentObject == NULL) {
983*8a978a17SVictor Perevertkin 
984*8a978a17SVictor Perevertkin                 //parent = FxToObjectItf::FxGetDriverAsDefaultParent(m_Globals, this);
985*8a978a17SVictor Perevertkin 
986*8a978a17SVictor Perevertkin 
987*8a978a17SVictor Perevertkin                 if (m_Globals->Driver != this) {
988*8a978a17SVictor Perevertkin                     parent = m_Globals->Driver;
989*8a978a17SVictor Perevertkin                 }
990*8a978a17SVictor Perevertkin 
991*8a978a17SVictor Perevertkin         }
992*8a978a17SVictor Perevertkin     }
993*8a978a17SVictor Perevertkin 
994*8a978a17SVictor Perevertkin     ASSERT(parent != this);
995*8a978a17SVictor Perevertkin 
996*8a978a17SVictor Perevertkin     if (parent != NULL) {
997*8a978a17SVictor Perevertkin         //
998*8a978a17SVictor Perevertkin         // Make it the parent of this object
999*8a978a17SVictor Perevertkin         //
1000*8a978a17SVictor Perevertkin         status = AssignParentObject(parent);
1001*8a978a17SVictor Perevertkin 
1002*8a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
1003*8a978a17SVictor Perevertkin             return status;
1004*8a978a17SVictor Perevertkin         }
1005*8a978a17SVictor Perevertkin     }
1006*8a978a17SVictor Perevertkin 
1007*8a978a17SVictor Perevertkin     //
1008*8a978a17SVictor Perevertkin     // Now assign the optional EvtObjectCleanup, EvtObjectDestroy callbacks
1009*8a978a17SVictor Perevertkin     //
1010*8a978a17SVictor Perevertkin     if (Attributes != NULL) {
1011*8a978a17SVictor Perevertkin         FxContextHeader* pHeader;
1012*8a978a17SVictor Perevertkin 
1013*8a978a17SVictor Perevertkin         pHeader = GetContextHeader();
1014*8a978a17SVictor Perevertkin 
1015*8a978a17SVictor Perevertkin         if (Attributes->EvtDestroyCallback != NULL) {
1016*8a978a17SVictor Perevertkin             pHeader->EvtDestroyCallback = Attributes->EvtDestroyCallback;
1017*8a978a17SVictor Perevertkin         }
1018*8a978a17SVictor Perevertkin 
1019*8a978a17SVictor Perevertkin         if (Attributes->EvtCleanupCallback != NULL) {
1020*8a978a17SVictor Perevertkin             pHeader->EvtCleanupCallback = Attributes->EvtCleanupCallback;
1021*8a978a17SVictor Perevertkin             m_ObjectFlags |= FXOBJECT_FLAGS_HAS_CLEANUP;
1022*8a978a17SVictor Perevertkin         }
1023*8a978a17SVictor Perevertkin     }
1024*8a978a17SVictor Perevertkin 
1025*8a978a17SVictor Perevertkin     //
1026*8a978a17SVictor Perevertkin     // We mark the handle as committed so that we can create the handle.
1027*8a978a17SVictor Perevertkin     //
1028*8a978a17SVictor Perevertkin     MarkCommitted();
1029*8a978a17SVictor Perevertkin 
1030*8a978a17SVictor Perevertkin     //
1031*8a978a17SVictor Perevertkin     // Create the object handle, assign EvtObjectCleanup, EvtObjectDestroy
1032*8a978a17SVictor Perevertkin     //
1033*8a978a17SVictor Perevertkin     FxObjectHandleCreate(this, &object);
1034*8a978a17SVictor Perevertkin 
1035*8a978a17SVictor Perevertkin     if (ObjectHandle != NULL) {
1036*8a978a17SVictor Perevertkin         *ObjectHandle = object;
1037*8a978a17SVictor Perevertkin     }
1038*8a978a17SVictor Perevertkin 
1039*8a978a17SVictor Perevertkin     return STATUS_SUCCESS;
1040*8a978a17SVictor Perevertkin }
1041*8a978a17SVictor Perevertkin 
1042*8a978a17SVictor Perevertkin _Must_inspect_result_
1043*8a978a17SVictor Perevertkin NTSTATUS
_GetEffectiveLock(__in FxObject * Object,__in_opt IFxHasCallbacks * Callbacks,__in BOOLEAN AutomaticLocking,__in BOOLEAN PassiveCallbacks,__out FxCallbackLock ** CallbackLock,__out_opt FxObject ** CallbackLockObject)1044*8a978a17SVictor Perevertkin FxObject::_GetEffectiveLock(
1045*8a978a17SVictor Perevertkin     __in        FxObject* Object,
1046*8a978a17SVictor Perevertkin     __in_opt    IFxHasCallbacks* Callbacks,
1047*8a978a17SVictor Perevertkin     __in        BOOLEAN AutomaticLocking,
1048*8a978a17SVictor Perevertkin     __in        BOOLEAN PassiveCallbacks,
1049*8a978a17SVictor Perevertkin     __out       FxCallbackLock** CallbackLock,
1050*8a978a17SVictor Perevertkin     __out_opt   FxObject** CallbackLockObject
1051*8a978a17SVictor Perevertkin     )
1052*8a978a17SVictor Perevertkin /*++
1053*8a978a17SVictor Perevertkin 
1054*8a978a17SVictor Perevertkin Routine Description:
1055*8a978a17SVictor Perevertkin 
1056*8a978a17SVictor Perevertkin     This gets the effective lock based on the callback constraints
1057*8a978a17SVictor Perevertkin     configuration of the supplied object.
1058*8a978a17SVictor Perevertkin 
1059*8a978a17SVictor Perevertkin     This is a common routine shared by all FxObject's that utilize
1060*8a978a17SVictor Perevertkin     DPC's. Currently, this is FxDpc, FxTimer, and FxInterrupt.
1061*8a978a17SVictor Perevertkin 
1062*8a978a17SVictor Perevertkin     This contains the common serialization configuration logic for these
1063*8a978a17SVictor Perevertkin     objects.
1064*8a978a17SVictor Perevertkin 
1065*8a978a17SVictor Perevertkin Arguments:
1066*8a978a17SVictor Perevertkin 
1067*8a978a17SVictor Perevertkin     Object - Object to serialize with
1068*8a978a17SVictor Perevertkin 
1069*8a978a17SVictor Perevertkin     Callbacks - Optional interface for acquiring constraints and locking pointers
1070*8a978a17SVictor Perevertkin 
1071*8a978a17SVictor Perevertkin     AutomaticLocking - TRUE if automatic serialization with Object is required
1072*8a978a17SVictor Perevertkin 
1073*8a978a17SVictor Perevertkin     PassiveCallbacks - TRUE if the caller requires passive level callback, FALSE
1074*8a978a17SVictor Perevertkin                        if the
1075*8a978a17SVictor Perevertkin     CallbackLock - Lock that is in effect for Object
1076*8a978a17SVictor Perevertkin 
1077*8a978a17SVictor Perevertkin     CallbackLockOjbect - FxObject that contains the callback lock
1078*8a978a17SVictor Perevertkin 
1079*8a978a17SVictor Perevertkin Returns:
1080*8a978a17SVictor Perevertkin 
1081*8a978a17SVictor Perevertkin     NTSTATUS
1082*8a978a17SVictor Perevertkin 
1083*8a978a17SVictor Perevertkin --*/
1084*8a978a17SVictor Perevertkin {
1085*8a978a17SVictor Perevertkin     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1086*8a978a17SVictor Perevertkin     WDF_EXECUTION_LEVEL parentLevel;
1087*8a978a17SVictor Perevertkin     WDF_SYNCHRONIZATION_SCOPE parentScope;
1088*8a978a17SVictor Perevertkin 
1089*8a978a17SVictor Perevertkin     pFxDriverGlobals = Object->GetDriverGlobals();
1090*8a978a17SVictor Perevertkin     *CallbackLock = NULL;
1091*8a978a17SVictor Perevertkin     *CallbackLockObject = NULL;
1092*8a978a17SVictor Perevertkin 
1093*8a978a17SVictor Perevertkin     //
1094*8a978a17SVictor Perevertkin     // No automatic locking, nothing to do
1095*8a978a17SVictor Perevertkin     //
1096*8a978a17SVictor Perevertkin     if (AutomaticLocking == FALSE) {
1097*8a978a17SVictor Perevertkin         return STATUS_SUCCESS;
1098*8a978a17SVictor Perevertkin     }
1099*8a978a17SVictor Perevertkin 
1100*8a978a17SVictor Perevertkin     //
1101*8a978a17SVictor Perevertkin     // Objects that have callback locks must support this interface.
1102*8a978a17SVictor Perevertkin     //
1103*8a978a17SVictor Perevertkin     if (Callbacks == NULL) {
1104*8a978a17SVictor Perevertkin         return STATUS_INVALID_DEVICE_REQUEST;
1105*8a978a17SVictor Perevertkin     }
1106*8a978a17SVictor Perevertkin 
1107*8a978a17SVictor Perevertkin     //
1108*8a978a17SVictor Perevertkin     // Get the callback constraints in effect for the object
1109*8a978a17SVictor Perevertkin     //
1110*8a978a17SVictor Perevertkin     Callbacks->GetConstraints(&parentLevel, &parentScope);
1111*8a978a17SVictor Perevertkin 
1112*8a978a17SVictor Perevertkin     if (parentScope == WdfSynchronizationScopeInheritFromParent ||
1113*8a978a17SVictor Perevertkin         parentScope == WdfSynchronizationScopeNone) {
1114*8a978a17SVictor Perevertkin         //
1115*8a978a17SVictor Perevertkin         // Do nothing, no synchronization specified
1116*8a978a17SVictor Perevertkin         //
1117*8a978a17SVictor Perevertkin         DO_NOTHING();
1118*8a978a17SVictor Perevertkin     }
1119*8a978a17SVictor Perevertkin     else {
1120*8a978a17SVictor Perevertkin         //
1121*8a978a17SVictor Perevertkin         // If the caller wants passive callbacks and the object does not support
1122*8a978a17SVictor Perevertkin         // it, failure.
1123*8a978a17SVictor Perevertkin         //
1124*8a978a17SVictor Perevertkin         // If the caller wants non passive callbacks and the object supports
1125*8a978a17SVictor Perevertkin         // passive only callbacks, failure.
1126*8a978a17SVictor Perevertkin         //
1127*8a978a17SVictor Perevertkin         if ((PassiveCallbacks && Object->IsPassiveCallbacks() == FALSE) ||
1128*8a978a17SVictor Perevertkin             (PassiveCallbacks == FALSE && Object->IsPassiveCallbacks())) {
1129*8a978a17SVictor Perevertkin             FxVerifierDbgBreakPoint(pFxDriverGlobals);
1130*8a978a17SVictor Perevertkin             return STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL;
1131*8a978a17SVictor Perevertkin         }
1132*8a978a17SVictor Perevertkin 
1133*8a978a17SVictor Perevertkin         *CallbackLock = Callbacks->GetCallbackLockPtr(CallbackLockObject);
1134*8a978a17SVictor Perevertkin     }
1135*8a978a17SVictor Perevertkin 
1136*8a978a17SVictor Perevertkin     return STATUS_SUCCESS;
1137*8a978a17SVictor Perevertkin }
1138