ReactOS 0.4.16-dev-340-g0540c21
fxworkitem.cpp
Go to the documentation of this file.
1/*++
2
3Copyright (c) Microsoft Corporation
4
5Module Name:
6
7 FxWorkItem.hpp
8
9Abstract:
10
11 This module implements a frameworks managed WORKITEM that
12 can synchrononize with driver frameworks object locks.
13
14Author:
15
16
17
18Environment:
19
20 Both kernel and user mode
21
22Revision History:
23
24
25--*/
26
27#include "coreprivshared.hpp"
28
29#include "fxworkitem.hpp"
30
31#if (FX_CORE_MODE == FX_CORE_USER_MODE)
32//
33// For DRIVER_OBJECT_UM definition
34//
35#include "fxldrum.h"
36#endif
37
38// Tracing support
39extern "C" {
40// #include "FxWorkItem.tmh"
41}
42
44 __in PFX_DRIVER_GLOBALS FxDriverGlobals
45 ) :
47 m_WorkItemCompleted(NotificationEvent, TRUE)
48{
49 m_Object = NULL;
57
58 //
59 // All operations on a workitem are PASSIVE_LEVEL so ensure that any Dispose
60 // and Destroy callbacks to the driver are as well.
61 //
63
65}
66
67
69 VOID
70 )
71{
73
75
76 //
77 // If this hits, it's because someone destroyed the WORKITEM by
78 // removing too many references by mistake without calling WdfObjectDelete
79 //
80 if (m_RunningDown == FALSE && m_Callback != NULL) {
83 "WDFWORKITEM %p destroyed without calling WdfObjectDelete, or by "
84 "Framework processing DeviceRemove. Possible reference count "
85 "problem?", GetObjectHandleUnchecked());
87 }
88
89 // Release our parent object reference
90 if (m_Object != NULL) {
91 m_Object->RELEASE(this);
92 m_Object = NULL;
93 }
94
95 // Free the workitem
96 if (m_WorkItem.GetWorkItem() != NULL) {
98 //m_WorkItem = NULL;
99 }
100
103
104 return;
105}
106
110 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
113 __in FxObject* ParentObject,
114 __out WDFWORKITEM* WorkItem
115 )
116{
119
120 pFxWorkItem = new(FxDriverGlobals, Attributes) FxWorkItem(FxDriverGlobals);
121
122 if (pFxWorkItem == NULL) {
124 }
125
128 Config,
129 ParentObject,
131 );
132
133 if (!NT_SUCCESS(status)) {
135 }
136
137 return status;
138}
139
145 __in FxObject* ParentObject,
146 __out WDFWORKITEM* WorkItem
147 )
148{
150 IFxHasCallbacks* pCallbacks;
152
154
155#if (FX_CORE_MODE == FX_CORE_USER_MODE)
157 if(!NT_SUCCESS(status)) {
159 "Could not initialize m_WorkItemCompleted event "
160 "%!STATUS!", status);
161 return status;
162 }
163#endif
164
165 ASSERT(Config->EvtWorkItemFunc != NULL);
166
167 // Set users callback function
168 m_Callback = Config->EvtWorkItemFunc;
169
170 //
171 // As long as we are associated, the parent object holds a reference
172 // count on the WDFWORKITEM.
173 //
174 // This reference must be taken early before we return any failure,
175 // since Dispose() expects this extra reference, and Dispose() will
176 // be called even if we return a failure status right now.
177 //
178 ADDREF(this);
179
180 //
181 // WorkItems can be parented by, and optionally serialize with an FxDevice or an FxQueue
182 //
183 m_DeviceBase = FxDeviceBase::_SearchForDevice(ParentObject, &pCallbacks);
184
185 if (m_DeviceBase == NULL) {
187 }
188
189 //
190 // Determine if it's an FxDevice, or FxIoQueue and get the
191 // CallbackSpinLock pointer for it.
192 //
194 ParentObject,
195 pCallbacks,
196 Config->AutomaticSerialization,
197 TRUE,
200 );
201
202 if (!NT_SUCCESS(status)) {
204
205
206
207
208
209
212 "ParentObject %p cannot automatically synchronize callbacks "
213 "with a WorkItem since it is not configured for passive level "
214 "callback constraints. Use a WDFDPC instead or set "
215 "AutomaticSerialization to FALSE."
216 "%!STATUS!", Attributes->ParentObject, status);
217 }
218
219 return status;
220 }
221
222 //
223 // Allocate the PIO_WORKITEM we will re-use
224 //
225#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
227#elif (FX_CORE_MODE == FX_CORE_USER_MODE)
230 (PVOID)&m_Device->GetDriver()->GetDriverObject()->ThreadPoolEnv);
231#endif
232 if (m_WorkItem.GetWorkItem() == NULL) {
236 "Could not allocate IoWorkItem, %!STATUS!", status);
237 return status;
238 }
239
240 //
241 // We automatically synchronize with and reference count
242 // the lifetime of the framework object to prevent any WORKITEM races
243 // that can access the object while it is going away.
244 //
245
246 //
247 // The caller supplied object is the object the caller wants the
248 // WorkItem to be associated with, and the framework must ensure this
249 // object remains live until the WorkItem object is destroyed. Otherwise,
250 // it could access either object context memory, or an object API
251 // on a freed object.
252 //
253 // Due to the locking model of the framework, the lock may actually
254 // be owned by a higher level object as well. This is the lockObject
255 // returned. As long as we are a child of this object, the lockObject
256 // does not need to be dereferenced since it will notify us of Cleanup
257 // before it goes away.
258 //
259
260 //
261 // Associate the FxWorkItem with the object. When this object Cleans up, it
262 // will notify our Cleanup function as well.
263 //
264
265 //
266 // Add a reference to the parent object we are associated with.
267 // We will be notified of Cleanup to release this reference.
268 //
269 ParentObject->ADDREF(this);
270
271 // Save the ptr to the object the WorkItem is associated with
272 m_Object = ParentObject;
273
274 //
275 // Attributes->ParentObject is the same as ParentObject. Since we already
276 // converted it to an object, use that.
277 //
278 status = Commit(Attributes, (WDFOBJECT*)WorkItem, ParentObject);
279
280 if (!NT_SUCCESS(status)) {
281 return status;
282 }
283
284 return status;
285}
286
287VOID
289 VOID
290 )
291{
293 KIRQL irql;
294 BOOLEAN enqueue;
295
297 enqueue = FALSE;
298
299 Lock(&irql);
300
301 if (m_Enqueued) {
304 "Previously queued WDFWORKITEM 0x%p is already pending. "
305 "Ignoring the request to queue again", GetHandle());
306 }
307 else if (m_RunningDown) {
309 "WDFWORKITEM 0x%p is already deleted", GetHandle());
311 }
312 else {
314
316
317 //
318 // We are going to enqueue the work item. Reference this FxWorkItem
319 // object and Globals while they are outstanding.
320 // These will be released when the workitem completes.
321 //
324
325 enqueue = TRUE;
326 }
327
328 Unlock(irql);
329
330 if (enqueue) {
332 }
333
334 return;
335}
336
337VOID
339 VOID
340 )
341{
342 KIRQL irql;
343
345
346 Lock(&irql);
347
348 //
349 // Mark the workitem as no longer enqueued and completed
350 //
351 // The handler is allowed to re-enqueue, so mark it before the callback
352 //
354
356
357 Unlock(irql);
358
359 if (m_CallbackLock != NULL) {
361#if FX_IS_KERNEL_MODE
363#endif
366 }
367 else {
368#if FX_IS_KERNEL_MODE
370#endif
372 }
373
374 Lock(&irql);
375
377
378 //
379 // The workitem can be re-enqueued by the drivers
380 // work item handler routine. We can't set the work
381 // item completed event until we are sure there are
382 // no outstanding work items.
383 //
384
387 }
388
389 Unlock(irql);
390}
391
392VOID
396 )
397/*++
398
399Routine Description:
400
401 This is the static routine called by the kernels PIO_WORKITEM handler.
402
403 A reference count was taken by Enqueue, which this routine releases
404 on return.
405
406Arguments:
407 DeviceObject - the devobj we passed to IoCreateWorkItem
408
409 Context - the internal Fx object
410
411Return Value:
412 None
413
414--*/
415{
416 FxWorkItem* pWorkItem;
418
420
421 pWorkItem = (FxWorkItem*)Context;
422 pFxDriverGlobals = pWorkItem->GetDriverGlobals();
423
424 //
425 // Save the current worker thread object pointer. We will use this avoid
426 // deadlock if the driver tries to delete or flush the workitem from within
427 // the callback.
428 //
430
431 pWorkItem->WorkItemHandler();
432
433 pWorkItem->m_WorkItemThread = NULL;
434
435 //
436 // Release the reference on the FxWorkItem and Globals taken when Enqueue
437 // was done. This may release the FxWorkItem if it is running down.
438 //
439 pWorkItem->RELEASE((PVOID)WorkItemThunk);
440
441 //
442 // This may release the driver if it is running down.
443 //
445}
446
447VOID
449 VOID
450 )
451{
453
454 //
455 // Wait for any outstanding workitem to complete if the workitem is not
456 // deleted from within the workitem callback to avoid deadlock.
457 //
460 }
461
462 //
463 // Release our reference count to the associated parent object if present
464 //
465 if (m_Object != NULL) {
467 m_Object = NULL;
468
469 pObject->RELEASE(this);
470 }
471
472 //
473 // Perform our final release to ourselves, destroying the FxWorkItem
474 //
475 RELEASE(this);
476}
477
480 VOID
481 )
482/*++
483
484Routine Description:
485 Called when DeleteObject is called, or when the parent is being deleted or
486 Disposed.
487
488Arguments:
489 None
490
491Return Value:
492 TRUE if the cleanup routines should be invoked, FALSE otherwise
493
494 --*/
495{
496 KIRQL irql;
497
498 Lock(&irql);
500 Unlock(irql);
501
503
504 return TRUE;
505}
506
507VOID
509{
511
513
516 "Calling WdfWorkItemFlush from within the WDFWORKITEM "
517 "%p callback will lead to deadlock, PRKTHREAD %p",
520 return;
521 }
522
523 //
524 // Wait for any outstanding workitem to complete.
525 // The event is only set upon return from the callback
526 // into the driver *and* the driver did not re-queue
527 // the workitem. See similar comment in WorkItemHandler().
528 //
530 return;
531}
532
533VOID
535 VOID
536 )
537{
538 LARGE_INTEGER timeOut;
540
542
543 timeOut.QuadPart = WDF_REL_TIMEOUT_IN_SEC(60);
544
545 do {
547 if (status == STATUS_TIMEOUT) {
548 DbgPrint("Thread 0x%p is waiting on WDFWORKITEM 0x%p\n",
550 GetHandle());
551 }
552 else {
554 break;
555 }
556 } WHILE(TRUE);
557
558
560 return;
561}
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
virtual void Lock(__out PKIRQL PreviousIrql)=0
virtual void Unlock(__in KIRQL PreviousIrql)=0
static FxDeviceBase * _SearchForDevice(__in FxObject *Object, __out_opt IFxHasCallbacks **Callbacks)
__inline FxDriver * GetDriver(VOID)
Definition: fxdevice.hpp:164
MdDeviceObject __inline GetDeviceObject(VOID)
Definition: fxdevice.hpp:174
__inline MdDriverObject GetDriverObject(VOID)
Definition: fxdriver.hpp:252
PVOID __inline GetObjectHandleUnchecked(VOID)
Definition: fxobject.hpp:446
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
CfxDevice * m_Device
Definition: fxobject.hpp:329
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
CfxDeviceBase * m_DeviceBase
Definition: fxobject.hpp:328
__drv_restoresIRQL KIRQL __in BOOLEAN Unlock
Definition: fxobject.hpp:1474
VOID DeleteFromFailedCreate(VOID)
Definition: fxobject.cpp:391
VOID MarkPassiveCallbacks(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:972
VOID MarkDisposeOverride(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:1101
_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
FxWorkItem(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
Definition: fxworkitem.cpp:43
virtual ~FxWorkItem()
Definition: fxworkitem.cpp:68
FxCREvent m_WorkItemCompleted
Definition: fxworkitem.hpp:98
VOID Enqueue()
Definition: fxworkitem.cpp:288
FxObject * m_Object
Definition: fxworkitem.hpp:75
VOID WorkItemHandler()
Definition: fxworkitem.cpp:338
FxCallbackLock * m_CallbackLock
Definition: fxworkitem.hpp:81
BOOLEAN m_RunningDown
Definition: fxworkitem.hpp:56
ULONG m_WorkItemRunningCount
Definition: fxworkitem.hpp:69
static MX_WORKITEM_ROUTINE WorkItemThunk
Definition: fxworkitem.hpp:216
MxThread m_WorkItemThread
Definition: fxworkitem.hpp:105
_Must_inspect_result_ NTSTATUS Initialize(__in PWDF_OBJECT_ATTRIBUTES Attributes, __in PWDF_WORKITEM_CONFIG Config, __in FxObject *ParentObject, __out WDFWORKITEM *WorkItem)
Definition: fxworkitem.cpp:142
FxObject * m_CallbackLockObject
Definition: fxworkitem.hpp:87
VOID FlushAndRundown()
Definition: fxworkitem.cpp:448
VOID FlushAndWait(VOID)
Definition: fxworkitem.cpp:508
VOID WaitForSignal(VOID)
Definition: fxworkitem.cpp:534
PFN_WDF_WORKITEM m_Callback
Definition: fxworkitem.hpp:92
virtual BOOLEAN Dispose(VOID)
Definition: fxworkitem.cpp:479
BOOLEAN m_Enqueued
Definition: fxworkitem.hpp:61
static _Must_inspect_result_ NTSTATUS _Create(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PWDF_WORKITEM_CONFIG Config, __in PWDF_OBJECT_ATTRIBUTES Attributes, __in FxObject *ParentObject, __out WDFWORKITEM *WorkItem)
Definition: fxworkitem.cpp:109
MxWorkItem m_WorkItem
Definition: fxworkitem.hpp:53
__inline MdWorkItem GetWorkItem()
Definition: mxworkitemkm.h:73
__inline VOID Free()
Definition: mxworkitemkm.h:90
_Must_inspect_result_ __inline NTSTATUS Allocate(__in MdDeviceObject DeviceObject, __in_opt PVOID ThreadPoolEnv=NULL)
Definition: mxworkitemkm.h:41
static __inline MdEThread GetCurrentEThread()
Definition: mxgeneralkm.h:69
static __inline MxThread MxGetCurrentThread()
Definition: mxgeneralkm.h:61
static __inline KIRQL MxGetCurrentIrql()
Definition: mxgeneralkm.h:86
#define STATUS_TIMEOUT
Definition: d3dkmdt.h:49
#define __in
Definition: dbghelp.h:35
#define __in_opt
Definition: dbghelp.h:38
#define __out
Definition: dbghelp.h:62
#define TRACINGDEVICE
Definition: dbgtrace.h:58
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
KIRQL irql
Definition: wave.h:1
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
PFX_DRIVER_GLOBALS pFxDriverGlobals
FX_TRACK_DRIVER(fxDriverGlobals)
FxVerifierDbgBreakPoint(pFxDriverGlobals)
#define WHILE(constant)
Definition: fxmacros.hpp:226
@ ObjectDoNotLock
Definition: fxobject.hpp:128
#define ADDREF(_tag)
Definition: fxobject.hpp:49
#define RELEASE(_tag)
Definition: fxobject.hpp:50
FxObject * pObject
FORCEINLINE VOID FxPerfTraceWorkItem(_In_ PVOID DriverCallback)
@ FX_TYPE_WORKITEM
Definition: fxtypes.h:78
FxWorkItem * pFxWorkItem
#define DbgPrint
Definition: hal.h:12
#define ASSERT(a)
Definition: mode.c:44
#define _Must_inspect_result_
Definition: no_sal2.h:62
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
@ NotificationEvent
#define L(x)
Definition: ntvdm.h:50
#define TRACE_LEVEL_VERBOSE
Definition: storswtr.h:30
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
NTSTATUS EnterCRAndWaitAndLeave(VOID)
Definition: fxwaitlock.hpp:87
VOID Set(VOID)
Definition: fxwaitlock.hpp:144
VOID Clear(VOID)
Definition: fxwaitlock.hpp:152
CHECK_RETURN_IF_USER_MODE NTSTATUS Initialize(__in BOOLEAN InitialState=FALSE)
Definition: fxwaitlock.hpp:51
Definition: ps.c:97
#define GetHandle(h)
Definition: treelist.c:116
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
LONGLONG QuadPart
Definition: typedefs.h:114
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_CHILD_LIST_CONFIG Config
Definition: wdfchildlist.h:476
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
FORCEINLINE LONGLONG WDF_REL_TIMEOUT_IN_SEC(_In_ ULONGLONG Time)
Definition: wdfcore.h:62
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL
Definition: wdfstatus.h:198
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:127
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:115
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList