/*++ Copyright (c) Microsoft Corporation Module Name: FxWaitLock.hpp Abstract: --*/ #ifndef _FXWAITLOCK_HPP_ #define _FXWAITLOCK_HPP_ struct FxCREvent { FxCREvent( __in BOOLEAN InitialState = FALSE ) { // // For kernel mode letting c'tor do the initialization to not churn the // non-shared code // #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) m_Event.Initialize(SynchronizationEvent, InitialState); #else UNREFERENCED_PARAMETER(InitialState); #endif } FxCREvent( __in EVENT_TYPE Type, __in BOOLEAN InitialState ) { #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) m_Event.Initialize(Type, InitialState); #else UNREFERENCED_PARAMETER(Type); UNREFERENCED_PARAMETER(InitialState); #endif } CHECK_RETURN_IF_USER_MODE NTSTATUS Initialize( __in BOOLEAN InitialState = FALSE ) { return m_Event.Initialize(SynchronizationEvent, InitialState); } CHECK_RETURN_IF_USER_MODE NTSTATUS Initialize( __in EVENT_TYPE Type, __in BOOLEAN InitialState ) { return m_Event.Initialize(Type, InitialState); } __drv_valueIs(==0;==258) _Acquires_lock_(_Global_critical_region_) NTSTATUS EnterCRAndWait( VOID ) { NTSTATUS status; Mx::MxEnterCriticalRegion(); status = m_Event.WaitFor(Executive, KernelMode, FALSE, NULL); return status; } NTSTATUS EnterCRAndWaitAndLeave( VOID ) { NTSTATUS status; status = EnterCRAndWait(); LeaveCR(); return status; } __drv_when(Timeout == NULL, __drv_valueIs(==0)) __drv_when(Timeout != NULL, __drv_valueIs(==0;==258)) __drv_when(Timeout != NULL, _Must_inspect_result_) _Acquires_lock_(_Global_critical_region_) NTSTATUS EnterCRAndWait( __in PLONGLONG Timeout ) { NTSTATUS status; Mx::MxEnterCriticalRegion(); status = m_Event.WaitFor(Executive, KernelMode, FALSE, (PLARGE_INTEGER) Timeout); return status; } _Must_inspect_result_ NTSTATUS EnterCRAndWaitAndLeave( __in PLONGLONG Timeout ) { NTSTATUS status; status = EnterCRAndWait(Timeout); LeaveCR(); return status; } _Releases_lock_(_Global_critical_region_) VOID LeaveCR( VOID ) { Mx::MxLeaveCriticalRegion(); } VOID Set( VOID ) { m_Event.Set(); } VOID Clear( VOID ) { m_Event.Clear(); } LONG ReadState( VOID ) { return m_Event.ReadState(); } // // Return the underlying event // PKEVENT in kernel mode and event HANDLE in user-mode // PVOID GetEvent( VOID ) { return m_Event.GetEvent(); } FxCREvent* GetSelfPointer( VOID ) { // // Since operator& is hidden, we still need to be able to get a pointer // to this object, so we must make it an explicit method. // return this; } private: FxCREvent* operator&( VOID ) { // // By making the address of operator private, we make it harder (hopefully // impossible) to accidentally use this object in an improper fashion, ie // something like this is prevented: // // FxCREvent event; // KeWaitForSingleObject(&event, ...); // ASSERT(FALSE); return NULL; } private: MxEvent m_Event; }; // // Non referencable object, just pure implementation // class FxWaitLockInternal { public: FxWaitLockInternal( VOID ) { // // For kernel mode letting c'tor do the initialization to not churn the // non-shared code // #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) m_Event.Initialize(SynchronizationEvent, TRUE); #endif m_OwningThread = NULL; } CHECK_RETURN_IF_USER_MODE NTSTATUS Initialize( ) { return m_Event.Initialize(SynchronizationEvent, TRUE); } // // __drv_when(Timeout == NULL, __drv_valueIs(==0)) __drv_when(Timeout != NULL, __drv_valueIs(==0;==258)) __drv_when(Timeout != NULL, _Must_inspect_result_) _When_(return!=0x00000102L, _Acquires_lock_(_Global_critical_region_)) NTSTATUS AcquireLock( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in_opt PLONGLONG Timeout = NULL ) { LARGE_INTEGER li; NTSTATUS status; UNREFERENCED_PARAMETER(FxDriverGlobals); ASSERT(m_OwningThread != Mx::MxGetCurrentThread() || (Timeout != NULL)); if (Timeout != NULL) { li.QuadPart = *Timeout; } Mx::MxEnterCriticalRegion(); status = m_Event.WaitFor(Executive, KernelMode, FALSE, Timeout == NULL ? NULL : &li); if (status == STATUS_TIMEOUT) { Mx::MxLeaveCriticalRegion(); } else { m_OwningThread = Mx::MxGetCurrentThread(); } return status; } static BOOLEAN IsLockAcquired( __in NTSTATUS Status ) { // // STATUS_TIMEOUT will return TRUE for NT_SUCCESS so check explicitly // return (NT_SUCCESS(Status) && Status != STATUS_TIMEOUT) ? TRUE : FALSE; } _Releases_lock_(_Global_critical_region_) VOID ReleaseLock( __in PFX_DRIVER_GLOBALS FxDriverGlobals ) { UNREFERENCED_PARAMETER(FxDriverGlobals); ASSERT(m_OwningThread == Mx::MxGetCurrentThread()); m_OwningThread = NULL; m_Event.Set(); Mx::MxLeaveCriticalRegion(); } protected: MxEvent m_Event; MxThread m_OwningThread; }; // // Order is important here, FxObject *must* be the first class in the // list so that &FxWaitWaitLock == &FxNonPagedObject. // class FxWaitLock : public FxObject, public FxWaitLockInternal { public: // Factory function _Must_inspect_result_ static NTSTATUS _Create( __in PFX_DRIVER_GLOBALS DriverGlobals, __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, __in_opt FxObject* ParentObject, __in BOOLEAN AssignDriverAsDefaultParent, __out WDFWAITLOCK* LockHandle ); CHECK_RETURN_IF_USER_MODE NTSTATUS Initialize( ) { return __super::Initialize(); } FxWaitLock( __in PFX_DRIVER_GLOBALS FxDriverGlobals ) : FxObject(FX_TYPE_WAIT_LOCK, sizeof(FxWaitLock), FxDriverGlobals) { } }; #endif // _FXWAITLOCK_HPP_