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