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