1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxWaitLock.hpp 8 9 Abstract: 10 11 --*/ 12 13 #ifndef _FXWAITLOCK_HPP_ 14 #define _FXWAITLOCK_HPP_ 15 16 struct FxCREvent { 17 FxCREvent( 18 __in BOOLEAN InitialState = FALSE 19 ) 20 { 21 // 22 // For kernel mode letting c'tor do the initialization to not churn the 23 // non-shared code 24 // 25 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 26 m_Event.Initialize(SynchronizationEvent, InitialState); 27 #else 28 UNREFERENCED_PARAMETER(InitialState); 29 #endif 30 } 31 32 33 34 35 36 FxCREvent( 37 __in EVENT_TYPE Type, 38 __in BOOLEAN InitialState 39 ) 40 { 41 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 42 m_Event.Initialize(Type, InitialState); 43 #else 44 UNREFERENCED_PARAMETER(Type); 45 UNREFERENCED_PARAMETER(InitialState); 46 #endif 47 } 48 49 CHECK_RETURN_IF_USER_MODE 50 NTSTATUS 51 Initialize( 52 __in BOOLEAN InitialState = FALSE 53 ) 54 { 55 return m_Event.Initialize(SynchronizationEvent, InitialState); 56 } 57 58 CHECK_RETURN_IF_USER_MODE 59 NTSTATUS 60 Initialize( 61 __in EVENT_TYPE Type, 62 __in BOOLEAN InitialState 63 ) 64 { 65 return m_Event.Initialize(Type, InitialState); 66 } 67 68 __drv_valueIs(==0;==258) 69 _Acquires_lock_(_Global_critical_region_) 70 NTSTATUS 71 EnterCRAndWait( 72 VOID 73 ) 74 { 75 NTSTATUS status; 76 77 Mx::MxEnterCriticalRegion(); 78 79 status = m_Event.WaitFor(Executive, 80 KernelMode, 81 FALSE, 82 NULL); 83 return status; 84 } 85 86 NTSTATUS 87 EnterCRAndWaitAndLeave( 88 VOID 89 ) 90 { 91 NTSTATUS status; 92 93 status = EnterCRAndWait(); 94 LeaveCR(); 95 96 return status; 97 } 98 99 __drv_when(Timeout == NULL, __drv_valueIs(==0)) 100 __drv_when(Timeout != NULL, __drv_valueIs(==0;==258)) 101 __drv_when(Timeout != NULL, _Must_inspect_result_) 102 _Acquires_lock_(_Global_critical_region_) 103 NTSTATUS 104 EnterCRAndWait( 105 __in PLONGLONG Timeout 106 ) 107 { 108 NTSTATUS status; 109 110 Mx::MxEnterCriticalRegion(); 111 112 status = m_Event.WaitFor(Executive, 113 KernelMode, 114 FALSE, 115 (PLARGE_INTEGER) Timeout); 116 117 return status; 118 } 119 120 _Must_inspect_result_ 121 NTSTATUS 122 EnterCRAndWaitAndLeave( 123 __in PLONGLONG Timeout 124 ) 125 { 126 NTSTATUS status; 127 128 status = EnterCRAndWait(Timeout); 129 LeaveCR(); 130 131 return status; 132 } 133 134 _Releases_lock_(_Global_critical_region_) 135 VOID 136 LeaveCR( 137 VOID 138 ) 139 { 140 Mx::MxLeaveCriticalRegion(); 141 } 142 143 VOID 144 Set( 145 VOID 146 ) 147 { 148 m_Event.Set(); 149 } 150 151 VOID 152 Clear( 153 VOID 154 ) 155 { 156 m_Event.Clear(); 157 } 158 159 LONG 160 ReadState( 161 VOID 162 ) 163 { 164 return m_Event.ReadState(); 165 } 166 167 // 168 // Return the underlying event 169 // PKEVENT in kernel mode and event HANDLE in user-mode 170 // 171 PVOID 172 GetEvent( 173 VOID 174 ) 175 { 176 return m_Event.GetEvent(); 177 } 178 179 FxCREvent* 180 GetSelfPointer( 181 VOID 182 ) 183 { 184 // 185 // Since operator& is hidden, we still need to be able to get a pointer 186 // to this object, so we must make it an explicit method. 187 // 188 return this; 189 } 190 private: 191 FxCREvent* operator&( 192 VOID 193 ) 194 { 195 // 196 // By making the address of operator private, we make it harder (hopefully 197 // impossible) to accidentally use this object in an improper fashion, ie 198 // something like this is prevented: 199 // 200 // FxCREvent event; 201 // KeWaitForSingleObject(&event, ...); 202 // 203 ASSERT(FALSE); 204 return NULL; 205 } 206 207 private: 208 MxEvent m_Event; 209 }; 210 211 // 212 // Non referencable object, just pure implementation 213 // 214 class FxWaitLockInternal { 215 216 public: 217 218 FxWaitLockInternal( 219 VOID 220 ) 221 { 222 // 223 // For kernel mode letting c'tor do the initialization to not churn the 224 // non-shared code 225 // 226 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 227 m_Event.Initialize(SynchronizationEvent, TRUE); 228 #endif 229 230 m_OwningThread = NULL; 231 } 232 233 CHECK_RETURN_IF_USER_MODE 234 NTSTATUS 235 Initialize( 236 ) 237 { 238 return m_Event.Initialize(SynchronizationEvent, TRUE); 239 } 240 241 // 242 243 // 244 __drv_when(Timeout == NULL, __drv_valueIs(==0)) 245 __drv_when(Timeout != NULL, __drv_valueIs(==0;==258)) 246 __drv_when(Timeout != NULL, _Must_inspect_result_) 247 _When_(return!=0x00000102L, _Acquires_lock_(_Global_critical_region_)) 248 NTSTATUS 249 AcquireLock( 250 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 251 __in_opt PLONGLONG Timeout = NULL 252 ) 253 { 254 LARGE_INTEGER li; 255 NTSTATUS status; 256 257 UNREFERENCED_PARAMETER(FxDriverGlobals); 258 259 ASSERT(m_OwningThread != Mx::MxGetCurrentThread() || (Timeout != NULL)); 260 261 if (Timeout != NULL) { 262 li.QuadPart = *Timeout; 263 } 264 265 Mx::MxEnterCriticalRegion(); 266 status = m_Event.WaitFor(Executive, 267 KernelMode, 268 FALSE, 269 Timeout == NULL ? NULL : &li); 270 271 if (status == STATUS_TIMEOUT) { 272 Mx::MxLeaveCriticalRegion(); 273 } 274 else { 275 m_OwningThread = Mx::MxGetCurrentThread(); 276 } 277 278 return status; 279 } 280 281 static 282 BOOLEAN 283 IsLockAcquired( 284 __in NTSTATUS Status 285 ) 286 { 287 // 288 // STATUS_TIMEOUT will return TRUE for NT_SUCCESS so check explicitly 289 // 290 return (NT_SUCCESS(Status) && Status != STATUS_TIMEOUT) ? TRUE : FALSE; 291 } 292 293 _Releases_lock_(_Global_critical_region_) 294 VOID 295 ReleaseLock( 296 __in PFX_DRIVER_GLOBALS FxDriverGlobals 297 ) 298 { 299 UNREFERENCED_PARAMETER(FxDriverGlobals); 300 301 ASSERT(m_OwningThread == Mx::MxGetCurrentThread()); 302 m_OwningThread = NULL; 303 304 m_Event.Set(); 305 Mx::MxLeaveCriticalRegion(); 306 } 307 308 protected: 309 MxEvent m_Event; 310 311 MxThread m_OwningThread; 312 }; 313 314 315 // 316 // Order is important here, FxObject *must* be the first class in the 317 // list so that &FxWaitWaitLock == &FxNonPagedObject. 318 // 319 class FxWaitLock : public FxObject, public FxWaitLockInternal { 320 321 public: 322 // Factory function 323 _Must_inspect_result_ 324 static 325 NTSTATUS 326 _Create( 327 __in PFX_DRIVER_GLOBALS DriverGlobals, 328 __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, 329 __in_opt FxObject* ParentObject, 330 __in BOOLEAN AssignDriverAsDefaultParent, 331 __out WDFWAITLOCK* LockHandle 332 ); 333 334 335 CHECK_RETURN_IF_USER_MODE 336 NTSTATUS 337 Initialize( 338 ) 339 { 340 return FxWaitLockInternal::Initialize(); // __super call 341 } 342 343 FxWaitLock( 344 __in PFX_DRIVER_GLOBALS FxDriverGlobals 345 ) : 346 FxObject(FX_TYPE_WAIT_LOCK, sizeof(FxWaitLock), FxDriverGlobals) 347 { 348 } 349 }; 350 351 #endif // _FXWAITLOCK_HPP_ 352