ReactOS  0.4.15-dev-2703-g05fb0f1
fxdpc.cpp
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7  FxDpc.hpp
8 
9 Abstract:
10 
11  This module implements a frameworks managed DPC that
12  can synchrononize with driver frameworks object locks.
13 
14 Author:
15 
16 
17 
18 Environment:
19 
20  Kernel mode only
21 
22 Revision History:
23 
24 
25 --*/
26 
27 #include "fxcorepch.hpp"
28 
29 #include "fxdpc.hpp"
30 
31 // Tracing support
32 extern "C" {
33 // #include "FxDpc.tmh"
34 }
35 
36 //
37 // Public constructors
38 //
39 
41  __in PFX_DRIVER_GLOBALS FxDriverGlobals
42  ) :
43  FxNonPagedObject(FX_TYPE_DPC, sizeof(FxDpc), FxDriverGlobals)
44 {
45  m_Object = NULL;
48  m_Callback = NULL;
50 
51  //
52  // Mark the object has having passive level dispose so that KeFlushQueuedDpcs
53  // can be called in Dispose().
54  //
56 
58 }
59 
60 
62 {
63  //
64  // If this hits, its because someone destroyed the DPC by
65  // removing too many references by mistake without calling WdfObjectDelete
66  //
67  if (m_Object != NULL) {
70  "Destroy WDFDPC %p destroyed without calling WdfObjectDelete, or by"
71  " Framework processing DeviceRemove. Possible reference count "
72  "problem?", GetObjectHandleUnchecked());
74  }
75 }
76 
80  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
83  __in FxObject* ParentObject,
84  __out WDFDPC* Dpc
85  )
86 /*++
87 
88 Routine Description:
89 
90  Create an FxDpc factory method
91 
92 Arguments:
93 
94  All arguments have been valided by the FxDpcApi stub.
95 
96 Returns:
97 
98  NTSTATUS
99 
100 --*/
101 {
102  FxDpc* pFxDpc;
104 
105  pFxDpc = new(FxDriverGlobals, Attributes) FxDpc(FxDriverGlobals);
106 
107  if (pFxDpc == NULL) {
109  }
110 
112  Attributes,
113  Config,
114  ParentObject,
115  Dpc
116  );
117 
118  if (!NT_SUCCESS(status)) {
120  }
121 
122  return status;
123 }
124 
126 NTSTATUS
130  __in FxObject* ParentObject,
131  __out WDFDPC* Dpc
132  )
133 {
135  IFxHasCallbacks* pCallbacks;
137  KDPC* pDpc;
138 
140  pDpc = NULL;
141  pCallbacks = NULL;
142 
143  pDpc = &m_Dpc;
144 
145  //
146  // Set user's callback function
147  //
148  m_Callback = Config->EvtDpcFunc;
149 
150  //
151  // Initialize the DPC to point to our thunk
152  //
154  pDpc, // Dpc
155  FxDpcThunk, // DeferredRoutine
156  this // DeferredContext
157  );
158 
159  //
160  // As long as we are associated, the parent object holds a reference
161  // count on the DPC.
162  //
163  // We keep an extra reference count since on Dispose, we wait until
164  // all outstanding DPC's complete before allowing finalization.
165  //
166  // This reference must be taken early before we return any failure,
167  // since Dispose() expects this extra reference, and Dispose() will
168  // be called even if we return a failure status right now.
169  //
170  ADDREF(this);
171 
172  //
173  // DPC's can be parented by, and optionally serialize with an FxDevice or
174  // an FxQueue.
175  //
176  m_DeviceBase = FxDeviceBase::_SearchForDevice(ParentObject, &pCallbacks);
177 
178  if (m_DeviceBase == NULL) {
180  }
181 
182  //
183  // Configure Serialization for the DPC and callbacks on the supplied object
184  //
186  ParentObject,
187  pCallbacks,
188  Config->AutomaticSerialization,
189  FALSE,
192  );
193 
194  if (!NT_SUCCESS(status)) {
196 
197 
198 
199 
200 
201 
204  "ParentObject %p can not automatically synchronize callbacks "
205  "with a DPC since it is configured for passive level callback "
206  "constraints. Set AutomaticSerialization to FALSE. %!STATUS!",
207  Attributes->ParentObject, status);
208  }
209 
210  return status;
211  }
212 
213  //
214  // We automatically synchronize with and reference count
215  // the lifetime of the framework object to prevent any DPC races
216  // that can access the object while it is going away.
217  //
218 
219  //
220  // The caller supplied object is the object the caller wants the
221  // DPC to be associated with, and the framework must ensure this
222  // object remains live until the DPC object is destroyed. Otherwise,
223  // it could access either object context memory, or an object API
224  // on a freed object.
225  //
226  // Due to the locking model of the framework, the lock may actually
227  // be owned by a higher level object as well. This is the lockObject
228  // returned. As long was we are a child of this object, the lockObject
229  // does not need to be dereferenced since it will notify us of Cleanup
230  // before it goes away.
231  //
232 
233  //
234  // Associate the FxDpc with the object. When this object gets deleted or
235  // disposed, it will notify our Dispose function as well.
236  //
237 
238  //
239  // Add a reference to the parent object we are associated with.
240  // We will be notified of Cleanup to release this reference.
241  //
242  ParentObject->ADDREF(this);
243 
244  // Save the ptr to the object the DPC is associated with
245  m_Object = ParentObject;
246 
247  //
248  // Attributes->ParentObject is the same as ParentObject. Since we already
249  // converted it to an object, use that.
250  //
251  status = Commit(Attributes, (WDFOBJECT*)Dpc, ParentObject);
252 
253  if (!NT_SUCCESS(status)) {
254  return status;
255  }
256 
257  return status;
258 }
259 
260 BOOLEAN
263  )
264 {
265  BOOLEAN result;
266 
268 
269  //
270  // If result == FALSE, then the DPC could already be running.
271  //
272  // If the caller supplies Wait == TRUE, they want to wait and
273  // ensure on return the DPC has finished running.
274  //
275  // The trick here is to implement this without adding execessive
276  // overhead to the "normal" path, such as tracking reference counts,
277  // locking, signaling events to waiting threads, etc.
278  //
279  // So we take the expensive approach for the Cancel call in the
280  // case the caller wants to wait, and misses the DPC window. In
281  // this case we will just do the system wide FlushQueuedDpc's to
282  // ensure the DPC has finished running before return.
283  //
284  if( Wait && !result ) {
285 
287 
289  }
290 
291  return result;
292 }
293 
294 VOID
296  __in PKDPC Dpc,
299  )
300 {
304 
306 
307  if (m_Callback != NULL) {
308 
310 
311  if (m_CallbackLock != NULL) {
312  KIRQL irql = 0;
313 
315  m_Callback((WDFDPC)(this->GetObjectHandle()));
316  m_CallbackLock->Unlock(irql);
317  }
318  else {
319  m_Callback((WDFDPC)(this->GetObjectHandle()));
320  }
321  }
322 }
323 
324 VOID
326  __in PKDPC Dpc,
330  )
331 
332 /*++
333 
334 Routine Description:
335 
336  This is the C routine called by the kernels DPC handler
337 
338 Arguments:
339 
340  Dpc - our DPC object associated with our Timer
341  DeferredContext - Context for the DPC that we setup in DriverEntry
342  SystemArgument1 -
343  SystemArgument2 -
344 
345 Return Value:
346 
347  Nothing.
348 
349 --*/
350 
351 {
352  FxDpc* pDpc = (FxDpc*)DeferredContext;
353 
354  pDpc->DpcHandler(
355  Dpc,
358  );
359 
360  return;
361 }
362 
363 //
364 // Called when DeleteObject is called, or when the parent
365 // is being deleted or Disposed.
366 //
367 // Also invoked directly by the cleanup list at our request after
368 // a Dispose occurs and must be deferred if not at passive level.
369 //
370 BOOLEAN
372 {
373  // MarkPassiveDispose() in Initialize ensures this
375 
377 
378  FlushAndRundown();
379 
380  return TRUE;
381 }
382 
383 //
384 // Called by the system work item to finish the rundown
385 //
386 VOID
388 {
389  FxObject* pObject;
390 
391  //
392  // If we have the KeFlushQueuedDpcs function call it
393  // to ensure the DPC routine is no longer running before
394  // we release the final reference and memory to the framework objects
395  //
397 
398  //
399  // Release our reference count to the associated parent object if present
400  //
401  if (m_Object != NULL) {
402  pObject = m_Object;
403  m_Object = NULL;
404 
405  pObject->RELEASE(this);
406  }
407 
408  //
409  // Perform our final release to ourselves, destroying the FxDpc
410  //
411  RELEASE(this);
412 }
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
virtual ~FxDpc(VOID)
Definition: fxdpc.cpp:61
KDPC m_Dpc
Definition: fxdpc.hpp:67
FxObject * pObject
#define _Must_inspect_result_
Definition: no_sal2.h:62
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:107
_Must_inspect_result_ NTSTATUS Commit(__in_opt PWDF_OBJECT_ATTRIBUTES Attributes, __out_opt WDFOBJECT *ObjectHandle, __in_opt FxObject *Parent=NULL, __in BOOLEAN AssignDriverAsDefaultParent=TRUE)
Definition: fxobject.cpp:904
GLuint64EXT * result
Definition: glext.h:11304
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
static _Must_inspect_result_ NTSTATUS _GetEffectiveLock(__in FxObject *Object, __in_opt IFxHasCallbacks *Callbacks, __in BOOLEAN AutomaticLocking, __in BOOLEAN PassiveCallbacks, __out FxCallbackLock **CallbackLock, __out_opt FxObject **CallbackLockObject)
Definition: fxobject.cpp:1044
Definition: fxdpc.hpp:63
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:167
KDPC * GetDpcPtr(VOID)
Definition: fxdpc.hpp:117
LONG NTSTATUS
Definition: precomp.h:26
VOID MarkPassiveDispose(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:944
BOOLEAN NTAPI KeRemoveQueueDpc(IN PKDPC Dpc)
Definition: dpc.c:877
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
KIRQL irql
Definition: wave.h:1
#define RELEASE(_tag)
Definition: fxobject.hpp:50
FxDpc(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
Definition: fxdpc.cpp:40
static FxDeviceBase * _SearchForDevice(__in FxObject *Object, __out_opt IFxHasCallbacks **Callbacks)
UCHAR KIRQL
Definition: env_spec_w32.h:591
FxObject * m_CallbackLockObject
Definition: fxdpc.hpp:85
#define FALSE
Definition: types.h:117
#define ADDREF(_tag)
Definition: fxobject.hpp:49
virtual void Lock(__out PKIRQL PreviousIrql)=0
VOID MarkDisposeOverride(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:1101
PVOID __inline GetObjectHandle(VOID)
Definition: fxobject.hpp:603
#define STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL
Definition: wdfstatus.h:198
#define __out
Definition: dbghelp.h:62
unsigned char BOOLEAN
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:675
FxObject * m_Object
Definition: fxdpc.hpp:73
#define TRACINGDEVICE
Definition: dbgtrace.h:58
PFX_DRIVER_GLOBALS pFxDriverGlobals
#define ASSERT(a)
Definition: mode.c:44
BOOLEAN Cancel(__in BOOLEAN Wait)
Definition: fxdpc.cpp:261
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
FORCEINLINE VOID FxPerfTraceDpc(_In_ PVOID DriverCallback)
static KDEFERRED_ROUTINE FxDpcThunk
Definition: fxdpc.hpp:190
FxDpc * pFxDpc
Definition: fxdpcapi.cpp:238
static _Must_inspect_result_ NTSTATUS _Create(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PWDF_DPC_CONFIG Config, __in PWDF_OBJECT_ATTRIBUTES Attributes, __in FxObject *ParentObject, __out WDFDPC *Dpc)
Definition: fxdpc.cpp:79
PVOID __inline GetObjectHandleUnchecked(VOID)
Definition: fxobject.hpp:446
virtual BOOLEAN Dispose(VOID)
Definition: fxdpc.cpp:371
Definition: ketypes.h:687
CfxDeviceBase * m_DeviceBase
Definition: fxobject.hpp:328
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
virtual void Unlock(__in KIRQL PreviousIrql)=0
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_CHILD_LIST_CONFIG Config
Definition: wdfchildlist.h:474
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:675
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
_Must_inspect_result_ NTSTATUS Initialize(__in PWDF_OBJECT_ATTRIBUTES Attributes, __in PWDF_DPC_CONFIG Config, __in FxObject *ParentObject, __out WDFDPC *Dpc)
Definition: fxdpc.cpp:127
BOOLEAN m_RunningDown
Definition: fxdpc.hpp:93
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
PFN_WDF_DPC m_Callback
Definition: fxdpc.hpp:90
#define NULL
Definition: types.h:112
VOID DeleteFromFailedCreate(VOID)
Definition: fxobject.cpp:391
VOID FlushAndRundown()
Definition: fxdpc.cpp:387
FX_TRACK_DRIVER(fxDriverGlobals)
FxCallbackLock * m_CallbackLock
Definition: fxdpc.hpp:79
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:711
#define __in
Definition: dbghelp.h:35
static SERVICE_STATUS status
Definition: service.c:31
VOID NTAPI KeFlushQueuedDpcs(VOID)
Definition: dpc.c:918
VOID DpcHandler(__in PKDPC Dpc, __in PVOID SystemArgument1, __in PVOID SystemArgument2)
Definition: fxdpc.cpp:295
FxVerifierDbgBreakPoint(pFxDriverGlobals)
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
Definition: ps.c:97
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675