1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxObject.hpp
8 
9 Abstract:
10 
11     This is the C++ header for the FxObject
12 
13 Author:
14 
15 
16 
17 
18 Revision History:
19 
20 
21         Made mode agnostic
22 
23         IMPORTANT: Common code must call Initialize method of
24         FxObject before using it
25 
26         Cannot put CreateAndInitialize method on this class as it
27         cannot be instantiated
28 
29 
30 --*/
31 
32 #ifndef _FXOBJECT_H_
33 #define _FXOBJECT_H_
34 
35 extern "C" {
36 
37 #if defined(EVENT_TRACING)
38 #include "FxObject.hpp.tmh"
39 #endif
40 
41 }
42 
43 //
44 // Macros to pass line and file information to AddRef and Release calls.
45 //
46 // NOTE:  ADDREF and RELEASE can be used by any class derived from FxObject or
47 //        IFxMemory while the OFFSET only works with an FxObject derivation
48 //
49 #define ADDREF(_tag)    AddRef(_tag, __LINE__, __FILE__)
50 #define RELEASE(_tag)   Release(_tag, __LINE__, __FILE__)
51 
52 #define ADDREF_OFFSET(_tag, offset)    AddRefOverride(offset, _tag, __LINE__, __FILE__)
53 #define RELEASE_OFFSET(_tag, offset)   ReleaseOverride(offset, _tag, __LINE__, __FILE__)
54 
55 //
56 // This assumes that the bottom 3 bits of an FxObject are clear, ie that the
57 // FxObject is 8 byte aligned.  The conversion from and to a handle value
58 // will set / clear these bits as appropriate.
59 //
60 enum FxHandleFlags {
61     FxHandleFlagIsOffset = 0x1,
62     FxHandleFlagMask     = 0x7, // bottom 3 bits are free
63 };
64 
65 //
66 // We cannot define FxHandleValueMask as an enumerant in FxHandleFlags because
67 // an enum is limited to sizeof(ULONG), which doesn't work for us on a 64 bit OS
68 //
69 extern DECLSPEC_SELECTANY const ULONG_PTR FxHandleValueMask = (~((ULONG_PTR) FxHandleFlagMask));
70 
71 //
72 // The type itself is aligned, but the pointer is not b/c those interested in the
73 // offset do not need it to be aligned.
74 //
75 // The offset is aligned on an 8 byte boundary so that we have the lower 3 bits
76 // of the low byte to use for a bit field
77 //
78 typedef DECLSPEC_ALIGN(8) USHORT WDFOBJECT_OFFSET_ALIGNED;
79 
80 typedef USHORT WDFOBJECT_OFFSET, *PWDFOBJECT_OFFSET;
81 
82 struct FxQueryInterfaceParams {
83     //
84     // We intentionally do not declare a constructor for this structure.
85     // Instead, code should use an inline initializer list.  This reduces the
86     // number of cycles on hot paths by removing a funciton call.
87     //
88     // FxQueryInterfaceParams(
89     //     PVOID* Object,
90     //     WDFTYPE Type
91     //     ) :
92     // Type(Type), Object(Object), Offset(0) {if (Object != NULL) *Object = NULL; }}
93 
94     //
95     // Object to query for
96     //
97     PVOID* Object;
98 
99     //
100     // Type for the object to query for
101     //
102     WDFTYPE Type;
103 
104     //
105     // Offset of handle within its owning object.  If zero, the Object was the
106     // handle.  If not zero, ((PUCHAR) Object)-Offset will yield the owning
107     // Object.
108     //
109     WDFOBJECT_OFFSET Offset;
110 };
111 
112 //
113 // type of object being allocated.  An internal object does *NOT*
114 // 1) have its size rounded up to an alignment value
115 // 2) extra size and context header appended to the allocation
116 //
117 enum FxObjectType : UINT32 {
118     FxObjectTypeInvalid = 0,
119     FxObjectTypeInternal,
120     FxObjectTypeExternal,
121     FxObjectTypeEmbedded,
122 };
123 
124 // Ensures that a BOOL type is generated from a flag mask
125 #define FLAG_TO_BOOL(_Flags, _FlagMask) (!!((_Flags) & (_FlagMask)))
126 
127 enum FxObjectLockState {
128     ObjectDoNotLock = 0,
129     ObjectLock = 1
130 };
131 
132 //
133 // Defines for FxObject::m_ObjectFlags
134 //
135 // NOTE:  if you modify (add, remove, reassign a value) this enum in any way
136 //        you must also change FxObject::m_ObjectFlagsByName.* to match your changes!!
137 //
138 enum FXOBJECT_FLAGS {
139     FXOBJECT_FLAGS_PASSIVE_CALLBACKS = 0x00000001, // Object must have all callbacks at passive level
140                                                    // implies passive destroy
141     FXOBJECT_FLAGS_NODELETEDDI      = 0x00000002,  // The WdfObjectDelete DDI is invalid
142     FXOBJECT_FLAGS_DELETECALLED     = 0x00000004,  // DeleteObject method called
143     FXOBJECT_FLAGS_COMMITTED        = 0x00000008,  // Commit called
144     FXOBJECT_FLAGS_PASSIVE_DISPOSE  = 0x00000010, // Object must be Dispose()'d at passive level
145     FXOBJECT_FLAGS_FORCE_DISPOSE_THREAD  = 0x00000020, // Object is always disposed in the dispose thread
146     // UNUSED                       = 0x00000040,
147     FXOBJECT_FLAGS_HAS_DEBUG        = 0x00000080, // has FxObjectDebugExtension before object pointer
148     FXOBJECT_FLAGS_EARLY_DISPOSED_EXT = 0x00000100,  // Early disposed externally to the state machine
149     FXOBJECT_FLAGS_TRACE_STATE      = 0x00000200, // log state changes to the IFR
150     FXOBJECT_FLAGS_HAS_CLEANUP      = 0x00000400,
151     FXOBJECT_FLAGS_DISPOSE_OVERRIDE = 0x00000800,
152 };
153 
154 //
155 // FxObject state represents whether an object is
156 // tearing down, and what phase its in.
157 //
158 enum FxObjectState {
159     FxObjectStateInvalid = 0,
160     FxObjectStateCreated,
161     FxObjectStateDisposed,
162     FxObjectStateDisposingEarly,
163     FxObjectStateDisposingDisposeChildren,
164     FxObjectStateDeferedDisposing,
165     FxObjectStateDeferedDeleting,
166     FxObjectStateWaitingForEarlyDispose,
167     FxObjectStateWaitingForParentDeleteAndDisposed,
168     FxObjectStateDeletedDisposing,
169     FxObjectStateDeletedAndDisposed,
170     FxObjectStateDeferedDestroy,
171     FxObjectStateDestroyed,
172     FxObjectStateMaximum,
173 };
174 
175 enum FxObjectDroppedEvent {
176     FxObjectDroppedEventAssignParentObject = 0,
177     FxObjectDroppedEventAddChildObjectInternal,
178     FxObjectDroppedEventRemoveChildObjectInternal,
179     FxObjectDroppedEventDeleteObject,
180     FxObjectDroppedEventPerformEarlyDispose,
181     FxObjectDroppedEventRemoveParentAssignment,
182     FxObjectDroppedEventParentDeleteEvent,
183 };
184 
185 // begin_wpp config
186 // CUSTOM_TYPE(FxObjectState, ItemEnum(FxObjectState));
187 // CUSTOM_TYPE(FxObjectDroppedEvent, ItemEnum(FxObjectDroppedEvent));
188 // end_wpp
189 
190 #define DECLARE_INTERNAL_NEW_OPERATOR()                     \
191     PVOID                                                   \
192     __inline                                             \
193     operator new(                                           \
194         __in size_t Size,                                        \
195         __in PFX_DRIVER_GLOBALS FxDriverGlobals                 \
196         )                                                   \
197     {                                                       \
198         return FxObjectHandleAlloc(FxDriverGlobals,         \
199                                    NonPagedPool,            \
200                                    Size,                    \
201                                    0,                       \
202                                    WDF_NO_OBJECT_ATTRIBUTES,\
203                                    0,                       \
204                                    FxObjectTypeInternal);   \
205     }
206 
207 struct FxObjectDebugExtension {
208     FxTagTracker* TagTracker;
209 
210     FxVerifierLock* VerifierLock;
211 
212     BYTE StateHistory[8];
213 
214     LONG StateHistoryIndex;
215 
216     //
217     // Signature lives after all the fields to avoid byte padding if it is
218     // first on 64 bit systems.
219     //
220     ULONG Signature;
221 
222     DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) ULONG AllocationStart[1];
223 };
224 
225 enum FxObjectDebugExtensionValues {
226     FxObjectDebugExtensionSize  = FIELD_OFFSET(FxObjectDebugExtension, AllocationStart),
227     FxObjectDebugExtensionSignature = 'DOxF',
228 };
229 
230 class UfxObject;
231 
232 class FxObject {
233 
234     friend UfxObject; //UMDF object wrapper
235 
236     friend FxDisposeList;
237     friend VOID GetTriageInfo(VOID);
238 
239 private:
240 
241 #if FX_CORE_MODE==FX_CORE_USER_MODE
242 #ifndef INLINE_WRAPPER_ALLOCATION
243     PVOID         m_COMWrapper;
244 #endif
245 #endif
246 
247     WDFTYPE       m_Type;
248 
249     //
250     // This is the already computed value of
251     // WDF_ALIGN_SIZE_UP(sizeof(derived object), MEMORY_ALLOCATION_ALIGNMENT) +
252     // WDF_ALIGN_SIZE_UP(extraContext, MEMORY_ALLOCATION_ALIGNMENT)
253     //
254     USHORT        m_ObjectSize;
255 
256     // Reference count is operated on with interlocked operations
257     LONG          m_Refcnt;
258 
259     PFX_DRIVER_GLOBALS m_Globals;
260 
261     // Flags are protected by m_SpinLock, bits defined by the enum FXOBJECT_FLAGS
262     union {
263         USHORT         m_ObjectFlags;
264 
265         // Each field in this struct correspond to ascending enumerant values
266         // in FXOBJECT_FLAGS.
267         //
268         // NOTE:  you should never touch these fields in any code, they are here
269         //        strictly for use by the debugger extension so that it doesn't
270         //       have to result FXOBJECT_FLAGS enumerant name strings into values.
271         //
272         struct {
273             USHORT PassiveCallbacks : 1;
274             USHORT NoDeleteDDI : 1;
275             USHORT DeleteCalled : 1;
276             USHORT Committed : 1;
277             USHORT PassiveDispose : 1;
278             USHORT ForceDisposeThread : 1;
279             USHORT Unused  : 1;
280             USHORT HasDebug : 1;
281             USHORT EarlyDisposedExt : 1;
282             USHORT TraceState : 1;
283         } m_ObjectFlagsByName;
284     };
285 
286     //
287     // m_ObjectState is protected by m_SpinLock.  Contains values in the
288     // FxObjectState enum.
289     //
290     USHORT m_ObjectState;
291 
292     // List of Child Objects
293     LIST_ENTRY m_ChildListHead;
294 
295     // SpinLock protects m_ObjectState, m_ObjectFlags, m_ChildListHead, and m_ParentObject
296     MxLock m_SpinLock;
297 
298     //
299     // Parent object when this object is a child.
300     //
301     // This is protected by the child objects m_SpinLock
302     //
303     FxObject*  m_ParentObject;
304 
305     //
306     // Link for when this object is a child
307     //
308     // This is accessed by the parent of this object, and
309     // protected by the parents spinlock.
310     //
311     LIST_ENTRY m_ChildEntry;
312 
313     //
314     //
315     //
316     SINGLE_LIST_ENTRY m_DisposeSingleEntry;
317 
318 protected:
319     union {
320         //
321         // This field is set when the object is being contructed or before
322         // Commit() and from then on is read only.
323         //
324         // FxDeviceBase* is used by the core object state machine.  Derived
325         // objects might need the fuller FxDevice* (and they can safely get at
326         // it since they know they are a part of the derived FxDevice*).
327         //
328         CfxDeviceBase* m_DeviceBase;
329         CfxDevice* m_Device;
330     };
331 
332 private:
FxObject(VOID)333     FxObject(
334         VOID
335         )
336     {
337         // Always make the caller supply a type and size
338     }
339 
340     // Do not specify argument names
341     FX_DECLARE_VF_FUNCTION_P1(
342     VOID,
343     VerifyConstruct,
344         _In_ BOOLEAN
345         );
346 
347     VOID
348     __inline
Construct(__in BOOLEAN Embedded)349     Construct(
350         __in BOOLEAN Embedded
351         )
352     {
353         m_Refcnt = 1;
354         m_ObjectState = FxObjectStateCreated;
355         m_ObjectFlags = 0;
356         m_ParentObject = NULL;
357 
358         InitializeListHead(&m_ChildListHead);
359         InitializeListHead(&m_ChildEntry);
360         m_DisposeSingleEntry.Next = NULL;
361 
362         m_DeviceBase = NULL;
363 
364         VerifyConstruct(m_Globals, Embedded);
365     }
366 
367     VOID
368     __inline
SetObjectStateLocked(__in FxObjectState NewState)369     SetObjectStateLocked(
370         __in FxObjectState NewState
371         )
372     {
373         if (m_ObjectFlags & FXOBJECT_FLAGS_TRACE_STATE) {
374             DoTraceLevelMessage(
375                 m_Globals, TRACE_LEVEL_VERBOSE, TRACINGOBJECT,
376                 "Object %p, WDFOBJECT %p transitioning from %!FxObjectState! to "
377                 "%!FxObjectState!", this, GetObjectHandleUnchecked(),
378                 m_ObjectState, NewState);
379             if (IsDebug()) {
380                 FxObjectDebugExtension* pExtension;
381 
382                 pExtension = GetDebugExtension();
383                 pExtension->StateHistory[
384                     InterlockedIncrement(&pExtension->StateHistoryIndex)] =
385                     (BYTE) NewState;
386             }
387         }
388 
389         m_ObjectState = (USHORT) NewState;
390     }
391 
392 protected:
393     FxObject(
394         __in WDFTYPE Type,
395         __in USHORT Size,
396         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
397         __in FxObjectType ObjectType
398         );
399 
400     FxObjectDebugExtension*
GetDebugExtension(VOID)401     GetDebugExtension(
402         VOID
403         )
404     {
405         return CONTAINING_RECORD(this, FxObjectDebugExtension, AllocationStart);
406     }
407 
408     BOOLEAN
IsDebug(VOID)409     IsDebug(
410         VOID
411         )
412     {
413         return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_HAS_DEBUG);
414     }
415 
416     static
417     PVOID
_GetBase(__in FxObject * Object)418     _GetBase(
419         __in FxObject* Object
420         )
421     {
422         if (Object->IsDebug()) {
423             return _GetDebugBase(Object);
424         }
425         else {
426             return (PVOID) Object;
427         }
428     }
429 
430     VOID
431     AllocateTagTracker(
432         __in WDFTYPE Type
433         );
434 
435     virtual
436     VOID
SelfDestruct(VOID)437     SelfDestruct(
438         VOID
439         )
440     {
441         delete this;
442     }
443 
444     PVOID
445     __inline
GetObjectHandleUnchecked(VOID)446     GetObjectHandleUnchecked(
447         VOID
448         )
449     {
450         //
451         // We don't support offset handles in the base FxObject implementation.
452         // Offsets are specialized to internal objects of an FxObject
453         //
454         if (m_ObjectSize > 0) {
455             return _ToHandle(this);
456         }
457         else {
458             return NULL;
459         }
460     }
461 
462     VOID
463     __inline
DestroyChildren(VOID)464     DestroyChildren(
465         VOID
466         )
467     {
468         PLIST_ENTRY ple;
469         FxObject *pChild;
470 
471         while (!IsListEmpty(&m_ChildListHead)) {
472             ple = RemoveHeadList(&m_ChildListHead);
473 
474             pChild = CONTAINING_RECORD(ple, FxObject, m_ChildEntry);
475 
476             //
477             // Mark entry as unlinked
478             //
479             InitializeListHead(&pChild->m_ChildEntry);
480 
481             //
482             // Inform child object of destruction. Object may be gone after return.
483             //
484             pChild->ParentDeleteEvent();
485         }
486     }
487 
488 public:
489 
490 #ifdef INLINE_WRAPPER_ALLOCATION
491 
492 #if FX_CORE_MODE==FX_CORE_USER_MODE
493     static
494     USHORT
495     GetWrapperSize(
496         );
497 
498     virtual
499     PVOID
500     GetCOMWrapper(
501         ) = 0;
502 
503 #else
504     static
505     USHORT
506     __inline
507     GetWrapperSize(
508         )
509     {
510         return 0;
511     }
512 
513 #endif
514 
515 #else
516 
517 #if FX_CORE_MODE==FX_CORE_USER_MODE
518     PVOID GetCOMWrapper(){ return m_COMWrapper; }
519 
520     void SetCOMWrapper(__drv_aliasesMem PVOID Wrapper){ m_COMWrapper = Wrapper; }
521 #endif
522 
523 #endif
524 
525     FxObject(
526         __in WDFTYPE Type,
527         __in USHORT Size,
528         __in PFX_DRIVER_GLOBALS FxDriverGlobals
529         );
530 
531     virtual
532     ~FxObject(
533         VOID
534         );
535 
536     PVOID
537     __inline
operator new(__in size_t Size,__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxObjectType Type)538     operator new(
539         __in size_t Size,
540         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
541         __in FxObjectType Type
542         )
543     {
544         UNREFERENCED_PARAMETER(Type);
545 
546         return FxObjectHandleAlloc(FxDriverGlobals,
547                                    NonPagedPool,
548                                    Size,
549                                    0,
550                                    WDF_NO_OBJECT_ATTRIBUTES,
551                                    0,
552                                    Type);
553     }
554 
555     PVOID
556     __inline
operator new(__in size_t Size,__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,__in USHORT ExtraSize=0)557     operator new(
558         __in        size_t Size,
559         __in        PFX_DRIVER_GLOBALS FxDriverGlobals,
560         __in_opt    PWDF_OBJECT_ATTRIBUTES Attributes,
561         __in USHORT ExtraSize = 0
562         )
563     {
564         return FxObjectHandleAlloc(FxDriverGlobals,
565                                    NonPagedPool,
566                                    Size,
567                                    0,
568                                    Attributes,
569                                    ExtraSize,
570                                    FxObjectTypeExternal);
571     }
572 
573     VOID
574     operator delete(
575         __in PVOID Memory
576         );
577 
578     static
579     FxObject*
_FromDisposeEntry(__in PSINGLE_LIST_ENTRY Entry)580     _FromDisposeEntry(
581         __in PSINGLE_LIST_ENTRY Entry
582         )
583     {
584         return CONTAINING_RECORD(Entry, FxObject, m_DisposeSingleEntry);
585     }
586 
587     //
588     // m_ObjectSize contains the size of the object + extra size.  m_ObjectSize
589     // was already rounded up to the correct alignment when it was contructed.
590     //
591     #define GET_CONTEXT_HEADER() WDF_PTR_ADD_OFFSET_TYPE(this, m_ObjectSize, FxContextHeader*)
592 
593     VOID
SetNoContextHeader(VOID)594     SetNoContextHeader(
595         VOID
596         )
597     {
598         m_ObjectSize = 0;
599     }
600 
601     PVOID
602     __inline
GetObjectHandle(VOID)603     GetObjectHandle(
604         VOID
605         )
606     {
607         ASSERT(GetRefCnt() > 0);
608         return GetObjectHandleUnchecked();
609     }
610 
611     static
612     FxObject*
_GetObjectFromHandle(__in WDFOBJECT Handle,__inout PWDFOBJECT_OFFSET ObjectOffset)613     _GetObjectFromHandle(
614         __in    WDFOBJECT Handle,
615         __inout PWDFOBJECT_OFFSET ObjectOffset
616         )
617     {
618         ULONG_PTR handle, flags;
619 
620         handle = (ULONG_PTR) Handle;
621 
622         //
623         // store the flags and then clear them off so we have a valid value
624         //
625         flags = FxHandleFlagMask & handle;
626         handle &= ~FxHandleFlagMask;
627 
628         //
629         // It is assumed the caller has already set the offset to zero
630         //
631         // *ObjectOffset = 0;
632 
633         //
634         // We always apply the mask
635         //
636         handle = handle ^ FxHandleValueMask;
637 
638         if (flags & FxHandleFlagIsOffset) {
639             //
640             // The handle is a pointer to an offset value.  Return the offset
641             // to the caller and then compute the object since the pointer
642             // to the offset is part of the object we are returning.
643             //
644             *ObjectOffset = *(PWDFOBJECT_OFFSET) handle;
645 
646             return (FxObject*) (((PUCHAR) handle) - *ObjectOffset);
647         }
648         else {
649             //
650             // No offset, no verification.  We pass the FxObject as the handle
651             //
652             return (FxObject*) handle;
653        }
654     }
655 
656     static
657     PVOID
658     __inline
_ToHandle(__in FxObject * Object)659     _ToHandle(
660         __in FxObject* Object
661         )
662     {
663         //
664         // Always XOR the constant. Faster than checking
665         // FxDriverGlobals->FxVerifierHandle.
666         //
667         return (PVOID) (((ULONG_PTR) Object) ^ FxHandleValueMask);
668     }
669 
670     static
671     VOID
672     __inline
_ReferenceActual(__in WDFOBJECT Object,__in_opt PVOID Tag,__in LONG Line,__in PSTR File)673     _ReferenceActual(
674         __in        WDFOBJECT Object,
675         __in_opt    PVOID Tag,
676         __in        LONG Line,
677         __in        PSTR File
678         )
679     {
680         FxObject* pObject;
681         WDFOBJECT_OFFSET offset;
682 
683         offset = 0;
684         pObject = FxObject::_GetObjectFromHandle(Object, &offset);
685 
686         if (offset == 0) {
687             pObject->AddRef(Tag, Line, File);
688         }
689         else {
690             pObject->AddRefOverride(offset, Tag, Line, File);
691         }
692     }
693 
694     static
695     VOID
696     __inline
_DereferenceActual(__in WDFOBJECT Object,__in_opt PVOID Tag,__in LONG Line,__in PSTR File)697     _DereferenceActual(
698         __in        WDFOBJECT Object,
699         __in_opt    PVOID Tag,
700         __in        LONG Line,
701         __in        PSTR File
702         )
703     {
704         FxObject* pObject;
705         WDFOBJECT_OFFSET offset;
706 
707         offset = 0;
708         pObject = FxObject::_GetObjectFromHandle(Object, &offset);
709 
710         if (offset == 0) {
711             pObject->Release(Tag, Line, File);
712         }
713         else {
714             pObject->ReleaseOverride(offset, Tag, Line, File);
715         }
716     }
717 
718     __inline
719     FxContextHeader*
GetContextHeader(VOID)720     GetContextHeader(
721         VOID
722         )
723     {
724         if (m_ObjectSize == 0) {
725             return NULL;
726         }
727         else {
728             return GET_CONTEXT_HEADER();
729         }
730     }
731 
732     __inline
733     PFX_DRIVER_GLOBALS
GetDriverGlobals(VOID)734     GetDriverGlobals(
735         VOID
736         )
737     {
738         return m_Globals;
739     }
740 
741     WDFTYPE
GetType(VOID)742     GetType(
743         VOID
744         )
745     {
746         return m_Type;
747     }
748 
749     USHORT
GetObjectSize(VOID)750     GetObjectSize(
751         VOID
752         )
753     {
754         return m_ObjectSize;
755     }
756 
757     LONG
GetRefCnt(VOID)758     GetRefCnt(
759         VOID
760         )
761     {
762         return m_Refcnt;
763     }
764 
765     FxTagTracker*
GetTagTracker(VOID)766     GetTagTracker(
767         VOID
768         )
769     {
770         if (IsDebug()) {
771             return CONTAINING_RECORD(this,
772                                      FxObjectDebugExtension,
773                                      AllocationStart)->TagTracker;
774         }
775         else {
776             return NULL;
777         }
778     }
779 
780     CfxDevice*
GetDevice(VOID)781     GetDevice(
782         VOID
783         )
784     {
785         return m_Device;
786     }
787 
788     CfxDeviceBase*
GetDeviceBase(VOID)789     GetDeviceBase(
790         VOID
791         )
792     {
793         return m_DeviceBase;
794     }
795 
796     VOID
SetDeviceBase(__in CfxDeviceBase * DeviceBase)797     SetDeviceBase(
798         __in CfxDeviceBase* DeviceBase
799         )
800     {
801         m_DeviceBase = DeviceBase;
802     }
803 
804     static
805     PVOID
_GetDebugBase(__in FxObject * Object)806     _GetDebugBase(
807         __in FxObject* Object
808         )
809     {
810         return CONTAINING_RECORD(Object, FxObjectDebugExtension, AllocationStart);
811     }
812 
813     __inline
814     VOID
CallCleanup(VOID)815     CallCleanup(
816         VOID
817         )
818     {
819         if (m_ObjectFlags & FXOBJECT_FLAGS_HAS_CLEANUP) {
820             CallCleanupCallbacks();
821         }
822     }
823 
824     ULONG
825     __inline
AddRef(__in_opt PVOID Tag=NULL,__in LONG Line=0,__in_opt PSTR File=NULL)826     AddRef(
827         __in_opt   PVOID Tag = NULL,
828         __in       LONG Line = 0,
829         __in_opt   PSTR File = NULL
830         )
831     {
832         FxTagTracker* pTagTracker;
833         ULONG c;
834 
835         c = InterlockedIncrement(&m_Refcnt);
836 
837         //
838         // Catch the transition from 0 to 1.  Since the REF_OBJ starts off at 1,
839         // we should never have to increment to get to this value.
840         //
841         ASSERT(c > 1);
842 
843         pTagTracker = GetTagTracker();
844         if (pTagTracker != NULL) {
845             pTagTracker->UpdateTagHistory(Tag, Line, File, TagAddRef, c);
846         }
847 
848         return c;
849     }
850 
851     virtual
852     ULONG
Release(__in_opt PVOID Tag=NULL,__in LONG Line=0,__in_opt PSTR File=NULL)853     Release(
854         __in_opt    PVOID Tag = NULL,
855         __in        LONG Line = 0,
856         __in_opt    PSTR File = NULL
857         )
858     {
859         FxTagTracker* pTagTracker;
860         ULONG c;
861 
862         pTagTracker = GetTagTracker();
863         if (pTagTracker != NULL) {
864             pTagTracker->UpdateTagHistory(Tag, Line, File, TagRelease, m_Refcnt - 1);
865         }
866 
867         c = InterlockedDecrement(&m_Refcnt);
868 
869         if (c == 0) {
870             FinalRelease();
871         }
872 
873         return c;
874     }
875 
876     virtual
877     ULONG
AddRefOverride(__in WDFOBJECT_OFFSET Offset,__in_opt PVOID Tag=NULL,__in LONG Line=0,__in_opt PSTR File=NULL)878     AddRefOverride(
879         __in        WDFOBJECT_OFFSET Offset,
880         __in_opt    PVOID Tag = NULL,
881         __in        LONG Line = 0,
882         __in_opt    PSTR File = NULL
883         )
884     {
885         UNREFERENCED_PARAMETER(Offset);
886 
887         return AddRef(Tag, Line, File);
888     }
889 
890     virtual
891     ULONG
ReleaseOverride(__in WDFOBJECT_OFFSET Offset,__in_opt PVOID Tag=NULL,__in LONG Line=0,__in_opt PSTR File=NULL)892     ReleaseOverride(
893         __in        WDFOBJECT_OFFSET Offset,
894         __in_opt    PVOID Tag = NULL,
895         __in        LONG Line = 0,
896         __in_opt    PSTR File = NULL
897         )
898     {
899         UNREFERENCED_PARAMETER(Offset);
900 
901         return Release(Tag, Line, File);
902     }
903 
904     _Must_inspect_result_
905     virtual
906     NTSTATUS
907     QueryInterface(
908         __in FxQueryInterfaceParams* Params
909         );
910 
911     VOID
MarkTraceState(VOID)912     MarkTraceState(
913         VOID
914         )
915     {
916         m_ObjectFlags |= FXOBJECT_FLAGS_TRACE_STATE;
917     }
918 
919     BOOLEAN
920     __inline
IsTraceState(VOID)921     IsTraceState(
922         VOID
923         )
924     {
925         return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_TRACE_STATE);
926     }
927 
928     VOID
929     __inline
TraceDroppedEvent(__in FxObjectDroppedEvent Event)930     TraceDroppedEvent(
931         __in FxObjectDroppedEvent Event
932         )
933     {
934         if (IsTraceState()) {
935             DoTraceLevelMessage(
936                 m_Globals, TRACE_LEVEL_INFORMATION, TRACINGOBJECT,
937                 "Object %p, WDFOBJECT %p, state %!FxObjectState! dropping event"
938                 " %!FxObjectDroppedEvent!",
939                 this, GetObjectHandleUnchecked(), m_ObjectState, Event);
940         }
941     }
942 
943     VOID
MarkPassiveDispose(__in FxObjectLockState State=ObjectLock)944     MarkPassiveDispose(
945         __in FxObjectLockState State = ObjectLock
946         )
947     {
948         //
949         // Object which can have > passive level locks, but needs to be Dispose()'d
950         // at passive level.  This means that the object's client cleanup
951         // routines will also be guaranteed to run at passive.
952         //
953         if (State == ObjectLock) {
954             KIRQL   oldIrql;
955 
956             m_SpinLock.Acquire(&oldIrql);
957             m_ObjectFlags |= FXOBJECT_FLAGS_PASSIVE_DISPOSE;
958             m_SpinLock.Release(oldIrql);
959         }
960         else {
961             m_ObjectFlags |= FXOBJECT_FLAGS_PASSIVE_DISPOSE;
962         }
963     }
964 
965     //
966     // Sets that the object is a passive level only object who
967     // accesses page-able pool, routines, or has a driver
968     // specified passive constraint on callbacks such as
969     // Cleanup and Destroy.
970     //
971     VOID
MarkPassiveCallbacks(__in FxObjectLockState State=ObjectLock)972     MarkPassiveCallbacks(
973         __in FxObjectLockState State = ObjectLock
974         )
975     {
976         if (State == ObjectLock) {
977             KIRQL   oldIrql;
978 
979             m_SpinLock.Acquire(&oldIrql);
980             m_ObjectFlags |= FXOBJECT_FLAGS_PASSIVE_CALLBACKS | FXOBJECT_FLAGS_PASSIVE_DISPOSE;
981             m_SpinLock.Release(oldIrql);
982         }
983         else {
984             m_ObjectFlags |= FXOBJECT_FLAGS_PASSIVE_CALLBACKS | FXOBJECT_FLAGS_PASSIVE_DISPOSE;
985         }
986     }
987 
988     VOID
MarkForceDisposeThread(__in FxObjectLockState State=ObjectLock)989     MarkForceDisposeThread(
990         __in FxObjectLockState State = ObjectLock
991         )
992     {
993         //
994         // Object must always be disposed in a separate thread
995         // to allow waiting for some outstanding async
996         // operation to complete.
997         //
998         if (State == ObjectLock) {
999             KIRQL   oldIrql;
1000 
1001             m_SpinLock.Acquire(&oldIrql);
1002             m_ObjectFlags |= FXOBJECT_FLAGS_FORCE_DISPOSE_THREAD;
1003             m_SpinLock.Release(oldIrql);
1004         }
1005         else {
1006             m_ObjectFlags |= FXOBJECT_FLAGS_FORCE_DISPOSE_THREAD;
1007         }
1008     }
1009 
1010     BOOLEAN
IsPassiveCallbacks(__in BOOLEAN AcquireLock=TRUE)1011     IsPassiveCallbacks(
1012         __in BOOLEAN AcquireLock = TRUE
1013         )
1014     {
1015         BOOLEAN result;
1016         KIRQL   oldIrql = PASSIVE_LEVEL;
1017 
1018         if (AcquireLock) {
1019             m_SpinLock.Acquire(&oldIrql);
1020         }
1021 
1022         result = IsPassiveCallbacksLocked();
1023 
1024         if (AcquireLock) {
1025             m_SpinLock.Release(oldIrql);
1026         }
1027 
1028         return result;
1029     }
1030 
1031     BOOLEAN
IsPassiveDispose(__in BOOLEAN AcquireLock=TRUE)1032     IsPassiveDispose(
1033         __in BOOLEAN AcquireLock = TRUE
1034         )
1035     {
1036         BOOLEAN result;
1037         KIRQL   oldIrql = PASSIVE_LEVEL;
1038 
1039         if (AcquireLock) {
1040             m_SpinLock.Acquire(&oldIrql);
1041         }
1042 
1043         result = IsPassiveDisposeLocked();
1044 
1045         if (AcquireLock) {
1046             m_SpinLock.Release(oldIrql);
1047         }
1048 
1049         return result;
1050     }
1051 
1052     BOOLEAN
IsForceDisposeThread(__in BOOLEAN AcquireLock=TRUE)1053     IsForceDisposeThread(
1054         __in BOOLEAN AcquireLock = TRUE
1055         )
1056     {
1057         BOOLEAN result;
1058         KIRQL   oldIrql = PASSIVE_LEVEL;
1059 
1060         if (AcquireLock) {
1061             m_SpinLock.Acquire(&oldIrql);
1062         }
1063 
1064         result = IsForceDisposeThreadLocked();
1065 
1066         if (AcquireLock) {
1067             m_SpinLock.Release(oldIrql);
1068         }
1069 
1070         return result;
1071     }
1072 
1073     VOID
MarkCommitted(VOID)1074     MarkCommitted(
1075         VOID
1076         )
1077     {
1078         //
1079         // Since no client code is accessing the handle yet, we don't need to
1080         // acquire the object state lock to set the flag since this will be
1081         // the only thread touching m_ObjectFlags.
1082         //
1083         m_ObjectFlags |= FXOBJECT_FLAGS_COMMITTED;
1084     }
1085 
1086     BOOLEAN
IsCommitted(VOID)1087     IsCommitted(
1088         VOID
1089         )
1090     {
1091         //
1092         // No need to acquire the lock because it is assumed the caller is
1093         // calling on an object whose ref count has gone to zero so there are
1094         // no other callers to contend with who might set this flag or modify
1095         // m_ObjectFlags.
1096         //
1097         return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_COMMITTED);
1098     }
1099 
1100     VOID
MarkDisposeOverride(__in FxObjectLockState State=ObjectLock)1101     MarkDisposeOverride(
1102         __in FxObjectLockState State = ObjectLock
1103         )
1104     {
1105         if (State == ObjectLock) {
1106             KIRQL irql;
1107 
1108             m_SpinLock.Acquire(&irql);
1109             m_ObjectFlags |= FXOBJECT_FLAGS_DISPOSE_OVERRIDE;
1110             m_SpinLock.Release(irql);
1111         }
1112         else {
1113             m_ObjectFlags |= FXOBJECT_FLAGS_DISPOSE_OVERRIDE;
1114         }
1115     }
1116 
1117     VOID
MarkNoDeleteDDI(__in FxObjectLockState State=ObjectLock)1118     MarkNoDeleteDDI(
1119         __in FxObjectLockState State = ObjectLock
1120         )
1121     {
1122         if (State == ObjectLock) {
1123             KIRQL irql;
1124 
1125             m_SpinLock.Acquire(&irql);
1126             m_ObjectFlags |= FXOBJECT_FLAGS_NODELETEDDI;
1127             m_SpinLock.Release(irql);
1128         }
1129         else {
1130             m_ObjectFlags |= FXOBJECT_FLAGS_NODELETEDDI;
1131         }
1132     }
1133 
1134     BOOLEAN
IsNoDeleteDDI(VOID)1135     IsNoDeleteDDI(
1136         VOID
1137         )
1138     {
1139         // No need for lock since its only set in constructor/init
1140         return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_NODELETEDDI);
1141     }
1142 
1143     //
1144     // Commit the WDF object before returning handle to the caller.
1145     //
1146     _Must_inspect_result_
1147     NTSTATUS
1148     Commit(
1149         __in_opt    PWDF_OBJECT_ATTRIBUTES Attributes,
1150         __out_opt   WDFOBJECT*             ObjectHandle,
1151         __in_opt    FxObject* Parent = NULL,
1152         __in        BOOLEAN  AssignDriverAsDefaultParent = TRUE
1153         );
1154 
1155     VOID
1156     DeleteFromFailedCreate(
1157         VOID
1158         );
1159 
1160     VOID
1161     ClearEvtCallbacks(
1162         VOID
1163         );
1164 
1165     BOOLEAN
1166     EarlyDispose(
1167         VOID
1168         );
1169 
1170     //
1171     // Request that an object be deleted.
1172     //
1173     // This can be the result of a WDF API or a WDM event.
1174     //
1175     virtual
1176     VOID
1177     DeleteObject(
1178         VOID
1179         );
1180 
1181     //
1182     // Invoked by FxObject *once* when the object is either
1183     // being deleted, or rundown due to its parent object
1184     // being deleted.
1185     //
1186     // An object can override this to perform per object
1187     // cleanup if required.
1188     //
1189     // TRUE means that the cleanup callbacks should be called when the function
1190     // returns.  FALSE indicates that the caller will take care of calling the
1191     // cleanup callbacks on behalf of the state machine.
1192     //
1193     virtual
1194     BOOLEAN
1195     Dispose(
1196         VOID
1197         );
1198 
1199     //
1200     // Request to make ParentObject the parent for this object.
1201     //
1202     _Must_inspect_result_
1203     NTSTATUS
1204     AssignParentObject(
1205         __in FxObject* ParentObject
1206         );
1207 
1208     _Must_inspect_result_
1209     NTSTATUS
1210     AddContext(
1211         __in FxContextHeader *Header,
1212         __in PVOID* Context,
1213         __in PWDF_OBJECT_ATTRIBUTES Attributes
1214         );
1215 
1216     //
1217     // Request that this Object be removed from the child association
1218     // list for its parent
1219     //
1220     _Must_inspect_result_
1221     NTSTATUS
1222     RemoveParentAssignment(
1223         VOID
1224         );
1225 
1226     //
1227     // Adds a reference to the parent object pointer if != NULL
1228     //
1229     _Must_inspect_result_
1230     FxObject*
1231     GetParentObjectReferenced(
1232         __in PVOID Tag
1233         );
1234 
1235     //
1236     // This is public to allow debug code to assert that
1237     // an object has been properly disposed either through
1238     // calling DeleteObject, or being disposed by its parent.
1239     //
1240     BOOLEAN
IsDisposed(VOID)1241     IsDisposed(
1242         VOID
1243         )
1244     {
1245         KIRQL   oldIrql;
1246         BOOLEAN disposed;
1247 
1248         if (m_Globals->FxVerifierOn &&
1249             m_Globals->FxVerifierHandle) {
1250             m_SpinLock.Acquire(&oldIrql);
1251 
1252             if (m_ObjectState == FxObjectStateCreated) {
1253                 disposed = FALSE;
1254             }
1255             else {
1256                 //
1257                 // Parent is disposing us, or we are being disposed
1258                 //
1259                 disposed = TRUE;
1260             }
1261 
1262             m_SpinLock.Release(oldIrql);
1263 
1264             return disposed;
1265         }
1266         else {
1267             return TRUE;
1268         }
1269     }
1270 
1271     static
1272     PFX_POOL_HEADER
_CleanupPointer(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxObject * Object)1273     _CleanupPointer(
1274         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
1275         __in FxObject* Object
1276         )
1277     {
1278         PFX_POOL_HEADER pHeader;
1279         PVOID pObjectBase;
1280 
1281         pObjectBase = _GetBase(Object);
1282 
1283         pHeader = CONTAINING_RECORD(pObjectBase, FX_POOL_HEADER, AllocationStart);
1284 
1285         //
1286         // If PoolTracker is on then do....
1287         //
1288         if (FxDriverGlobals->IsPoolTrackingOn()) {
1289             //
1290             // Decommission this NonPaged Allocation tracker
1291             //
1292             FxPoolRemoveNonPagedAllocateTracker((PFX_POOL_TRACKER) pHeader->Base);
1293         }
1294 
1295         return pHeader;
1296     }
1297 
1298     _Must_inspect_result_
1299     static
1300     NTSTATUS
1301     _GetEffectiveLock(
1302         __in        FxObject* Object,
1303         __in_opt    IFxHasCallbacks* Callbacks,
1304         __in        BOOLEAN AutomaticLocking,
1305         __in        BOOLEAN PassiveCallbacks,
1306         __out       FxCallbackLock** CallbackLock,
1307         __out_opt   FxObject** CallbackLockObject
1308         );
1309 
1310     //
1311     // Implementation for WdfObjectQuery
1312     //
1313     _Must_inspect_result_
1314     static
1315     NTSTATUS
1316     _ObjectQuery(
1317         _In_    FxObject* Object,
1318         _In_    CONST GUID* Guid,
1319         _In_    ULONG QueryBufferLength,
1320         _Out_writes_bytes_(QueryBufferLength)
1321                 PVOID QueryBuffer
1322         );
1323 
1324 protected:
1325     VOID
1326     DeleteEarlyDisposedObject(
1327         VOID
1328         );
1329 
1330 private:
1331     VOID
1332     FinalRelease(
1333         VOID
1334         );
1335 
1336     //
1337     // This is used by verifier to ensure that DeleteObject
1338     // is only called once.
1339     //
1340     // It must be accessed under the m_SpinLock.
1341     //
1342     // It returns TRUE if this is the first call.
1343     //
1344     BOOLEAN
MarkDeleteCalledLocked(VOID)1345     MarkDeleteCalledLocked(
1346         VOID
1347         )
1348     {
1349         BOOLEAN retval;
1350 
1351         retval = !(m_ObjectFlags & FXOBJECT_FLAGS_DELETECALLED);
1352 
1353         m_ObjectFlags |= FXOBJECT_FLAGS_DELETECALLED;
1354 
1355         return retval;
1356     }
1357 
1358     BOOLEAN
IsPassiveCallbacksLocked(VOID)1359     IsPassiveCallbacksLocked(
1360         VOID
1361         )
1362     {
1363         return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_PASSIVE_CALLBACKS);
1364     }
1365 
1366     BOOLEAN
IsPassiveDisposeLocked(VOID)1367     IsPassiveDisposeLocked(
1368         VOID
1369         )
1370     {
1371         return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_PASSIVE_DISPOSE);
1372     }
1373 
1374     BOOLEAN
IsForceDisposeThreadLocked(VOID)1375     IsForceDisposeThreadLocked(
1376         VOID
1377         )
1378     {
1379         return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_FORCE_DISPOSE_THREAD);
1380     }
1381 
1382     BOOLEAN
ShouldDeferDisposeLocked(__out_opt PKIRQL PreviousIrql=NULL)1383     ShouldDeferDisposeLocked(
1384         __out_opt PKIRQL PreviousIrql = NULL
1385         )
1386     {
1387         if (IsForceDisposeThreadLocked()) {
1388             return TRUE;
1389         }
1390         else if (IsPassiveDisposeLocked()) {
1391             //
1392             // Only call KeGetCurrentIrql() if absolutely necessary.  It is an
1393             // expensive call and we want to minimize the cycles required when
1394             // destroying an object  that requires passive rundown
1395             //
1396 
1397             //
1398             // Cases:
1399             // 1)  Caller does not know the current IRQL, so we must query for it
1400             //
1401             // 2)  Caller knew prev IRQL, so we used the caller's value
1402             //
1403             if (PreviousIrql == NULL) {                  // case 1
1404                 if (Mx::MxGetCurrentIrql() != PASSIVE_LEVEL) {
1405                     return TRUE;
1406                 }
1407             }
1408             else if (*PreviousIrql != PASSIVE_LEVEL) {   // case 2
1409                 return TRUE;
1410             }
1411         }
1412 
1413         return FALSE;
1414     }
1415 
1416     VOID
1417     ParentDeleteEvent(
1418         VOID
1419         );
1420 
1421     BOOLEAN
1422     PerformEarlyDispose(
1423         VOID
1424         );
1425 
1426     _Releases_lock_(this->m_SpinLock.m_Lock)
1427     __drv_requiresIRQL(DISPATCH_LEVEL)
1428     BOOLEAN
1429     PerformEarlyDisposeWorkerAndUnlock(
1430         __in __drv_restoresIRQL KIRQL OldIrql,
1431         __in                    BOOLEAN CanDefer
1432         );
1433 
1434     _Releases_lock_(this->m_SpinLock.m_Lock)
1435     __drv_requiresIRQL(DISPATCH_LEVEL)
1436     BOOLEAN
1437     PerformDisposingDisposeChildrenLocked(
1438         __in __drv_restoresIRQL KIRQL OldIrql,
1439         __in                    BOOLEAN CanDefer
1440         );
1441 
1442     _Releases_lock_(this->m_SpinLock.m_Lock)
1443     __drv_requiresIRQL(DISPATCH_LEVEL)
1444     BOOLEAN
1445     DeleteWorkerAndUnlock(
1446         __in __drv_restoresIRQL KIRQL OldIrql,
1447         __in                    BOOLEAN CanDefer
1448         );
1449 
1450     VOID
1451     QueueDeferredDisposeLocked(
1452         __in FxObjectState NewDeferedState
1453         );
1454 
1455     VOID
1456     DeferredDisposeWorkItem(
1457         VOID
1458         );
1459 
1460     _Releases_lock_(this->m_SpinLock.m_Lock)
1461     __drv_requiresIRQL(DISPATCH_LEVEL)
1462     BOOLEAN
1463     DisposeChildrenWorker(
1464         __in                    FxObjectState NewDeferedState,
1465         __in __drv_restoresIRQL KIRQL OldIrql,
1466         __in                    BOOLEAN CanDefer
1467         );
1468 
1469     _When_(Unlock, _Releases_lock_(this->m_SpinLock.m_Lock))
1470     __drv_when(Unlock, __drv_requiresIRQL(DISPATCH_LEVEL))
1471     VOID
1472     DeletedAndDisposedWorkerLocked(
1473         __in __drv_when(Unlock, __drv_restoresIRQL) KIRQL OldIrql,
1474         __in                                        BOOLEAN Unlock = TRUE
1475         );
1476 
1477     _Must_inspect_result_
1478     NTSTATUS
1479     RemoveParentAssociation(
1480         VOID
1481         );
1482 
1483     _Must_inspect_result_
1484     NTSTATUS
1485     AddChildObjectInternal(
1486         __in FxObject* ChildObject
1487         );
1488 
1489    _Must_inspect_result_
1490    NTSTATUS
1491     RemoveChildObjectInternal(
1492         __in FxObject* ChildObject
1493         );
1494 
1495     VOID
1496     ProcessDestroy(
1497         VOID
1498         );
1499 
1500     VOID
1501     CallCleanupCallbacks(
1502         VOID
1503         );
1504 };
1505 
1506 #endif // _FXOBJECT_H_
1507