1 /*++ 2 3 Copyright (c) Microsoft. All rights reserved. 4 5 Module Name: 6 7 EventQueueKm.cpp 8 9 Abstract: 10 11 This module implements kernel mode specific functionality of event queue 12 13 This functionality needed to be separated out since the KM portion takes 14 a reference on driver object because KM MxWorkItem::_Free does not wait for 15 callback to return (i.e. rundown synchronously). 16 17 MxWorkItem::_Free in UM currently waits for callback to return (i.e. runs 18 down synchronously) hence does not need a reference on driver/devstack 19 object (see comments on top of MxWorkItemUm.h file). 20 21 In future if UM work-item is made similar to km workitem, UMDF may need to 22 ensure that modules stay loaded, though the mechanism to ensure that would 23 likely be different from a reference on the driver. It would likely be a 24 reference on the devicestack object. 25 26 Environment: 27 28 Kernel mode only 29 30 Revision History: 31 32 33 34 35 --*/ 36 37 #include "pnppriv.hpp" 38 39 VOID 40 FxWorkItemEventQueue::QueueWorkItem( 41 VOID 42 ) 43 { 44 // 45 // The work item will take a reference on KMDF itself. This will keep KMDF's 46 // image around (but not necessarily prevent DriverUnload from being called) 47 // so that the code after we set the done event will be in memory and not 48 // unloaded. We must do this because there is no explicit reference between 49 // the client driver and KMDF, so when the io manager calls the client's 50 // DriverUnload, it has no way of managing KMDF's ref count to stay in memory 51 // when the loader unloads KMDF explicitly in response to DriverUnload. 52 // 53 // We manually take a reference on the client so that we provide the same 54 // functionality that IO workitems do. The client driver's image will have 55 // a reference on it after it has returned. 56 // 57 58 59 60 61 Mx::MxReferenceObject(m_PkgPnp->GetDriverGlobals()->Driver->GetDriverObject()); 62 63 // 64 // Prevent FxDriverGlobals from being deleted until the workitem finishes 65 // its work. In case of a bus driver with a PDO in removed 66 // state, if the bus is removed, the removal of PDO may happen in a workitem 67 // and may result in unload routine being called before the PDO package is 68 // deallocated. Since FxPool deallocation code touches FxDriverGlobals 69 // (a pointer of which is located in the header of each FxPool allocated 70 // object), taking this ref prevents the globals from going away until a 71 // corresponding deref at the end of workitem. 72 // 73 m_PkgPnp->GetDriverGlobals()->ADDREF((PVOID)_WorkItemCallback); 74 75 m_WorkItem.Enqueue( 76 (PMX_WORKITEM_ROUTINE) _WorkItemCallback, 77 (FxEventQueue*) this); 78 } 79 80 VOID 81 FxWorkItemEventQueue::_WorkItemCallback( 82 __in MdDeviceObject DeviceObject, 83 __in PVOID Context 84 ) 85 /*++ 86 87 Routine Description: 88 This is the work item that attempts to run the machine on a thread 89 separate from the one the caller was using. It implements step 9 above. 90 91 --*/ 92 { 93 FxWorkItemEventQueue* This = (FxWorkItemEventQueue*) Context; 94 PFX_DRIVER_GLOBALS pFxDriverGlobals; 95 96 UNREFERENCED_PARAMETER(DeviceObject); 97 98 MdDriverObject pDriverObject; 99 100 pFxDriverGlobals = This->m_PkgPnp->GetDriverGlobals(); 101 102 // 103 // Capture the driver object before we call the EventQueueWoker() because 104 // the time it returns, This could be freed. 105 106 107 108 pDriverObject = pFxDriverGlobals->Driver->GetDriverObject(); 109 110 This->EventQueueWorker(); 111 112 // 113 // Release the ref on FxDriverGlobals taken before queuing this workitem. 114 // 115 pFxDriverGlobals->RELEASE((PVOID)_WorkItemCallback); 116 117 Mx::MxDereferenceObject(pDriverObject); 118 } 119 120