1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxIrpQueue.hpp 8 9 Abstract: 10 11 This module implements a common queue structure for the 12 driver frameworks built around the Cancel Safe Queues pattern 13 14 Author: 15 16 17 18 19 20 21 Environment: 22 23 Both kernel and user mode 24 25 Revision History: 26 27 28 --*/ 29 30 #ifndef _FXIRPQUEUE_H_ 31 #define _FXIRPQUEUE_H_ 32 33 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 34 #include "fxirpkm.hpp" 35 #else 36 #include "fxirpum.hpp" 37 #endif 38 39 40 // 41 // IRP DriverContext[] entry used. 42 // 43 // We use the same entry that the CSQ package does 44 // which is OK since we can't use CSQ if we implement the 45 // cancel handler ourselves 46 // 47 #define FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY 3 48 49 // 50 // FxIrpQueue entry identifier 51 // 52 #define FX_IRP_QUEUE_ENTRY_IDENTIFIER 1 53 54 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) 55 #include "fxirpkm.hpp" 56 #elif ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) 57 #include "fxirpum.hpp" 58 #endif 59 60 61 // 62 // This is the cancel function callback for the IrpQueue to its caller/parent 63 // This is called holding the lock of the object owning the IrpQueue, and it 64 // is responsible for completing the IRP. 65 // 66 67 extern "C" { 68 __drv_functionClass(EVT_IRP_QUEUE_CANCEL) 69 __drv_requiresIRQL(DISPATCH_LEVEL) 70 typedef 71 VOID 72 EVT_IRP_QUEUE_CANCEL ( 73 __in FxIrpQueue* Queue, 74 __in MdIrp Irp, 75 __in PMdIoCsqIrpContext pCsqContext, 76 __in KIRQL CallerIrql 77 ); 78 79 typedef EVT_IRP_QUEUE_CANCEL *PFN_IRP_QUEUE_CANCEL; 80 } 81 82 class FxIrpQueue { 83 84 friend VOID GetTriageInfo(VOID); 85 86 private: 87 88 // 89 // The Queue 90 // 91 LIST_ENTRY m_Queue; 92 93 // 94 // The object whose lock controls the queue. 95 // Provided by the client object. 96 // 97 FxNonPagedObject* m_LockObject; 98 99 // 100 // Callers registered cancel callback 101 // 102 PFN_IRP_QUEUE_CANCEL m_CancelCallback; 103 104 // 105 // Count of requests in the Queue 106 // 107 LONG m_RequestCount; 108 109 public: 110 111 FxIrpQueue( 112 VOID 113 ); 114 115 ~FxIrpQueue( 116 VOID 117 ); 118 119 VOID 120 Initialize( 121 __in FxNonPagedObject* LockObject, 122 __in PFN_IRP_QUEUE_CANCEL Callback 123 ); 124 125 _Must_inspect_result_ 126 NTSTATUS 127 InsertTailRequest( 128 __inout MdIrp Irp, 129 __in_opt PMdIoCsqIrpContext CsqContext, 130 __out_opt ULONG* pRequestCount 131 ); 132 133 _Must_inspect_result_ 134 NTSTATUS 135 InsertHeadRequest( 136 __inout MdIrp Irp, 137 __in_opt PMdIoCsqIrpContext CsqContext, 138 __out_opt ULONG* pRequestCount 139 ); 140 141 MdIrp 142 GetNextRequest( 143 __out PMdIoCsqIrpContext* pCsqContext 144 ); 145 146 _Must_inspect_result_ 147 NTSTATUS 148 GetNextRequest( 149 __in_opt PMdIoCsqIrpContext TagContext, 150 __in_opt MdFileObject FileObject, 151 __out FxRequest** ppOutRequest 152 ); 153 154 _Must_inspect_result_ 155 NTSTATUS 156 PeekRequest( 157 __in_opt PMdIoCsqIrpContext TagContext, 158 __in_opt MdFileObject FileObject, 159 __out FxRequest** ppOutRequest 160 ); 161 162 MdIrp 163 RemoveRequest( 164 __in PMdIoCsqIrpContext Context 165 ); 166 167 // 168 // Return whether the queue is empty 169 // (for optimizing the non-pending case in the caller) 170 // 171 inline 172 BOOLEAN IsQueueEmpty()173 IsQueueEmpty() { 174 175 if( IsListEmpty(&m_Queue) ) { 176 177 ASSERT(m_RequestCount == 0); 178 179 return TRUE; 180 } 181 else { 182 ASSERT(m_RequestCount != 0); 183 184 return FALSE; 185 } 186 } 187 188 // 189 // Return count of queued and driver pending requests. 190 // 191 inline 192 LONG GetRequestCount()193 GetRequestCount() { 194 return m_RequestCount; 195 } 196 197 BOOLEAN 198 IsIrpInQueue( 199 __in PMdIoCsqIrpContext Context 200 ); 201 202 203 private: 204 205 // 206 // Insert an IRP on the cancel list 207 // 208 _Must_inspect_result_ 209 NTSTATUS 210 InsertIrpInQueue( 211 __inout MdIrp Irp, 212 __in_opt PMdIoCsqIrpContext Context, 213 __in BOOLEAN InsertInHead, 214 __out_opt ULONG* pRequestCount 215 ); 216 217 // Do not specify argument names 218 FX_DECLARE_VF_FUNCTION_P1( 219 VOID, 220 VerifyRemoveIrpFromQueueByContext, 221 __in PMdIoCsqIrpContext 222 ); 223 224 // 225 // Ask to remove an IRP from the cancel list by Context, 226 // and return NULL if its been cancelled 227 // 228 MdIrp 229 RemoveIrpFromQueueByContext( 230 __in PMdIoCsqIrpContext Context 231 ); 232 233 // 234 // Remove a request from the head of the queue if PeekContext == NULL, 235 // or the next request after PeekContext if != NULL 236 // 237 MdIrp 238 RemoveNextIrpFromQueue( 239 __in_opt PVOID PeekContext, 240 __out_opt PMdIoCsqIrpContext* pCsqContext 241 ); 242 243 // 244 // Peek an IRP in the queue 245 // 246 MdIrp 247 PeekNextIrpFromQueue( 248 __in_opt MdIrp Irp, 249 __in_opt PVOID PeekContext 250 ); 251 252 // 253 // Unconditionally remove the IRP from the list entry 254 // 255 inline 256 VOID RemoveIrpFromListEntry(__inout FxIrp * Irp)257 RemoveIrpFromListEntry( 258 __inout FxIrp* Irp 259 ) 260 { 261 PLIST_ENTRY entry = Irp->ListEntry(); 262 RemoveEntryList(entry); 263 InitializeListHead(entry); 264 m_RequestCount--; 265 ASSERT(m_RequestCount >= 0); 266 } 267 268 // 269 // WDM IRP cancel function 270 // 271 static 272 MdCancelRoutineType 273 _WdmCancelRoutineInternal; 274 275 // 276 // Lock functions accessed from WDM cancel callback 277 // 278 __inline 279 void LockFromCancel(__out PKIRQL PreviousIrql)280 LockFromCancel( 281 __out PKIRQL PreviousIrql 282 ) 283 { 284 m_LockObject->Lock(PreviousIrql); 285 } 286 287 __inline 288 void UnlockFromCancel(__in KIRQL PreviousIrql)289 UnlockFromCancel( 290 __in KIRQL PreviousIrql 291 ) 292 { 293 m_LockObject->Unlock(PreviousIrql); 294 } 295 }; 296 297 #endif // _FXIRPQUEUE_H 298