reactos/sdk/lib/drivers/wdf/shared/inc/private/common/fxwaitlock.hpp
Victor Perevertkin 1f377076d7
[WDF] Fix KMDF so it can compile with ReactOS SDK
Not all files are included, but these are necessary to compile cdrom driver.
So far it can only be statically linked with drivers, a proper
implementation requires wdfldr helper driver
2020-11-03 00:06:27 +03:00

351 lines
7 KiB
C++

/*++
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 FxWaitLockInternal::Initialize(); // __super call
}
FxWaitLock(
__in PFX_DRIVER_GLOBALS FxDriverGlobals
) :
FxObject(FX_TYPE_WAIT_LOCK, sizeof(FxWaitLock), FxDriverGlobals)
{
}
};
#endif // _FXWAITLOCK_HPP_