1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxSystemThread.hpp
8 
9 Abstract:
10 
11     This class provides the safe handling for system threads
12     in the driver frameworks.
13 
14 
15 Author:
16 
17 
18 
19 
20 Revision History:
21 
22 --*/
23 
24 #ifndef _FXSYSTEMTHREAD_H_
25 #define _FXSYSTEMTHREAD_H_
26 
27 class FxSystemThread : public FxNonPagedObject {
28 
29 private:
30 
31     MxEvent m_InitEvent;
32     MxEvent m_WorkEvent;
33 
34     LIST_ENTRY m_WorkList;
35 
36     PVOID m_ThreadPtr;
37 
38     MdEThread m_PEThread;
39 
40     // Used for Async thread spinup and reaping
41     //WORK_QUEUE_ITEM m_Spinup; // Async-Thread-Spinup
42     WORK_QUEUE_ITEM m_Reaper;
43 
44     BOOLEAN m_Exit;
45     BOOLEAN m_Initialized;
46 
47     FxSystemThread(
48         __in PFX_DRIVER_GLOBALS FxDriverGlobals
49         );
50 
51     //
52     // Create the system thread in order to be able to service work items
53     //
54     // It is recommended this is done from the system process context
55     // since the thread's handle is available to the user mode process
56     // for a temporary window. XP and later supports OBJ_KERNELHANDLE, but
57     // DriverFrameworks must support W2K with the same binary.
58     //
59     // It is safe to call this at DriverEntry which is in the system process
60     // to create an initial driver thread, and this driver thread should be
61     // used for creating any child driver threads on demand by using
62     // Initialize(FxSystemThread* SpinupThread).
63     //
64     BOOLEAN
65     Initialize(
66         VOID
67         );
68 
69 public:
70 
71     _Must_inspect_result_
72     static
73     NTSTATUS
74     _CreateAndInit(
75         __deref_out FxSystemThread** SystemThread,
76         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
77         __in WDFDEVICE Device,
78         __in MdDeviceObject DeviceObject
79         );
80 
81     virtual
82     ~FxSystemThread(
83         VOID
84         );
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
102 
103 
104 
105 
106     //
107     // This is called to tell the thread to exit.
108     //
109     // It must be called from thread context such as
110     // the driver unload routine since it will wait for the
111     // thread to exit.
112     //
113     // A worker thread will not exit unless it has processed
114     // all of its queued work items. If processing of queued
115     // workitems is no longer desired, then use CancelWorkItem
116     // to remove the items before calling this method.
117     //
118     BOOLEAN
119     ExitThread(
120         VOID
121         );
122 
123     //
124     // This is called to tell the thread to exit.
125     //
126     // This may be called from any context since it
127     // only signals the thread to exit, and does not
128     // wait for it. It is safe to release the object
129     // reference when this routine returns.
130     //
131     // This routine requires an FxSystemThread* to perform
132     // final thread reaping. This allows a driver to ensure that
133     // child threads have exited by waiting on their object pointer,
134     // before exiting a top level driver thread.
135     //
136     // This is required since a frameworks object that contains a
137     // system thread can be dereferenced, and thus destroyed
138     // in any context, so waiting may not be available. But unless
139     // a wait is done on the thread object pointer, no guarantee can be
140     // made that the thread has actually run and exited before
141     // the drivers code get unloaded, resulting in a system crash.
142     //
143     // Top level threads, such as the reaper, are exited using the
144     // ExitThread() synchronous call that waits for it to exit. This
145     // can be done in synchronous thread context such as DriverUnload
146     // time.
147     //
148     // If Synchronous threading is configured in the frameworks, the
149     // FxDriver object always contains a top level worker thread that
150     // may be used as the reaper, and DriverUnload synchronously waits
151     // for this thread to finish processing its work queue before
152     // exiting.
153     //
154     // A worker thread will not exit unless it has processed
155     // all of its queued work items. If processing of queued
156     // workitems is no longer desired, then use CancelWorkItem
157     // to remove the items before calling this method.
158     //
159     BOOLEAN
160     ExitThreadAsync(
161         __inout FxSystemThread* Reaper
162         );
163 
164     //
165     // Queue a work item to the thread
166     //
167     // It is valid to queue work items before thread
168     // Initialize()/Initialize(FxSystemThread*) is called. The items
169     // remain queued until the system thread is started.
170     //
171     BOOLEAN
172     QueueWorkItem(
173         __inout PWORK_QUEUE_ITEM WorkItem
174         );
175 
176     //
177     // Attempt to cancel the work item.
178     //
179     // Returns TRUE if success.
180     //
181     // If returns FALSE, the work item
182     // routine either has been called, is running,
183     // or is about to be called.
184     //
185     BOOLEAN
186     CancelWorkItem(
187         __inout PWORK_QUEUE_ITEM WorkItem
188         );
189 
190     //
191     // Determine if current thread is this
192     // worker thread
193     //
194     __inline
195     BOOLEAN
196     IsCurrentThread()
197     {
198         return (Mx::GetCurrentEThread() == m_PEThread) ? TRUE : FALSE;
199     }
200 
201     DECLARE_INTERNAL_NEW_OPERATOR();
202 
203 #ifdef INLINE_WRAPPER_ALLOCATION
204 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
205     FORCEINLINE
206     PVOID
207     GetCOMWrapper(
208         )
209     {
210         PBYTE ptr = (PBYTE) this;
211         return (ptr + (USHORT) WDF_ALIGN_SIZE_UP(sizeof(*this), MEMORY_ALLOCATION_ALIGNMENT));
212     }
213 #endif
214 #endif
215 
216 private:
217 
218     //
219     // This is the thread's main processing function
220     //
221     VOID
222     Thread(
223         VOID
224         );
225 
226 
227 
228 
229 
230 
231 
232 
233 
234 
235 
236 
237 
238 
239     //
240     // This is the reaper method
241     //
242     VOID
243     Reaper(
244         VOID
245         );
246 
247     _Must_inspect_result_
248     NTSTATUS
249     CreateThread(
250         VOID
251         );
252 
253     //
254     // This is the thunk used to get from the system
255     // thread start callback into this class
256     //
257     static
258     VOID
259     STDCALL
260     StaticThreadThunk(
261         __inout PVOID Context
262         );
263 
264 
265 
266 
267 
268 
269 
270 
271 
272 
273 
274 
275 
276 
277 
278 
279     //
280     // This thunk is called from the workitem in another
281     // thread that is reaping this thread
282     //
283     static
284     VOID
285     STDCALL
286     StaticReaperThunk(
287         __inout PVOID Context
288         );
289 };
290 
291 #endif // _FXSYSTEMTHREAD_H_
292