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
FxObject(__in WDFTYPE Type,__in USHORT Size,__in PFX_DRIVER_GLOBALS FxDriverGlobals)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
FxObject(__in WDFTYPE Type,__in USHORT Size,__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxObjectType ObjectType)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
~FxObject()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
FX_VF_METHOD(FxObject,VerifyConstruct)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
FinalRelease(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
QueryInterface(__in FxQueryInterfaceParams * Params)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
AllocateTagTracker(__in WDFTYPE Type)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
operator delete(__in PVOID Memory)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
CallCleanupCallbacks(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
ClearEvtCallbacks(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
DeleteFromFailedCreate(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
AssignParentObject(__in FxObject * ParentObject)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
AddContext(__in FxContextHeader * Header,__in PVOID * Context,__in PWDF_OBJECT_ATTRIBUTES Attributes)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
AddChildObjectInternal(__in FxObject * ChildObject)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
RemoveChildObjectInternal(__in FxObject * ChildObject)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*
GetParentObjectReferenced(__in PVOID Tag)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
Commit(__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,__out_opt WDFOBJECT * ObjectHandle,__in_opt FxObject * Parent,__in BOOLEAN AssignDriverAsDefaultParent)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
_GetEffectiveLock(__in FxObject * Object,__in_opt IFxHasCallbacks * Callbacks,__in BOOLEAN AutomaticLocking,__in BOOLEAN PassiveCallbacks,__out FxCallbackLock ** CallbackLock,__out_opt FxObject ** CallbackLockObject)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