ReactOS  0.4.15-dev-3175-g222acf5
fxsystemworkitem.cpp
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7  FxSystemWorkItem.hpp
8 
9 Abstract:
10 
11  This module implements a frameworks managed WORKITEM that
12  can synchrononize with driver frameworks object locks.
13 
14 Author:
15 
16 
17 
18 Environment:
19 
20  Both kernel and user mode
21 
22 Revision History:
23 
24 
25 --*/
26 
27 #include "coreprivshared.hpp"
28 
29 #include "fxsystemworkitem.hpp"
30 
31 // Tracing support
32 extern "C" {
33 // #include "FxSystemWorkItem.tmh"
34 }
35 
36 //
37 // Public constructors
38 //
42  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
43  __in PVOID WdmObject,
45  )
46 {
48  FxSystemWorkItem* wi;
49 
50  wi = new(FxDriverGlobals) FxSystemWorkItem(FxDriverGlobals);
51  if (wi == NULL) {
53  }
54 
55  status = wi->Initialize(WdmObject);
56  if (!NT_SUCCESS(status)) {
57  wi->Release();
58  return status;
59  }
60 
61  *pObject = wi;
62 
63  return status;
64 }
65 
67  __in PFX_DRIVER_GLOBALS FxDriverGlobals
68  ) :
69  FxNonPagedObject(FX_TYPE_SYSTEMWORKITEM, 0, FxDriverGlobals),
70  m_WorkItemCompleted(NotificationEvent, TRUE),
71  m_RemoveEvent(SynchronizationEvent, FALSE)
72 {
74  m_Enqueued = FALSE;
75  m_Callback = NULL;
79 }
80 
82 {
83  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
84 
85  //
86  // If this hits, it's because someone destroyed the WORKITEM by
87  // removing too many references by mistake without calling WdfObjectDelete
88  //
89  if( !m_RunningDown && (m_WorkItem.GetWorkItem() != NULL)) {
91  "WorkItem destroyed without calling "
92  "FxSystemWorkItem::Delete, or by Framework "
93  "processing DeviceRemove. "
94  "Possible reference count problem?");
95  FxVerifierDbgBreakPoint(FxDriverGlobals);
96  }
97 
98  // Free the workitem
99  if( m_WorkItem.GetWorkItem() != NULL ) {
100  m_WorkItem.Free();
101  }
102 
103  ASSERT(m_Enqueued == FALSE);
105 
106  return;
107 }
108 
110 NTSTATUS
112  __in PVOID WdmObject
113  )
114 {
115  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
117 
118  //
119  // Mark this object as passive level to ensure that Dispose() is passive
120  //
122 
124 
125 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
127  if (!NT_SUCCESS(status)) {
129  "Could not initialize m_WorkItemCompleted event "
130  "status %!status!", status);
131  return status;
132  }
133 
135  if(!NT_SUCCESS(status)) {
137  "Could not initialize m_RemoveEvent event "
138  "status %!status!", status);
139  return status;
140  }
141 #endif
142 
143  //
144  // Allocate the PIO_WORKITEM we will re-use
145  //
146  status = m_WorkItem.Allocate((MdDeviceObject) WdmObject);
147  if(!NT_SUCCESS(status)) {
149  "Could not allocate IoWorkItem, insufficient resources");
150  return status;
151  }
152 
154 
155  return STATUS_SUCCESS;
156 }
157 
158 BOOLEAN
162  __in BOOLEAN AssertIfAlreadyQueued
163  )
164 /*++
165 
166 Routine Description:
167 
168  Called to queue the workitem. This function, under verifier, will
169  throw an assert if AssertIfAlreadyQueued parameter is set.
170 
171 Arguments:
172  Func - Callback function.
173 
174  Parameter - Callback's context.
175 
176  AssertIfAlreadyQueued - is used to make sure that caller doesn't
177  miss any workitem callback.
178 
179 Return Value:
180 
181  FALSE
182  - if the previously queued workitem hasn't run to completion.
183  - if the object is running down.
184 
185  TRUE - workitem is queued.
186 --*/
187 {
189  KIRQL irql;
190 
192 
193  Lock(&irql);
194 
195  if( m_Enqueued ) {
196  if (AssertIfAlreadyQueued) {
198  "WorkItem 0x%p already enqueued IoWorkItem 0x%p",
199  this, m_WorkItem.GetWorkItem());
201  }
202 
203  Unlock(irql);
204  return FALSE;
205  }
206 
207  //
208  // If running down, fail
209  //
210  if( m_RunningDown ) {
212  "WorkItem 0x%p is already deleted", this);
214  Unlock(irql);
215  return FALSE;
216  }
217 
219 
220  m_Callback = Func;
222 
223  m_Enqueued = TRUE;
224 
225  // Add a reference while outstanding
227 
228  Unlock(irql);
229 
231 
232  return TRUE;
233 }
234 
235 VOID
237 {
239  PVOID CallbackArg;
240  KIRQL irql;
241 
243 
244  Lock(&irql);
245 
246  m_Enqueued = FALSE;
247 
249  CallbackArg = m_CallbackArg;
250 
251  m_Callback = NULL;
252 
253  //
254  // We should only see this count rise to a small number (like 10 or so).
255  //
257 
259 
260  Unlock(irql);
261 
262  Callback(CallbackArg);
263 
264  Lock(&irql);
265 
267 
268  //
269  // The driver could re-enqueue a new callback from within the
270  // callback handler, which could make m_Enqueued no longer false.
271  //
272  // We only set the event specifying the callback as completed when
273  // we are ensured that no more workitems are enqueued.
274  //
275  if (m_WorkItemRunningCount == 0L && m_Enqueued == FALSE) {
277  }
278 
279  Unlock(irql);
280 
281  return;
282 }
283 
284 VOID
288  )
289 
290 /*++
291 
292 Routine Description:
293 
294  This is the static routine called by the kernel's PIO_WORKITEM handler.
295 
296  A reference count was taken by Enqueue, which this routine releases
297  on return.
298 
299 Arguments:
300 
301 Return Value:
302 
303  Nothing.
304 
305 --*/
306 
307 {
309 
311 
312  pWorkItem->WorkItemHandler();
313 
314  // Release the reference taken when enqueued
315  pWorkItem->DecrementWorkItemQueued();
316 
317  return;
318 }
319 
320 //
321 // Invoked when DeleteObject is called on the object, or its parent.
322 //
323 BOOLEAN
325  )
326 {
327  KIRQL irql;
328 
330 
331  Lock(&irql);
332 
334 
336 
337  Unlock(irql);
338 
340 
341  return TRUE;
342 }
343 
344 //
345 // Wait until any outstanding WorkItem has completed safely
346 //
347 // Can only be called after Delete
348 //
349 // The caller must call AddRef() and Release() around this call
350 // to ensure the FxSystemWorkItem remains valid while it is doing the
351 // wait.
352 //
353 VOID
355  )
356 {
358 
359  //
360  // Wait for current workitem to complete processing
361  //
363 
366 
367  //
368  // This assert is not under a lock, but the code in WorkItemHandler()
369  // clears m_Enqueued under the lock, thus releasing it with a memory
370  // barrier. Since we have ensured above that no one can re-queue a request
371  // due to m_RunningDown, we should not hit this assert unless there
372  // is a code problem with wakeup occuring while an outstanding
373  // workitem is running.
374  //
375  ASSERT(m_Enqueued == FALSE);
376 
377  return;
378 }
379 
PFN_WDF_SYSTEMWORKITEM m_Callback
__drv_restoresIRQL KIRQL __in BOOLEAN Unlock
Definition: fxobject.hpp:1474
FxObject * pObject
CHECK_RETURN_IF_USER_MODE NTSTATUS Initialize(__in BOOLEAN InitialState=FALSE)
Definition: fxwaitlock.hpp:51
virtual ULONG Release(__in_opt PVOID Tag=NULL, __in LONG Line=0, __in_opt PSTR File=NULL)
Definition: fxobject.hpp:853
static _Must_inspect_result_ NTSTATUS _Create(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PVOID WdmObject, __out FxSystemWorkItem **pObject)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
virtual ~FxSystemWorkItem()
FxSystemWorkItem(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
__inline MdWorkItem GetWorkItem()
Definition: mxworkitemkm.h:73
#define __in_opt
Definition: dbghelp.h:38
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
EVT_SYSTEMWORKITEM * PFN_WDF_SYSTEMWORKITEM
LONG NTSTATUS
Definition: precomp.h:26
FxCREvent m_WorkItemCompleted
KIRQL irql
Definition: wave.h:1
_In_ PVOID Parameter
Definition: ldrtypes.h:241
virtual BOOLEAN Dispose(VOID)
VOID Set(VOID)
Definition: fxwaitlock.hpp:144
UCHAR KIRQL
Definition: env_spec_w32.h:591
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define FALSE
Definition: types.h:117
VOID MarkDisposeOverride(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:1101
#define __out
Definition: dbghelp.h:62
NTSTATUS EnterCRAndWaitAndLeave(VOID)
Definition: fxwaitlock.hpp:87
unsigned char BOOLEAN
_Must_inspect_result_ __inline NTSTATUS Allocate(__in MdDeviceObject DeviceObject, __in_opt PVOID ThreadPoolEnv=NULL)
Definition: mxworkitemkm.h:41
__inline VOID DecrementWorkItemQueued()
VOID MarkPassiveCallbacks(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:972
Status
Definition: gdiplustypes.h:24
#define TRACINGDEVICE
Definition: dbgtrace.h:58
PFX_DRIVER_GLOBALS pFxDriverGlobals
#define ASSERT(a)
Definition: mode.c:44
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID Clear(VOID)
Definition: fxwaitlock.hpp:152
static __inline KIRQL MxGetCurrentIrql()
Definition: mxgeneralkm.h:86
__inline VOID Enqueue(__in PMX_WORKITEM_ROUTINE Callback, __in PVOID Context)
Definition: mxworkitemkm.h:58
BOOLEAN EnqueueWorker(__in PFN_WDF_SYSTEMWORKITEM Func, __in PVOID Parameter, __in BOOLEAN AssertIfAlreadyQueued)
static const WCHAR L[]
Definition: oid.c:1250
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
#define _Must_inspect_result_
Definition: ms_sal.h:558
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
_In_ WDFINTERRUPT _In_ PFN_WDF_INTERRUPT_SYNCHRONIZE Callback
Definition: wdfinterrupt.h:456
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
void(* Func)(int)
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
#define NULL
Definition: types.h:112
__inline VOID Free()
Definition: mxworkitemkm.h:90
_Must_inspect_result_ NTSTATUS Initialize(__in PVOID WdmObject)
FX_TRACK_DRIVER(fxDriverGlobals)
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:124
__inline VOID ReleaseWorkItemQueuedCountAndWait()
#define STATUS_SUCCESS
Definition: shellext.h:65
__inline VOID IncrementWorkItemQueued()
static MX_WORKITEM_ROUTINE _WorkItemThunk
#define __in
Definition: dbghelp.h:35
static SERVICE_STATUS status
Definition: service.c:31
FxVerifierDbgBreakPoint(pFxDriverGlobals)
Definition: ps.c:97