ReactOS 0.4.15-dev-8222-g9164419
eventqueue.cpp
Go to the documentation of this file.
1/*++
2
3Copyright (c) Microsoft. All rights reserved.
4
5Module Name:
6
7 EventQueue.cpp
8
9Abstract:
10
11 This module implements a baseline event queue structure which takes care of
12 90% of the work requireed to run a state machine
13
14Author:
15
16
17
18Environment:
19
20 Both kernel and user mode
21
22Revision History:
23
24
25
26--*/
27
28#include "pnppriv.hpp"
29
30extern "C" {
31#if defined(EVENT_TRACING)
32#include "EventQueue.tmh"
33#endif
34}
35
37 __in UCHAR QueueDepth
38 )
39{
40 m_PkgPnp = NULL;
42
44 m_QueueHead = 0;
45 m_QueueTail = 0;
46 m_QueueDepth = QueueDepth;
47
49 m_QueueFlags = 0x0;
51}
52
57 )
58{
60
61 //
62 // For KM, lock initialize always succeeds. For UM, it might fail.
63 //
65 if (!NT_SUCCESS(status)) {
68 "Initializing state machine lock failed for EventQueue 0x%p, "
69 "status %!STATUS!",
70 this, status);
71 }
72
73 return status;
74}
75
76VOID
78 __in FxPkgPnp* Pnp,
81 )
82{
83 m_PkgPnp = Pnp;
86
87 return;
88}
89
93 )
94/*++
95
96Routine Description:
97 Puts the queue into a closed state. If the queue cannot be closed and
98 finished in this context, the Event is stored and set when it moves into
99 the finished state
100
101Arguments:
102 Event - the event to set when we move into the finished state
103
104Return Value:
105 TRUE if the queue is closed in this context, FALSE if the Event should be
106 waited on.
107
108 --*/
109{
110 KIRQL irql;
112
113 result = TRUE;
114
115 Lock(&irql);
118
120
121 if (result == FALSE) {
123 }
124
125 Unlock(irql);
126
127 if (result) {
128 Event->Set();
129 }
130
131 return result;
132}
133
134VOID
136 VOID
137 )
138{
139 KIRQL irql;
140
143 "WDFDEVICE 0x%p !devobj 0x%p delaying deletion to outside state machine",
146
147 Lock(&irql);
150 Unlock(irql);
151}
152
155 VOID
156 )
157/*++
158
159Routine Description:
160 Generic worker function which encapsulates the logic of whether to enqueue
161 onto a different thread if the thread has not already been queued to.
162
163 NOTE: this function could have been virtual, or call a virtual worker function
164 once we have determined that we need to queue to a thread. But to save
165 space on vtable storage (why have one unless you really need one?),
166 we rearrange the code so that the derived class calls the worker function
167 and this function indicates in its return value what the caller should
168 do
169
170Arguments:
171 None
172
173Return Value:
174 TRUE if the caller should queue to a thread to do the work
175 FALSE if the caller shoudl not queue to a thread b/c it has already been
176 queued
177
178 --*/
179{
180 KIRQL irql;
182
183 Lock(&irql);
184
185 //
186 // For one reason or another, we couldn't run the state machine on this
187 // thread. So queue a work item to do it.
188 //
189 if (IsEmpty()) {
190 //
191 // There is no work to do. This means that the caller inserted the
192 // event into the queue, dropped the lock, and then another thread came
193 // in and processed the event.
194 //
195 // This check also helps in the rundown case when the queue is closing
196 // and the following happens between 2 thread:
197 // #1 #2
198 // insert event
199 // drop lock
200 // process event queue
201 // queue goes to empty, so event is set
202 // try to queue work item
203 //
204 result = FALSE;
205
208 "WDFDEVICE 0x%p !devobj 0x%p not queueing work item to process "
209 "event queue", m_PkgPnp->GetDevice()->GetHandle(),
211 }
212 else if ((m_QueueFlags & FxEventQueueFlagWorkItemQueued) == 0x00) {
214 result = TRUE;
215 }
216 else {
217 //
218 // Somebody is already in the process of enqueuing the work item.
219 //
220 result = FALSE;
221 }
222
223 Unlock(irql);
224
225 return result;
226}
227
228VOID
230 VOID
231 )
232/*++
233
234Routine Description:
235 This is the work item that attempts to run the queue state machine on
236 the special power thread.
237
238
239--*/
240{
242 KIRQL irql;
244
245#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
247#endif
248
249 //
250 // Cache away m_PkgPnp while we know we still have a valid object. Once
251 // we Unlock() after the worker routine, the object could be gone until
252 // the worker routine set a flag postponing deletion.
253 //
255
256 Lock(&irql);
257
259
260 //
261 // Clear the queued flag, so that it's clear that the work item can
262 // be safely re-enqueued.
263 //
264 m_QueueFlags &= ~FxEventQueueFlagWorkItemQueued;
265
266 //
267 // We should only see this count rise to a small number (like 10 or so).
268 //
271
272 Unlock(irql);
273
274 //
275 // Call the function that will actually run the state machine.
276 //
278
279 Lock(&irql);
282 Unlock(irql);
283
284 //
285 // NOTE: There is no need to use a reference count to keep this event queue
286 // (and the containing state machine) alive. Instead, the thread
287 // which wants to delete the state machine must wait for this work
288 // item to exit. If there was a reference to release, we would have
289 // a race between Unlock()ing and releasing the reference if the state
290 // machine moved into the finished state and deletes the device after
291 // we dropped the lock, but before we released the reference.
292 //
293 // This is important in that the device deletion can trigger
294 // DriverUnload to run before the release executes. DriverUnload
295 // frees the IFR buffer. If this potential release logs something to
296 // the IFR, you would bugcheck. Since it is impossible to defensively
297 // prevent all destructors from logging to the IFR, we can't use a
298 // ref count here to keep the queue alive.
299 //
300
301 //
302 // If Evaluate needs to use pPkgPnp, then the call to the worker routine
303 // above made sure that pPkgPnp has not yet been freed.
304 //
305 info.Evaluate(pPkgPnp);
306}
307
309 __in UCHAR QueueDepth
310 ) : FxEventQueue(QueueDepth)
311{
312}
313
315{
317}
318
322 __inout FxPkgPnp* Pnp,
324 __in PVOID WorkerContext
325 )
326{
328
329 Configure(Pnp, WorkerRoutine, WorkerContext);
330
331
332
333
334
335
336
337
338
339
340
343 );
344
345 if (!NT_SUCCESS(status)) {
346 return status;
347 }
348
349 return STATUS_SUCCESS;
350}
351
353 __in UCHAR QueueDepth
354 ) : FxEventQueue(QueueDepth)
355{
358 this);
359}
360
362 VOID
363 )
364{
366}
367
371 __inout FxPkgPnp* Pnp,
373 __in PVOID WorkerContext
374 )
375{
377
378 Configure(Pnp, WorkerRoutine, WorkerContext);
379
380
381 status = m_WorkItem.Allocate(Pnp->GetDevice()->GetDeviceObject());
382 if (!NT_SUCCESS(status)) {
383 return status;
384 }
385
386 return STATUS_SUCCESS;
387}
388
389VOID
392 )
393{
395
396 This->EventQueueWorker();
397}
398
399VOID
401 VOID
402 )
403{
404 if (m_PkgPnp->HasPowerThread()) {
405 //
406 // Use the power thread for the stack
407 //
409 }
410 else {
411 //
412 // Use the work item since the power thread is not available
413 //
415 (FxEventQueue*) this);
416 }
417}
418
419VOID
423 )
424/*++
425
426Routine Description:
427 This is the work item that attempts to run the machine on a thread
428 separate from the one the caller was using.
429
430--*/
431{
433
435
436 This->EventQueueWorker();
437}
438
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
WDFDEVICE __inline GetHandle(VOID)
Definition: fxdevice.hpp:237
MdDeviceObject __inline GetDeviceObject(VOID)
Definition: fxdevice.hpp:174
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
__inline CfxDevice * GetDevice(VOID)
Definition: fxpackage.hpp:46
VOID QueueToPowerThread(__in PWORK_QUEUE_ITEM WorkItem)
Definition: fxpkgpnp.hpp:3516
BOOLEAN HasPowerThread(VOID)
Definition: fxpkgpnp.hpp:3508
CHECK_RETURN_IF_USER_MODE NTSTATUS Initialize()
Definition: fxwaitlock.hpp:235
__inline VOID Enqueue(__in PMX_WORKITEM_ROUTINE Callback, __in PVOID Context)
Definition: mxworkitemkm.h:58
__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
#define __in
Definition: dbghelp.h:35
#define __inout
Definition: dbghelp.h:50
#define TRACINGPNP
Definition: dbgtrace.h:67
#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:32
@ IsEmpty
Definition: atl_ax.c:995
KIRQL irql
Definition: wave.h:1
UCHAR KIRQL
Definition: env_spec_w32.h:591
_Must_inspect_result_ _In_ PFLT_CALLBACK_DATA _In_ PFLT_DEFERRED_IO_WORKITEM_ROUTINE WorkerRoutine
Definition: fltkernel.h:1977
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
FX_TRACK_DRIVER(fxDriverGlobals)
FxPkgPnp * pPkgPnp
DriverGlobals
VOID(* PFN_PNP_EVENT_WORKER)(__in FxPkgPnp *PkgPnp, __in FxPostProcessInfo *Info, __in PVOID Context)
@ FxEventQueueFlagWorkItemQueued
@ FxEventQueueFlagClosed
@ FxEventQueueFlagDelayDeletion
GLuint64EXT * result
Definition: glext.h:11304
#define ASSERT(a)
Definition: mode.c:44
#define _Must_inspect_result_
Definition: ms_sal.h:558
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
@ Unlock
Definition: ntsecapi.h:294
#define STATUS_SUCCESS
Definition: shellext.h:65
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
UCHAR m_HistoryIndex
BOOLEAN QueueToThreadWorker(VOID)
Definition: eventqueue.cpp:154
FxEventQueue(__in UCHAR QueueDepth)
Definition: eventqueue.cpp:36
UCHAR m_WorkItemRunningCount
VOID EventQueueWorker(VOID)
Definition: eventqueue.cpp:229
FxPkgPnp * m_PkgPnp
BOOLEAN IsIdleLocked(VOID)
FxWaitLockInternal m_StateMachineLock
VOID Configure(__in FxPkgPnp *Pnp, __in PFN_PNP_EVENT_WORKER WorkerRoutine, __in PVOID Context)
Definition: eventqueue.cpp:77
FxCREvent * m_WorkItemFinished
BOOLEAN SetFinished(__in FxCREvent *Event)
Definition: eventqueue.cpp:91
VOID GetFinishedState(__inout FxPostProcessInfo *Info)
PFN_PNP_EVENT_WORKER m_EventWorker
_Must_inspect_result_ NTSTATUS Initialize(__in PFX_DRIVER_GLOBALS DriverGlobals)
Definition: eventqueue.cpp:55
PVOID m_EventWorkerContext
VOID SetDelayedDeletion(VOID)
Definition: eventqueue.cpp:135
static MX_WORKITEM_ROUTINE _WorkItemCallback
_Must_inspect_result_ NTSTATUS Init(__inout FxPkgPnp *Pnp, __in PFN_PNP_EVENT_WORKER WorkerRoutine, __in PVOID WorkerContext=NULL)
Definition: eventqueue.cpp:370
VOID QueueWorkItem(VOID)
Definition: eventqueue.cpp:400
WORK_QUEUE_ITEM m_EventWorkQueueItem
static WORKER_THREAD_ROUTINE _WorkerThreadRoutine
FxThreadedEventQueue(__in UCHAR QueueDepth)
Definition: eventqueue.cpp:352
FxWorkItemEventQueue(__in UCHAR QueueDepth)
Definition: eventqueue.cpp:308
_Must_inspect_result_ NTSTATUS Init(__inout FxPkgPnp *Pnp, __in PFN_PNP_EVENT_WORKER WorkerRoutine, __in PVOID WorkerContext=NULL)
Definition: eventqueue.cpp:321
Definition: ps.c:97
PVOID GetIoMgrObjectForWorkItemAllocation(VOID)
Definition: supportum.cpp:98
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:127
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
WORKER_THREAD_ROUTINE * PWORKER_THREAD_ROUTINE
Definition: extypes.h:200
unsigned char UCHAR
Definition: xmlstorage.h:181