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