ReactOS  0.4.15-dev-2700-g4b4ffa9
mxworkitemum.h
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 ModuleName:
6 
7  MxWorkItemUm.h
8 
9 Abstract:
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 
36 Author:
37 
38 
39 
40 Revision History:
41 
42 
43 
44 
45 
46 
47 --*/
48 
49 #pragma once
50 
51 typedef
52 VOID
56  );
57 
59 
60 typedef 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  //
80 } UmWorkItem;
81 
83 
84 #include "MxWorkItem.h"
85 
86 __inline
88  )
89 {
90  m_WorkItem = NULL;
91 }
92 
94 __inline
98  __in_opt PVOID ThreadPoolEnv
99  )
100 {
101  DWORD err = 0;
102 
104  GetProcessHeap(),
105  0,
106  sizeof(UmWorkItem)
107  );
108 
109  if (NULL == m_WorkItem) {
111  }
112 
113  ZeroMemory(m_WorkItem, sizeof(UmWorkItem));
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(
127  _WorkerThunk,
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 
141 exit:
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 
152  m_WorkItem = NULL;
153  }
154 
155  return NTSTATUS_FROM_WIN32(err);
156 }
157 
158 __inline
159 VOID
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
207 VOID
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 
256  ::HeapFree(
257  GetProcessHeap(),
258  0,
259  Item
260  );
261  }
262 }
263 
264 __inline
265 VOID
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) {
280  m_WorkItem = NULL;
281  }
282 }
283 
284 //
285 // FxAutoWorkitem
286 //
287 __inline
289  )
290 {
291  this->Free();
292 }
293 
294 
#define CreateEvent
Definition: winbase.h:3604
PVOID Context
Definition: io.h:311
static VOID CALLBACK _WorkerThunk(_Inout_ PTP_CALLBACK_INSTANCE Instance, _Inout_opt_ PVOID Parameter, _Inout_ PTP_WAIT Wait, _In_ TP_WAIT_RESULT WaitResult)
#define _Must_inspect_result_
Definition: no_sal2.h:62
#define CloseHandle
Definition: compat.h:598
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
PMX_WORKITEM_ROUTINE Callback
Definition: mxworkitemum.h:70
__inline MdWorkItem GetWorkItem()
Definition: mxworkitemkm.h:73
#define __in_opt
Definition: dbghelp.h:38
LONG NTSTATUS
Definition: precomp.h:26
HANDLE WorkItemEvent
Definition: mxworkitemum.h:68
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1040
#define ZeroMemory
Definition: winbase.h:1664
IO_WORKITEM_ROUTINE MX_WORKITEM_ROUTINE
Definition: mxworkitemkm.h:26
MdWorkItem m_WorkItem
Definition: mxworkitem.h:32
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define FALSE
Definition: types.h:117
PDEVICE_OBJECT DeviceObject
Definition: io.h:309
VOID MX_WORKITEM_ROUTINE(__in MdDeviceObject DeviceObject, __in_opt PVOID Context)
Definition: mxworkitemum.h:53
unsigned char BOOLEAN
BOOLEAN DefaultThreadpoolEnv
Definition: mxworkitemum.h:79
PVOID Context
Definition: mxworkitemum.h:72
_Must_inspect_result_ __inline NTSTATUS Allocate(__in MdDeviceObject DeviceObject, __in_opt PVOID ThreadPoolEnv=NULL)
Definition: mxworkitemkm.h:41
#define GetProcessHeap()
Definition: compat.h:595
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
unsigned long DWORD
Definition: ntddk_ex.h:95
__inline ~MxAutoWorkItem()
Definition: mxworkitemkm.h:103
__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
PTP_WAIT WaitBlock
Definition: mxworkitemum.h:66
#define err(...)
_In_ WDFINTERRUPT _In_ PFN_WDF_INTERRUPT_SYNCHRONIZE Callback
Definition: wdfinterrupt.h:456
MdDeviceObject DeviceObject
Definition: mxworkitemum.h:61
#define NULL
Definition: types.h:112
__inline VOID Free()
Definition: mxworkitemkm.h:90
_In_ WDFCOLLECTION _In_ WDFOBJECT Item
IO_WORKITEM_ROUTINE * PMX_WORKITEM_ROUTINE
Definition: mxworkitemkm.h:26
struct tagContext Context
Definition: acpixf.h:1034
UmWorkItem * MdWorkItem
Definition: mxworkitemum.h:82
void exit(int exitcode)
Definition: _exit.c:33
#define __in
Definition: dbghelp.h:35
__inline MxWorkItem()
Definition: mxworkitemkm.h:32
#define HeapFree(x, y, z)
Definition: compat.h:594
MX_WORKITEM_ROUTINE * PMX_WORKITEM_ROUTINE
Definition: mxworkitemum.h:58