ReactOS 0.4.16-dev-401-g45b008d
mxworkitemum.h
Go to the documentation of this file.
1/*++
2
3Copyright (c) Microsoft Corporation
4
5ModuleName:
6
7 MxWorkItemUm.h
8
9Abstract:
10
11 User mode implementation of work item
12 class defined in MxWorkItem.h
13
14 ***********PLEASE NOTE*****************************
15 A significant difference from kernel mode implementation of work item
16 is that user mode version of MxWorkItem::_Free synchronously waits for
17 callback to return.
18
19 This implies that _Free cannot be invoked from within the callback otherwise
20 it would lead to a deadlock.
21
22 PLEASE NOTE that _Free cannot be made to return without waiting without
23 significant changes.
24
25 If Free is not made to wait synchronously there is a potential for binary
26 unload while workitem is running - even with waiting for an event/reference
27 count etc., the tail instructions may be running.
28 The only way to resolve that is to move work-item code out of framework
29 binary and into the host so that host can take a reference on framework
30 binary around the work item callback invocation (similar to the way I/O
31 manager keeps a reference on the device object around the invocation of
32
33 workitem callback).
34 ****************************************************
35
36Author:
37
38
39
40Revision History:
41
42
43
44
45
46
47--*/
48
49#pragma once
50
51typedef
52VOID
56 );
57
59
60typedef struct {
62
63 //
64 // threadpool wait block
65 //
66 PTP_WAIT WaitBlock;
67
69
71
73
74 //
75 // True if callbacks run in the default thread pool environment,
76 // rather than in an environment explicitly owned by the driver.
77 // This has implications in MxWorkItem::_Free.
78 //
81
83
84#include "MxWorkItem.h"
85
86__inline
88 )
89{
91}
92
94__inline
98 __in_opt PVOID ThreadPoolEnv
99 )
100{
101 DWORD err = 0;
102
105 0,
106 sizeof(UmWorkItem)
107 );
108
109 if (NULL == m_WorkItem) {
111 }
112
114
115 m_WorkItem->WorkItemEvent = CreateEvent(
116 NULL,
117 FALSE,
118 FALSE,
119 NULL);
120
121 if (NULL == m_WorkItem->WorkItemEvent) {
122 err = GetLastError();
123 goto exit;
124 }
125
126 m_WorkItem->WaitBlock = CreateThreadpoolWait(
128 this->GetWorkItem(), // Context to callback function
129 (PTP_CALLBACK_ENVIRON)ThreadPoolEnv
130 );
131
132 if (m_WorkItem->WaitBlock == NULL) {
133 err = GetLastError();
134 goto exit;
135 }
136
137 m_WorkItem->DefaultThreadpoolEnv = (NULL == ThreadPoolEnv);
138
140
141exit:
142 //
143 // Cleanup in case of failure
144 //
145 if (0 != err) {
146 if (NULL != m_WorkItem->WorkItemEvent) {
147 CloseHandle(m_WorkItem->WorkItemEvent);
148 m_WorkItem->WorkItemEvent = NULL;
149 }
150
153 }
154
155 return NTSTATUS_FROM_WIN32(err);
156}
157
158__inline
159VOID
163 )
164{
165 //
166 // ASSUMPTION: This function assumes that another call to Enqueue
167 // is made only after the callback has been invoked, altough it is OK
168 // to make another call from within the callback.
169 //
170 // It is up to a higher layer/caller to ensure this.
171 // For example: FxSystemWorkItem layered on top of MxWorkItem ensures this.
172 //
173
174 //
175 // Since multiple calls to Enqueue cannot be made at the same time
176 // as explained above, it is OK to store callback and context in
177 // the workitem itself.
178 //
179 // This behavior is similar to that of IoQueueWorkItem which accepts
180 // a callback and a context which are stored within the work-item.
181 //
182
183 m_WorkItem->Callback = Callback;
185
186 //
187 // We must register the event with the wait object before signaling it
188 // to trigger the wait callback.
189 //
190 SetThreadpoolWait(m_WorkItem->WaitBlock,
191 m_WorkItem->WorkItemEvent,
192 NULL // timeout
193 );
194
195 SetEvent(m_WorkItem->WorkItemEvent);
196}
197
198__inline
201 )
202{
203 return m_WorkItem;
204}
205
206__inline
207VOID
210 )
211{
212 //
213 // PLEASE NOTE that _Free waits for callback to return synchronously.
214 //
215 // DO NOT call _Free from work item callback otherwise it would cause a
216 // deadlock.
217 //
218 // Please see comments on the top of the file.
219 //
220
221 if (NULL != Item) {
222 //
223 // Wait indefinitely for work item to complete
224 //
225 if (NULL != Item->WaitBlock) {
226 //
227 // this will prevent any new waits to be queued but callbacks
228 // already queued will still occur.
229 //
230 SetThreadpoolWait(Item->WaitBlock, NULL, NULL);
231
232 //
233 // If the callbacks ran in the default thread pool environment,
234 // wait for callbacks to finish.
235 // If they ran in an environment explicitly owned by the driver,
236 // then this wait will happen before the driver DLL is unloaded,
237 // the host takes care of this.
238 //
239 if (Item->DefaultThreadpoolEnv) {
240 WaitForThreadpoolWaitCallbacks(Item->WaitBlock,
241 FALSE // donot cancel pending waits
242 );
243 }
244
245 //
246 // Release the wait object.
247 //
248 CloseThreadpoolWait(Item->WaitBlock);
249 }
250
251 if (NULL != Item->WorkItemEvent) {
252 CloseHandle(Item->WorkItemEvent);
253 Item->WorkItemEvent = NULL;
254 }
255
258 0,
259 Item
260 );
261 }
262}
263
264__inline
265VOID
267 )
268{
269 //
270 // PLEASE NOTE that _Free waits for callback to return synchronously.
271 //
272 // DO NOT call Free from work item callback otherwise it would cause a
273 // deadlock.
274 //
275 // Please see comments on the top of the file.
276 //
277
278 if (NULL != m_WorkItem) {
281 }
282}
283
284//
285// FxAutoWorkitem
286//
287__inline
289 )
290{
291 this->Free();
292}
293
294
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
__inline MxWorkItem()
Definition: mxworkitemkm.h:32
__inline MdWorkItem GetWorkItem()
Definition: mxworkitemkm.h:73
__inline VOID Enqueue(__in PMX_WORKITEM_ROUTINE Callback, __in PVOID Context)
Definition: mxworkitemkm.h:58
static __inline VOID _Free(__in MdWorkItem Item)
Definition: mxworkitemkm.h:81
__inline VOID Free()
Definition: mxworkitemkm.h:90
MdWorkItem m_WorkItem
Definition: mxworkitem.h:32
_Must_inspect_result_ __inline NTSTATUS Allocate(__in MdDeviceObject DeviceObject, __in_opt PVOID ThreadPoolEnv=NULL)
Definition: mxworkitemkm.h:41
static VOID CALLBACK _WorkerThunk(_Inout_ PTP_CALLBACK_INSTANCE Instance, _Inout_opt_ PVOID Parameter, _Inout_ PTP_WAIT Wait, _In_ TP_WAIT_RESULT WaitResult)
#define __in
Definition: dbghelp.h:35
#define __in_opt
Definition: dbghelp.h:38
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define CloseHandle
Definition: compat.h:739
#define GetProcessHeap()
Definition: compat.h:736
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
unsigned long DWORD
Definition: ntddk_ex.h:95
IO_WORKITEM_ROUTINE * PMX_WORKITEM_ROUTINE
Definition: mxworkitemkm.h:26
PIO_WORKITEM MdWorkItem
Definition: mxworkitemkm.h:27
IO_WORKITEM_ROUTINE MX_WORKITEM_ROUTINE
Definition: mxworkitemkm.h:26
VOID MX_WORKITEM_ROUTINE(__in MdDeviceObject DeviceObject, __in_opt PVOID Context)
Definition: mxworkitemum.h:53
UmWorkItem * MdWorkItem
Definition: mxworkitemum.h:82
MX_WORKITEM_ROUTINE * PMX_WORKITEM_ROUTINE
Definition: mxworkitemum.h:58
#define _Must_inspect_result_
Definition: no_sal2.h:62
#define err(...)
#define exit(n)
Definition: config.h:202
__inline ~MxAutoWorkItem()
Definition: mxworkitemkm.h:103
PTP_WAIT WaitBlock
Definition: mxworkitemum.h:66
MdDeviceObject DeviceObject
Definition: mxworkitemum.h:61
BOOLEAN DefaultThreadpoolEnv
Definition: mxworkitemum.h:79
HANDLE WorkItemEvent
Definition: mxworkitemum.h:68
PMX_WORKITEM_ROUTINE Callback
Definition: mxworkitemum.h:70
PVOID Context
Definition: mxworkitemum.h:72
PDEVICE_OBJECT DeviceObject
Definition: io.h:313
PVOID Context
Definition: io.h:315
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFCOLLECTION _In_ WDFOBJECT Item
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_In_ WDFINTERRUPT _In_ PFN_WDF_INTERRUPT_SYNCHRONIZE Callback
Definition: wdfinterrupt.h:458
#define ZeroMemory
Definition: winbase.h:1737
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CreateEvent
Definition: winbase.h:3773