mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 20:35:43 +00:00
[WDF] Add Windows Driver Framework files
Takern from Microsoft GitHub repo:
d9c6040fe9
Licensed under MIT
This commit is contained in:
parent
545df81502
commit
8a978a179f
475 changed files with 285099 additions and 0 deletions
2036
sdk/lib/drivers/wdf/shared/inc/primitives/um/errtostatus.h
Normal file
2036
sdk/lib/drivers/wdf/shared/inc/primitives/um/errtostatus.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,18 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxDeviceObjectUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
User Mode implementation of Device Object defined in MxDeviceObject.h
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "MxDeviceObject.h"
|
|
@ -0,0 +1,24 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxDriverObjectUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
User Mode implementation of Driver Object defined in MxDriverObject.h
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef PDRIVER_OBJECT_UM MdDriverObject;
|
||||
typedef DRIVER_ADD_DEVICE_UM MdDriverAddDeviceType, *MdDriverAddDevice;
|
||||
typedef DRIVER_UNLOAD_UM MdDriverUnloadType, *MdDriverUnload;
|
||||
typedef DRIVER_DISPATCH_UM MdDriverDispatchType, *MdDriverDispatch;
|
||||
|
||||
#include "MxDriverObject.h"
|
||||
|
||||
|
289
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxeventum.h
Normal file
289
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxeventum.h
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxEventUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
User mode implementation of event
|
||||
class defined in MxEvent.h
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
HANDLE Event;
|
||||
#if DBG
|
||||
EVENT_TYPE Type; //tracked to allow ReadState only for notification events
|
||||
#endif
|
||||
} MdEvent;
|
||||
|
||||
#include "DbgMacros.h"
|
||||
#include "MxEvent.h"
|
||||
|
||||
__inline
|
||||
MxEvent::MxEvent()
|
||||
{
|
||||
CLEAR_DBGFLAG_INITIALIZED;
|
||||
|
||||
m_Event.Event = NULL;
|
||||
}
|
||||
|
||||
__inline
|
||||
MxEvent::~MxEvent()
|
||||
{
|
||||
//
|
||||
// PLEASE NOTE: shared code must not rely of d'tor uninitializing the
|
||||
// event. d'tor may not be invoked if the event is used in a structure
|
||||
// which is allocated/deallocated using MxPoolAllocate/Free instead of
|
||||
// new/delete
|
||||
//
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__inline
|
||||
NTSTATUS
|
||||
MxEvent::Initialize(
|
||||
__in EVENT_TYPE Type,
|
||||
__in BOOLEAN InitialState
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
HANDLE event;
|
||||
BOOL bManualReset;
|
||||
|
||||
if (NotificationEvent == Type)
|
||||
{
|
||||
bManualReset = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
bManualReset = FALSE;
|
||||
}
|
||||
|
||||
event = CreateEvent(
|
||||
NULL,
|
||||
bManualReset,
|
||||
InitialState ? TRUE : FALSE,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (NULL == event) {
|
||||
DWORD err = GetLastError();
|
||||
status = WinErrorToNtStatus(err);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
m_Event.Event = event;
|
||||
|
||||
#if DBG
|
||||
m_Event.Type = Type;
|
||||
#endif
|
||||
|
||||
SET_DBGFLAG_INITIALIZED;
|
||||
|
||||
exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
__inline
|
||||
PVOID
|
||||
MxEvent::GetEvent(
|
||||
)
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
return m_Event.Event;
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxEvent::Set(
|
||||
)
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
SetEvent(m_Event.Event);
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxEvent::SetWithIncrement(
|
||||
__in KPRIORITY Priority
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Priority);
|
||||
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
Set();
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxEvent::Clear(
|
||||
)
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
ResetEvent(m_Event.Event);
|
||||
}
|
||||
|
||||
__drv_when(Timeout != NULL, _Must_inspect_result_)
|
||||
__inline
|
||||
NTSTATUS
|
||||
MxEvent::WaitFor(
|
||||
__in KWAIT_REASON WaitReason,
|
||||
__in KPROCESSOR_MODE WaitMode,
|
||||
__in BOOLEAN Alertable,
|
||||
__in_opt PLARGE_INTEGER Timeout
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Waits for the event
|
||||
|
||||
Arguments:
|
||||
WaitReason - Unused (only there to match km definition)
|
||||
|
||||
WaitMode - Unuses (only there to match km definition)
|
||||
|
||||
Altertable - Whether the wait is alertable
|
||||
|
||||
Timout - Timeout in 100 ns units, MUST BE NEGATIVE
|
||||
(negative implies relative timeout)
|
||||
|
||||
Return Value:
|
||||
Status corresponding to return value of WaitForSingleObjectEx
|
||||
|
||||
--*/
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
DWORD retVal;
|
||||
|
||||
UNREFERENCED_PARAMETER(WaitReason);
|
||||
UNREFERENCED_PARAMETER(WaitMode);
|
||||
|
||||
LONGLONG relativeTimeOut = 0;
|
||||
LONGLONG timeoutInMs = 0;
|
||||
DWORD dwTimeout = 0;
|
||||
|
||||
if (NULL != Timeout)
|
||||
{
|
||||
//
|
||||
// Make sure that timeout is 0 or -ve (which implies relative timeout)
|
||||
//
|
||||
if (Timeout->QuadPart > 0)
|
||||
{
|
||||
Mx::MxAssertMsg(
|
||||
"Absolute wait not supported in user mode",
|
||||
FALSE
|
||||
);
|
||||
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Remove the -ve sign
|
||||
//
|
||||
if (Timeout->QuadPart < 0)
|
||||
{
|
||||
relativeTimeOut = -1 * Timeout->QuadPart;
|
||||
}
|
||||
|
||||
//
|
||||
// Convert from 100ns units to milliseconds
|
||||
//
|
||||
timeoutInMs = (relativeTimeOut / (10 * 1000));
|
||||
|
||||
if (timeoutInMs > ULONG_MAX)
|
||||
{
|
||||
Mx::MxAssertMsg("Timeout too large", FALSE);
|
||||
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwTimeout = (DWORD) timeoutInMs;
|
||||
}
|
||||
}
|
||||
|
||||
retVal = WaitForSingleObjectEx(
|
||||
m_Event.Event,
|
||||
(NULL == Timeout) ? INFINITE : dwTimeout,
|
||||
Alertable
|
||||
);
|
||||
|
||||
switch(retVal)
|
||||
{
|
||||
case WAIT_ABANDONED:
|
||||
return STATUS_ABANDONED;
|
||||
case WAIT_OBJECT_0:
|
||||
return STATUS_SUCCESS;
|
||||
case WAIT_TIMEOUT:
|
||||
return STATUS_TIMEOUT;
|
||||
case WAIT_FAILED:
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
return WinErrorToNtStatus(err);
|
||||
}
|
||||
default:
|
||||
{
|
||||
//
|
||||
// We shoudn't get here
|
||||
//
|
||||
Mx::MxAssert(FALSE);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LONG
|
||||
__inline
|
||||
MxEvent::ReadState(
|
||||
)
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
#if DBG
|
||||
Mx::MxAssert(m_Event.Type == NotificationEvent);
|
||||
#endif
|
||||
|
||||
if (WAIT_OBJECT_0 == WaitForSingleObject(
|
||||
m_Event.Event,
|
||||
0
|
||||
)) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxEvent::Uninitialize(
|
||||
)
|
||||
{
|
||||
if (NULL != m_Event.Event) {
|
||||
CloseHandle(m_Event.Event);
|
||||
m_Event.Event = NULL;
|
||||
}
|
||||
|
||||
CLEAR_DBGFLAG_INITIALIZED;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxFileObjectUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
User Mode implementation of File Object defined in MxFileObject.h
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct IWudfFile;
|
||||
|
||||
typedef IWudfFile * MdFileObject;
|
||||
|
||||
#include "MxFileObject.h"
|
||||
|
||||
__inline
|
||||
PLARGE_INTEGER
|
||||
MxFileObject::GetCurrentByteOffset(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ASSERTMSG("Not implemented for UMDF\n", FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__inline
|
||||
ULONG
|
||||
MxFileObject::GetFlags(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxFileObject::SetFsContext(
|
||||
_In_ PVOID Value
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Value);
|
||||
ASSERTMSG("Not implemented for UMDF\n", FALSE);
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxFileObject::SetFsContext2(
|
||||
_In_ PVOID Value
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Value);
|
||||
ASSERTMSG("Not implemented for UMDF\n", FALSE);
|
||||
}
|
||||
|
||||
__inline
|
||||
PVOID
|
||||
MxFileObject::GetFsContext(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ASSERTMSG("Not implemented for UMDF\n", FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__inline
|
||||
PVOID
|
||||
MxFileObject::GetFsContext2(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ASSERTMSG("Not implemented for UMDF\n", FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
1078
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxgeneralum.h
Normal file
1078
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxgeneralum.h
Normal file
File diff suppressed because it is too large
Load diff
185
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxlockum.h
Normal file
185
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxlockum.h
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxLockUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
User mode implementation of lock
|
||||
class defined in MxLock.h
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
CRITICAL_SECTION Lock;
|
||||
bool Initialized;
|
||||
DWORD OwnerThreadId;
|
||||
} MdLock;
|
||||
|
||||
#include "DbgMacros.h"
|
||||
#include "MxLock.h"
|
||||
|
||||
__inline
|
||||
MxLock::MxLock(
|
||||
)
|
||||
{
|
||||
CLEAR_DBGFLAG_INITIALIZED;
|
||||
|
||||
m_Lock.Initialized = false;
|
||||
m_Lock.OwnerThreadId = 0;
|
||||
|
||||
MxLock::Initialize();
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxLockNoDynam::Initialize(
|
||||
)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
ASSERT_DBGFLAG_NOT_INITIALIZED;
|
||||
|
||||
ret = InitializeCriticalSectionAndSpinCount(&m_Lock.Lock, 0);
|
||||
|
||||
//
|
||||
// InitializeCriticalSectionAndSpinCount always returns TRUE on Vista+
|
||||
// Assert this contract on checked builds using DBGFLAG macro.
|
||||
//
|
||||
if (ret) {
|
||||
m_Lock.Initialized = true;
|
||||
SET_DBGFLAG_INITIALIZED;
|
||||
}
|
||||
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
}
|
||||
|
||||
|
||||
__inline
|
||||
VOID
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations.");
|
||||
MxLockNoDynam::Acquire(
|
||||
__out KIRQL * OldIrql
|
||||
)
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
EnterCriticalSection(&m_Lock.Lock);
|
||||
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
|
||||
if (threadId == m_Lock.OwnerThreadId) {
|
||||
Mx::MxAssertMsg("Recursive acquision of the lock is not allowed", FALSE);
|
||||
}
|
||||
|
||||
m_Lock.OwnerThreadId = threadId;
|
||||
|
||||
*OldIrql = PASSIVE_LEVEL;
|
||||
}
|
||||
|
||||
__inline
|
||||
BOOLEAN
|
||||
MxLockNoDynam::TryToAcquire(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
BOOLEAN acquired;
|
||||
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
acquired = (BOOLEAN) TryEnterCriticalSection(&m_Lock.Lock);
|
||||
|
||||
if (acquired) {
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
|
||||
if (threadId == m_Lock.OwnerThreadId) {
|
||||
Mx::MxAssertMsg("Recursive acquision of the lock is not allowed", FALSE);
|
||||
}
|
||||
|
||||
m_Lock.OwnerThreadId = threadId;
|
||||
}
|
||||
|
||||
return acquired;
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations.");
|
||||
MxLockNoDynam::AcquireAtDpcLevel(
|
||||
)
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
KIRQL dontCare;
|
||||
|
||||
Acquire(&dontCare);
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations.");
|
||||
MxLockNoDynam::Release(
|
||||
KIRQL NewIrql
|
||||
)
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
Mx::MxAssert(NewIrql == PASSIVE_LEVEL);
|
||||
|
||||
m_Lock.OwnerThreadId = 0;
|
||||
|
||||
LeaveCriticalSection(&m_Lock.Lock);
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations.");
|
||||
MxLockNoDynam::ReleaseFromDpcLevel(
|
||||
)
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
Release(PASSIVE_LEVEL);
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxLockNoDynam::Uninitialize(
|
||||
)
|
||||
{
|
||||
ASSERT_DBGFLAG_INITIALIZED;
|
||||
|
||||
DeleteCriticalSection(&m_Lock.Lock);
|
||||
m_Lock.Initialized = false;
|
||||
|
||||
CLEAR_DBGFLAG_INITIALIZED;
|
||||
}
|
||||
|
||||
__inline
|
||||
MxLock::~MxLock(
|
||||
)
|
||||
{
|
||||
//
|
||||
// PLEASE NOTE: shared code must not rely of d'tor uninitializing the
|
||||
// lock. d'tor may not be invoked if the event is used in a structure
|
||||
// which is allocated/deallocated using MxPoolAllocate/Free instead of
|
||||
// new/delete
|
||||
//
|
||||
|
||||
if (m_Lock.Initialized) {
|
||||
this->Uninitialize();
|
||||
}
|
||||
}
|
58
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxmemoryum.h
Normal file
58
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxmemoryum.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxMemoryUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
User mode implementation of memory
|
||||
class defined in MxMemory.h
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MxMemory.h"
|
||||
|
||||
__inline
|
||||
PVOID
|
||||
MxMemory::MxAllocatePoolWithTag(
|
||||
__in POOL_TYPE PoolType,
|
||||
__in SIZE_T NumberOfBytes,
|
||||
__in ULONG Tag
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(PoolType);
|
||||
UNREFERENCED_PARAMETER(Tag);
|
||||
|
||||
return ::HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
0,
|
||||
NumberOfBytes
|
||||
);
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxMemory::MxFreePool(
|
||||
__in PVOID Ptr
|
||||
)
|
||||
{
|
||||
::HeapFree(
|
||||
GetProcessHeap(),
|
||||
0,
|
||||
Ptr
|
||||
);
|
||||
}
|
||||
|
129
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxpagedlockum.h
Normal file
129
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxpagedlockum.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxPagedLockUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
User mode implementation of paged lock defined in
|
||||
MxPagedLock.h
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
CRITICAL_SECTION Lock;
|
||||
bool Initialized;
|
||||
DWORD OwnerThreadId;
|
||||
} MdPagedLock;
|
||||
|
||||
#include "MxPagedLock.h"
|
||||
|
||||
__inline
|
||||
MxPagedLock::MxPagedLock(
|
||||
)
|
||||
{
|
||||
m_Lock.Initialized = false;
|
||||
m_Lock.OwnerThreadId = 0;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__inline
|
||||
NTSTATUS
|
||||
MxPagedLockNoDynam::Initialize(
|
||||
)
|
||||
{
|
||||
if (InitializeCriticalSectionAndSpinCount(&m_Lock.Lock, 0)) {
|
||||
m_Lock.Initialized = true;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else {
|
||||
DWORD err = GetLastError();
|
||||
return WinErrorToNtStatus(err);
|
||||
}
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations.");
|
||||
MxPagedLockNoDynam::Acquire(
|
||||
)
|
||||
{
|
||||
EnterCriticalSection(&m_Lock.Lock);
|
||||
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
|
||||
if (threadId == m_Lock.OwnerThreadId) {
|
||||
Mx::MxAssertMsg("Recursive acquision of the lock is not allowed", FALSE);
|
||||
}
|
||||
|
||||
m_Lock.OwnerThreadId = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxPagedLockNoDynam::AcquireUnsafe(
|
||||
)
|
||||
{
|
||||
MxPagedLockNoDynam::Acquire();
|
||||
}
|
||||
|
||||
__inline
|
||||
BOOLEAN
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations.");
|
||||
MxPagedLockNoDynam::TryToAcquire(
|
||||
)
|
||||
{
|
||||
return TryEnterCriticalSection(&m_Lock.Lock) == TRUE ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
|
||||
__inline
|
||||
VOID
|
||||
#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations.");
|
||||
MxPagedLockNoDynam::Release(
|
||||
)
|
||||
{
|
||||
m_Lock.OwnerThreadId = 0;
|
||||
|
||||
LeaveCriticalSection(&m_Lock.Lock);
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxPagedLockNoDynam::ReleaseUnsafe(
|
||||
)
|
||||
{
|
||||
MxPagedLockNoDynam::Release();
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxPagedLockNoDynam::Uninitialize(
|
||||
)
|
||||
{
|
||||
DeleteCriticalSection(&m_Lock.Lock);
|
||||
m_Lock.Initialized = false;
|
||||
}
|
||||
|
||||
__inline
|
||||
MxPagedLock::~MxPagedLock(
|
||||
)
|
||||
{
|
||||
if (m_Lock.Initialized) {
|
||||
this->Uninitialize();
|
||||
}
|
||||
}
|
479
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxtimerum.h
Normal file
479
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxtimerum.h
Normal file
|
@ -0,0 +1,479 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxTimerUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
User mode implementation of timer defined in
|
||||
MxTimer.h
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct _MdTimer {
|
||||
//
|
||||
// Callback function to be invoked upon timer expiration and the context to
|
||||
// be passed in to the callback function
|
||||
//
|
||||
MdDeferredRoutine m_TimerCallback;
|
||||
PVOID m_TimerContext;
|
||||
|
||||
//
|
||||
// The timer period
|
||||
//
|
||||
LONG m_Period;
|
||||
|
||||
//
|
||||
// Handle to the timer object
|
||||
//
|
||||
PTP_TIMER m_TimerHandle;
|
||||
|
||||
//
|
||||
// Work object to be executed by threadpool upon timer expiration
|
||||
//
|
||||
PTP_WORK m_WorkObject;
|
||||
|
||||
//
|
||||
// Flag to indicate that the timer callback has started running
|
||||
//
|
||||
BOOL m_CallbackStartedRunning;
|
||||
|
||||
//
|
||||
// Flag to indicate that the timer was started
|
||||
// since it was created or since it was last stopped.
|
||||
//
|
||||
BOOL m_TimerWasStarted;
|
||||
|
||||
_MdTimer(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
m_TimerHandle = NULL;
|
||||
m_WorkObject = NULL;
|
||||
m_TimerCallback = NULL;
|
||||
m_TimerContext = NULL;
|
||||
m_Period = 0;
|
||||
m_CallbackStartedRunning = FALSE;
|
||||
m_TimerWasStarted = FALSE;
|
||||
}
|
||||
|
||||
~_MdTimer(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Release the timer object
|
||||
//
|
||||
if (m_TimerHandle)
|
||||
{
|
||||
CloseThreadpoolTimer(m_TimerHandle);
|
||||
m_TimerHandle = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Release the work object
|
||||
//
|
||||
if (m_WorkObject)
|
||||
{
|
||||
CloseThreadpoolWork(m_WorkObject);
|
||||
m_WorkObject = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
IsInSystemQueue(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Timer was not started since it was created or since
|
||||
// it was last stopped, so it can't be in the system timer queue.
|
||||
//
|
||||
if (!m_TimerWasStarted) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Periodic timers are always in the system timer queue.
|
||||
//
|
||||
if (m_Period != 0) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Non-periodic timer:
|
||||
//
|
||||
// At this point, the timer callback function has either been canceled or
|
||||
// has finished running. Examine the m_CallbackStartedRunning value to see
|
||||
// which one of these happened.
|
||||
//
|
||||
if (m_CallbackStartedRunning)
|
||||
{
|
||||
//
|
||||
// Timer cancellation was too late. Timer callback already started
|
||||
// running and the timer was removed from the system timer queue.
|
||||
//
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Timer cancellation happened on time and prevented the timer callback
|
||||
// from running.
|
||||
//
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
Initialize(
|
||||
__in_opt PVOID TimerContext,
|
||||
__in MdDeferredRoutine TimerCallback,
|
||||
__in LONG Period
|
||||
)
|
||||
{
|
||||
NTSTATUS ntStatus = STATUS_SUCCESS;
|
||||
|
||||
m_TimerCallback = TimerCallback;
|
||||
m_TimerContext = TimerContext;
|
||||
m_Period = Period;
|
||||
|
||||
//
|
||||
// Create the timer object
|
||||
//
|
||||
m_TimerHandle = CreateThreadpoolTimer(_MdTimer::s_MdTimerCallback,
|
||||
this,
|
||||
NULL);
|
||||
if (NULL == m_TimerHandle)
|
||||
{
|
||||
ntStatus = WinErrorToNtStatus(GetLastError());
|
||||
}
|
||||
|
||||
//
|
||||
// Create the work object
|
||||
//
|
||||
if (NT_SUCCESS(ntStatus))
|
||||
{
|
||||
m_WorkObject = CreateThreadpoolWork(_MdTimer::s_MdWorkCallback,
|
||||
this,
|
||||
NULL);
|
||||
if (NULL == m_WorkObject)
|
||||
{
|
||||
ntStatus = WinErrorToNtStatus(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
return ntStatus;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Start(
|
||||
__in LARGE_INTEGER DueTime,
|
||||
__in ULONG TolerableDelay
|
||||
)
|
||||
{
|
||||
BOOLEAN bRetVal;
|
||||
FILETIME dueFileTime;
|
||||
|
||||
if (m_TimerWasStarted) {
|
||||
//
|
||||
// Cancel the previously pended timer callback,
|
||||
// we want it to execute after a full period elapsed.
|
||||
//
|
||||
WaitForThreadpoolTimerCallbacks(m_TimerHandle, TRUE);
|
||||
}
|
||||
|
||||
//
|
||||
// Return TRUE if the timer is in the system timer queue.
|
||||
//
|
||||
bRetVal = IsInSystemQueue();
|
||||
|
||||
//
|
||||
// This is a fresh start for the timer, so clear the flag that the
|
||||
// timer callback function may have previously set.
|
||||
//
|
||||
m_CallbackStartedRunning = FALSE;
|
||||
|
||||
//
|
||||
// Set the timer started flag.
|
||||
//
|
||||
m_TimerWasStarted = TRUE;
|
||||
|
||||
//
|
||||
// Copy the due time into a FILETIME structure
|
||||
//
|
||||
dueFileTime.dwLowDateTime = DueTime.LowPart;
|
||||
dueFileTime.dwHighDateTime = (DWORD) DueTime.HighPart;
|
||||
|
||||
//
|
||||
// Start the timer
|
||||
//
|
||||
SetThreadpoolTimer(m_TimerHandle,
|
||||
&dueFileTime,
|
||||
(DWORD) m_Period,
|
||||
TolerableDelay);
|
||||
|
||||
return bRetVal;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
BOOLEAN
|
||||
Stop(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
BOOLEAN bRetVal;
|
||||
|
||||
bRetVal = IsInSystemQueue();
|
||||
|
||||
//
|
||||
// Stop the timer
|
||||
//
|
||||
SetThreadpoolTimer(m_TimerHandle,
|
||||
NULL, // pftDueTime
|
||||
0, // msPeriod
|
||||
0 // msWindowLength
|
||||
);
|
||||
|
||||
//
|
||||
// Cancel pending callbacks that have not yet started to execute and wait
|
||||
// for outstanding callbacks to complete.
|
||||
//
|
||||
WaitForThreadpoolTimerCallbacks(m_TimerHandle,
|
||||
TRUE // cancel pending callbacks
|
||||
);
|
||||
|
||||
//
|
||||
// Reset the timer started flag.
|
||||
//
|
||||
m_TimerWasStarted = FALSE;
|
||||
|
||||
return bRetVal;
|
||||
}
|
||||
|
||||
VOID
|
||||
TimerCallback(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Invoke the user's callback function
|
||||
//
|
||||
m_TimerCallback(NULL, /* Reserved1 */
|
||||
m_TimerContext,
|
||||
NULL, /* Reserved2 */
|
||||
NULL /* Reserved3 */
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
VOID CALLBACK
|
||||
s_MdWorkCallback(
|
||||
__inout PTP_CALLBACK_INSTANCE Instance,
|
||||
__inout_opt PVOID Context,
|
||||
__inout PTP_WORK Work
|
||||
)
|
||||
{
|
||||
struct _MdTimer *pThis = NULL;
|
||||
|
||||
UNREFERENCED_PARAMETER(Instance);
|
||||
UNREFERENCED_PARAMETER(Work);
|
||||
|
||||
pThis = (struct _MdTimer*) Context;
|
||||
pThis->TimerCallback();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
VOID CALLBACK
|
||||
s_MdTimerCallback(
|
||||
__inout PTP_CALLBACK_INSTANCE Instance,
|
||||
__inout_opt PVOID Context,
|
||||
__inout PTP_TIMER Timer
|
||||
)
|
||||
{
|
||||
struct _MdTimer *pThis = NULL;
|
||||
|
||||
UNREFERENCED_PARAMETER(Instance);
|
||||
UNREFERENCED_PARAMETER(Timer);
|
||||
|
||||
pThis = (struct _MdTimer*) Context;
|
||||
|
||||
//
|
||||
// First, indicate that the callback has started running
|
||||
//
|
||||
pThis->m_CallbackStartedRunning = TRUE;
|
||||
|
||||
//
|
||||
// Post a work object to execute the callback function supplied by the
|
||||
// user of MxTimer.
|
||||
//
|
||||
// We do not execute the user-supplied callback here because we could
|
||||
// run into a deadlock if the user is trying to cancel the timer by
|
||||
// calling MxTimer::Stop. MxTimer::Stop actually blocks waiting for
|
||||
// MdTimer::s_MdTimerCallback to finish executing, so that it can know
|
||||
// where its attempt to cancel the timer was successful. If we were to
|
||||
// execute the user's callback in MdTimer::s_MdTimerCallback, the user
|
||||
// would have to be careful not to call MxTimer::Stop while holding a
|
||||
// lock that the user's callback tries to acquire. In order to avoid
|
||||
// imposing such a restriction on the user, we allow
|
||||
// MdTimer::s_MdTimerCallback to return immediately after posting a
|
||||
// work object to run the user's callback.
|
||||
//
|
||||
SubmitThreadpoolWork(pThis->m_WorkObject);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
StartWithReturn(
|
||||
__in LARGE_INTEGER DueTime,
|
||||
__in ULONG TolerableDelay
|
||||
)
|
||||
{
|
||||
return Start(DueTime, TolerableDelay);
|
||||
}
|
||||
} MdTimer;
|
||||
|
||||
#include "MxTimer.h"
|
||||
|
||||
//
|
||||
// Implementation of MxTimer functions
|
||||
//
|
||||
MxTimer::MxTimer(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
MxTimer::~MxTimer(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
MxTimer::Initialize(
|
||||
__in_opt PVOID TimerContext,
|
||||
__in MdDeferredRoutine TimerCallback,
|
||||
__in LONG Period
|
||||
)
|
||||
/*++
|
||||
Routine description:
|
||||
Initializes the MxTimer object.
|
||||
|
||||
Arguments:
|
||||
TimerContext - Context information that will be passed in to the timer
|
||||
callback function.
|
||||
|
||||
TimerCallback - The timer callback function.
|
||||
|
||||
*** IMPORTANT NOTE ***
|
||||
MxTimer object must not be freed inside the timer callback function
|
||||
because in the pre-Vista, user mode implementation of MxTimer, the
|
||||
destructor blocks waiting for all callback functions to finish
|
||||
executing. Hence freeing the MxTimer object inside the callback
|
||||
function will result in a deadlock.
|
||||
|
||||
Period - The period of the timer in milliseconds.
|
||||
|
||||
Return value:
|
||||
An NTSTATUS value that indicates whether or not we succeeded in
|
||||
initializing the MxTimer
|
||||
--*/
|
||||
{
|
||||
NTSTATUS ntStatus;
|
||||
|
||||
ntStatus = m_Timer.Initialize(TimerContext,
|
||||
TimerCallback,
|
||||
Period);
|
||||
|
||||
return ntStatus;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
MxTimer::InitializeEx(
|
||||
__in_opt PVOID TimerContext,
|
||||
__in MdExtCallback TimerCallback,
|
||||
__in LONG Period,
|
||||
__in ULONG TolerableDelay,
|
||||
__in BOOLEAN UseHighResolutionTimer
|
||||
)
|
||||
{
|
||||
|
||||
UNREFERENCED_PARAMETER(TolerableDelay);
|
||||
UNREFERENCED_PARAMETER(UseHighResolutionTimer);
|
||||
UNREFERENCED_PARAMETER(TimerCallback);
|
||||
UNREFERENCED_PARAMETER(TimerContext);
|
||||
UNREFERENCED_PARAMETER(Period);
|
||||
ASSERTMSG("Not implemented for UMDF\n", FALSE);
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
}
|
||||
|
||||
VOID
|
||||
MxTimer::Start(
|
||||
__in LARGE_INTEGER DueTime,
|
||||
__in ULONG TolerableDelay
|
||||
)
|
||||
{
|
||||
m_Timer.Start(DueTime, TolerableDelay);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
BOOLEAN
|
||||
MxTimer::Stop(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
BOOLEAN bRetVal;
|
||||
|
||||
bRetVal = m_Timer.Stop();
|
||||
|
||||
return bRetVal;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
BOOLEAN
|
||||
MxTimer::StartWithReturn(
|
||||
__in LARGE_INTEGER DueTime,
|
||||
__in ULONG TolerableDelay
|
||||
)
|
||||
{
|
||||
BOOLEAN bRetVal = TRUE;
|
||||
|
||||
bRetVal = m_Timer.StartWithReturn(DueTime, TolerableDelay);
|
||||
|
||||
return bRetVal;
|
||||
}
|
||||
|
||||
VOID
|
||||
MxTimer::FlushQueuedDpcs(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
WaitForThreadpoolWorkCallbacks(m_Timer.m_WorkObject,
|
||||
TRUE // cancel pending callbacks
|
||||
);
|
||||
}
|
||||
|
248
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxum.h
Normal file
248
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxum.h
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This file includes standard NT headers and
|
||||
user mode versions of mode agnostic headers
|
||||
|
||||
It also contains definitions pulled out from wdm.h
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef UMDF_USING_NTSTATUS
|
||||
#define UMDF_USING_NTSTATUS
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <devpropdef.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef UMDF_INFRASTRUCTURE
|
||||
#ifndef WUDF_KERNEL
|
||||
typedef PVOID PIRP;
|
||||
typedef PVOID PIO_REMOVE_LOCK;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "wdmdefs.h"
|
||||
|
||||
#define WDF_VIOLATION ((ULONG)0x0000010DL)
|
||||
|
||||
#define FX_PLUGPLAY_REGKEY_DEVICEMAP 0x8
|
||||
|
||||
//
|
||||
// Define the callback function to be supplied by a user-mode user of MxTimer
|
||||
// It has the extra parameters Reserved1, Reserved2 and Reserved3 to make it
|
||||
// look like the KDEFERRED_ROUTINE that used as the callback function for the
|
||||
// kernel mode version of MxTimer. The user-mode user of MxTimer should not
|
||||
// use these ReservedX parameters.
|
||||
//
|
||||
|
||||
typedef
|
||||
VOID
|
||||
TIMER_CALLBACK_ROUTINE(
|
||||
__in PKDPC Reserved1,
|
||||
__in_opt PVOID Context,
|
||||
__in_opt PVOID Reserved2,
|
||||
__in_opt PVOID Reserved3
|
||||
);
|
||||
|
||||
typedef PVOID PEX_TIMER;
|
||||
|
||||
typedef
|
||||
VOID
|
||||
TIMER_CALLBACK_ROUTINE_EX(
|
||||
__in PEX_TIMER Reserved1,
|
||||
__in_opt PVOID Context
|
||||
);
|
||||
|
||||
typedef TIMER_CALLBACK_ROUTINE MdDeferredRoutineType, *MdDeferredRoutine;
|
||||
typedef TIMER_CALLBACK_ROUTINE_EX MdExtCallbackType, *MdExtCallback;
|
||||
|
||||
//
|
||||
// Forward defines
|
||||
//
|
||||
struct IFxMessageDispatch;
|
||||
struct IUnknown;
|
||||
struct IWudfIrp;
|
||||
struct IWudfIoIrp;
|
||||
struct IWudfFile;
|
||||
struct IWDFObject;
|
||||
struct IObjectCleanup;
|
||||
struct IWudfDeviceStack;
|
||||
struct IWudfDeviceStack2;
|
||||
struct IWudfTargetCallbackDeviceChange;
|
||||
struct IWudfIoDispatcher;
|
||||
struct IWudfRemoteDispatcher;
|
||||
struct IWudfDevice;
|
||||
struct IWudfDevice2;
|
||||
struct IWudfHost;
|
||||
struct IWudfHost2;
|
||||
|
||||
//
|
||||
// typedefs
|
||||
//
|
||||
typedef IWudfDevice * MdDeviceObject;
|
||||
typedef IWudfIrp* MdIrp;
|
||||
typedef LPCSTR MxFuncName;
|
||||
typedef PVOID MxThread;
|
||||
typedef PVOID MdEThread;
|
||||
typedef PWUDF_IO_REMOVE_LOCK MdRemoveLock;
|
||||
typedef PVOID MdInterrupt;
|
||||
|
||||
typedef struct _STACK_DEVICE_CAPABILITIES *PSTACK_DEVICE_CAPABILITIES;
|
||||
typedef UINT64 WUDF_INTERFACE_CONTEXT;
|
||||
typedef enum _WDF_REQUEST_TYPE WDF_REQUEST_TYPE;
|
||||
typedef struct _WDF_INTERRUPT_INFO *PWDF_INTERRUPT_INFO;
|
||||
typedef enum _WDF_INTERRUPT_POLICY WDF_INTERRUPT_POLICY;
|
||||
typedef enum _WDF_INTERRUPT_PRIORITY WDF_INTERRUPT_PRIORITY;
|
||||
typedef struct _WDF_OBJECT_ATTRIBUTES *PWDF_OBJECT_ATTRIBUTES;
|
||||
typedef enum _WDF_DEVICE_IO_BUFFER_RETRIEVAL WDF_DEVICE_IO_BUFFER_RETRIEVAL;
|
||||
typedef enum RdWmiPowerAction;
|
||||
typedef struct _WDF_REQUEST_PARAMETERS *PWDF_REQUEST_PARAMETERS;
|
||||
typedef enum _WDF_EVENT_TYPE WDF_EVENT_TYPE;
|
||||
typedef enum _WDF_FILE_INFORMATION_CLASS WDF_FILE_INFORMATION_CLASS;
|
||||
typedef WDF_FILE_INFORMATION_CLASS *PWDF_FILE_INFORMATION_CLASS;
|
||||
|
||||
typedef
|
||||
NTSTATUS
|
||||
WUDF_IO_COMPLETION_ROUTINE (
|
||||
__in MdDeviceObject DeviceObject,
|
||||
__in MdIrp Irp,
|
||||
__in PVOID Context
|
||||
);
|
||||
|
||||
typedef WUDF_IO_COMPLETION_ROUTINE *PWUDF_IO_COMPLETION_ROUTINE;
|
||||
|
||||
typedef
|
||||
VOID
|
||||
WUDF_DRIVER_CANCEL (
|
||||
__in MdDeviceObject DeviceObject,
|
||||
__in MdIrp Irp
|
||||
);
|
||||
|
||||
typedef WUDF_DRIVER_CANCEL *PWUDF_DRIVER_CANCEL;
|
||||
typedef WUDF_IO_COMPLETION_ROUTINE MdCompletionRoutineType, *MdCompletionRoutine;
|
||||
typedef WUDF_DRIVER_CANCEL MdCancelRoutineType, *MdCancelRoutine;
|
||||
|
||||
//
|
||||
// From wdm.h
|
||||
//
|
||||
|
||||
typedef
|
||||
__drv_functionClass(REQUEST_POWER_COMPLETE)
|
||||
__drv_sameIRQL
|
||||
VOID
|
||||
REQUEST_POWER_COMPLETE (
|
||||
__in MdDeviceObject DeviceObject,
|
||||
__in UCHAR MinorFunction,
|
||||
__in POWER_STATE PowerState,
|
||||
__in_opt PVOID Context,
|
||||
__in PIO_STATUS_BLOCK IoStatus
|
||||
);
|
||||
|
||||
typedef REQUEST_POWER_COMPLETE *PREQUEST_POWER_COMPLETE;
|
||||
typedef REQUEST_POWER_COMPLETE MdRequestPowerCompleteType, *MdRequestPowerComplete;
|
||||
|
||||
typedef enum _WDF_DEVICE_IO_TYPE WDF_DEVICE_IO_TYPE;
|
||||
typedef struct _DRIVER_OBJECT_UM *PDRIVER_OBJECT_UM;
|
||||
|
||||
//
|
||||
// Driver object's basic interface.
|
||||
//
|
||||
typedef
|
||||
NTSTATUS
|
||||
DRIVER_ADD_DEVICE_UM (
|
||||
_In_ PDRIVER_OBJECT_UM DriverObject,
|
||||
_In_ PVOID Context,
|
||||
_In_ IWudfDeviceStack * DevStack,
|
||||
_In_ LPCWSTR KernelDeviceName,
|
||||
_In_opt_ HKEY hPdoKey,
|
||||
_In_ LPCWSTR pwszServiceName,
|
||||
_In_ LPCWSTR pwszDevInstanceID,
|
||||
_In_ ULONG ulDriverID
|
||||
);
|
||||
|
||||
typedef DRIVER_ADD_DEVICE_UM *PFN_DRIVER_ADD_DEVICE_UM;
|
||||
|
||||
typedef
|
||||
VOID
|
||||
DRIVER_DISPATCH_UM (
|
||||
_In_ IWudfDevice * DeviceObject,
|
||||
_In_ IWudfIrp * Irp,
|
||||
_In_opt_ IUnknown * Context
|
||||
);
|
||||
|
||||
typedef DRIVER_DISPATCH_UM *PFN_DRIVER_DISPATCH_UM;
|
||||
|
||||
typedef
|
||||
VOID
|
||||
DRIVER_UNLOAD_UM (
|
||||
_In_ PDRIVER_OBJECT_UM DriverObject
|
||||
);
|
||||
|
||||
typedef DRIVER_UNLOAD_UM *PFN_DRIVER_UNLOAD_UM;
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef UMDF_INFRASTRUCTURE
|
||||
#ifndef WUDF_KERNEL
|
||||
typedef CCHAR KPROCESSOR_MODE;
|
||||
typedef PVOID PMDL;
|
||||
typedef
|
||||
_IRQL_requires_same_
|
||||
_Function_class_(ALLOCATE_FUNCTION)
|
||||
PVOID
|
||||
ALLOCATE_FUNCTION (
|
||||
_In_ POOL_TYPE PoolType,
|
||||
_In_ SIZE_T NumberOfBytes,
|
||||
_In_ ULONG Tag
|
||||
);
|
||||
typedef ALLOCATE_FUNCTION *PALLOCATE_FUNCTION;
|
||||
typedef
|
||||
_IRQL_requires_same_
|
||||
_Function_class_(FREE_FUNCTION)
|
||||
VOID
|
||||
FREE_FUNCTION (
|
||||
_In_ __drv_freesMem(Mem) PVOID Buffer
|
||||
);
|
||||
typedef FREE_FUNCTION *PFREE_FUNCTION;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//===============================================================================
|
||||
#include <limits.h>
|
||||
#include <driverspecs.h>
|
||||
|
||||
#include "ErrToStatus.h"
|
||||
|
||||
#include "MxDriverObjectUm.h"
|
||||
#include "MxDeviceObjectUm.h"
|
||||
#include "MxFileObjectUm.h"
|
||||
#include "MxGeneralUm.h"
|
||||
#include "MxLockUm.h"
|
||||
#include "MxPagedLockUm.h"
|
||||
#include "MxEventUm.h"
|
||||
#include "MxMemoryUm.h"
|
||||
#include "MxTimerUm.h"
|
||||
#include "MxWorkItemUm.h"
|
294
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxworkitemum.h
Normal file
294
sdk/lib/drivers/wdf/shared/inc/primitives/um/mxworkitemum.h
Normal file
|
@ -0,0 +1,294 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
ModuleName:
|
||||
|
||||
MxWorkItemUm.h
|
||||
|
||||
Abstract:
|
||||
|
||||
User mode implementation of work item
|
||||
class defined in MxWorkItem.h
|
||||
|
||||
***********PLEASE NOTE*****************************
|
||||
A significant difference from kernel mode implementation of work item
|
||||
is that user mode version of MxWorkItem::_Free synchronously waits for
|
||||
callback to return.
|
||||
|
||||
This implies that _Free cannot be invoked from within the callback otherwise
|
||||
it would lead to a deadlock.
|
||||
|
||||
PLEASE NOTE that _Free cannot be made to return without waiting without
|
||||
significant changes.
|
||||
|
||||
If Free is not made to wait synchronously there is a potential for binary
|
||||
unload while workitem is running - even with waiting for an event/reference
|
||||
count etc., the tail instructions may be running.
|
||||
The only way to resolve that is to move work-item code out of framework
|
||||
binary and into the host so that host can take a reference on framework
|
||||
binary around the work item callback invocation (similar to the way I/O
|
||||
manager keeps a reference on the device object around the invocation of
|
||||
|
||||
workitem callback).
|
||||
****************************************************
|
||||
|
||||
Author:
|
||||
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef
|
||||
VOID
|
||||
MX_WORKITEM_ROUTINE (
|
||||
__in MdDeviceObject DeviceObject,
|
||||
__in_opt PVOID Context
|
||||
);
|
||||
|
||||
typedef MX_WORKITEM_ROUTINE *PMX_WORKITEM_ROUTINE;
|
||||
|
||||
typedef struct {
|
||||
MdDeviceObject DeviceObject;
|
||||
|
||||
//
|
||||
// threadpool wait block
|
||||
//
|
||||
PTP_WAIT WaitBlock;
|
||||
|
||||
HANDLE WorkItemEvent;
|
||||
|
||||
PMX_WORKITEM_ROUTINE Callback;
|
||||
|
||||
PVOID Context;
|
||||
|
||||
//
|
||||
// True if callbacks run in the default thread pool environment,
|
||||
// rather than in an environment explicitly owned by the driver.
|
||||
// This has implications in MxWorkItem::_Free.
|
||||
//
|
||||
BOOLEAN DefaultThreadpoolEnv;
|
||||
} UmWorkItem;
|
||||
|
||||
typedef UmWorkItem* MdWorkItem;
|
||||
|
||||
#include "MxWorkItem.h"
|
||||
|
||||
__inline
|
||||
MxWorkItem::MxWorkItem(
|
||||
)
|
||||
{
|
||||
m_WorkItem = NULL;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
__inline
|
||||
NTSTATUS
|
||||
MxWorkItem::Allocate(
|
||||
__in MdDeviceObject DeviceObject,
|
||||
__in_opt PVOID ThreadPoolEnv
|
||||
)
|
||||
{
|
||||
DWORD err = 0;
|
||||
|
||||
m_WorkItem = (MdWorkItem)::HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
0,
|
||||
sizeof(UmWorkItem)
|
||||
);
|
||||
|
||||
if (NULL == m_WorkItem) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
ZeroMemory(m_WorkItem, sizeof(UmWorkItem));
|
||||
|
||||
m_WorkItem->WorkItemEvent = CreateEvent(
|
||||
NULL,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
if (NULL == m_WorkItem->WorkItemEvent) {
|
||||
err = GetLastError();
|
||||
goto exit;
|
||||
}
|
||||
|
||||
m_WorkItem->WaitBlock = CreateThreadpoolWait(
|
||||
_WorkerThunk,
|
||||
this->GetWorkItem(), // Context to callback function
|
||||
(PTP_CALLBACK_ENVIRON)ThreadPoolEnv
|
||||
);
|
||||
|
||||
if (m_WorkItem->WaitBlock == NULL) {
|
||||
err = GetLastError();
|
||||
goto exit;
|
||||
}
|
||||
|
||||
m_WorkItem->DefaultThreadpoolEnv = (NULL == ThreadPoolEnv);
|
||||
|
||||
m_WorkItem->DeviceObject = DeviceObject;
|
||||
|
||||
exit:
|
||||
//
|
||||
// Cleanup in case of failure
|
||||
//
|
||||
if (0 != err) {
|
||||
if (NULL != m_WorkItem->WorkItemEvent) {
|
||||
CloseHandle(m_WorkItem->WorkItemEvent);
|
||||
m_WorkItem->WorkItemEvent = NULL;
|
||||
}
|
||||
|
||||
::HeapFree(GetProcessHeap(), 0, m_WorkItem);
|
||||
m_WorkItem = NULL;
|
||||
}
|
||||
|
||||
return NTSTATUS_FROM_WIN32(err);
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxWorkItem::Enqueue(
|
||||
__in PMX_WORKITEM_ROUTINE Callback,
|
||||
__in PVOID Context
|
||||
)
|
||||
{
|
||||
//
|
||||
// ASSUMPTION: This function assumes that another call to Enqueue
|
||||
// is made only after the callback has been invoked, altough it is OK
|
||||
// to make another call from within the callback.
|
||||
//
|
||||
// It is up to a higher layer/caller to ensure this.
|
||||
// For example: FxSystemWorkItem layered on top of MxWorkItem ensures this.
|
||||
//
|
||||
|
||||
//
|
||||
// Since multiple calls to Enqueue cannot be made at the same time
|
||||
// as explained above, it is OK to store callback and context in
|
||||
// the workitem itself.
|
||||
//
|
||||
// This behavior is similar to that of IoQueueWorkItem which accepts
|
||||
// a callback and a context which are stored within the work-item.
|
||||
//
|
||||
|
||||
m_WorkItem->Callback = Callback;
|
||||
m_WorkItem->Context = Context;
|
||||
|
||||
//
|
||||
// We must register the event with the wait object before signaling it
|
||||
// to trigger the wait callback.
|
||||
//
|
||||
SetThreadpoolWait(m_WorkItem->WaitBlock,
|
||||
m_WorkItem->WorkItemEvent,
|
||||
NULL // timeout
|
||||
);
|
||||
|
||||
SetEvent(m_WorkItem->WorkItemEvent);
|
||||
}
|
||||
|
||||
__inline
|
||||
MdWorkItem
|
||||
MxWorkItem::GetWorkItem(
|
||||
)
|
||||
{
|
||||
return m_WorkItem;
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxWorkItem::_Free(
|
||||
__in MdWorkItem Item
|
||||
)
|
||||
{
|
||||
//
|
||||
// PLEASE NOTE that _Free waits for callback to return synchronously.
|
||||
//
|
||||
// DO NOT call _Free from work item callback otherwise it would cause a
|
||||
// deadlock.
|
||||
//
|
||||
// Please see comments on the top of the file.
|
||||
//
|
||||
|
||||
if (NULL != Item) {
|
||||
//
|
||||
// Wait indefinitely for work item to complete
|
||||
//
|
||||
if (NULL != Item->WaitBlock) {
|
||||
//
|
||||
// this will prevent any new waits to be queued but callbacks
|
||||
// already queued will still occur.
|
||||
//
|
||||
SetThreadpoolWait(Item->WaitBlock, NULL, NULL);
|
||||
|
||||
//
|
||||
// If the callbacks ran in the default thread pool environment,
|
||||
// wait for callbacks to finish.
|
||||
// If they ran in an environment explicitly owned by the driver,
|
||||
// then this wait will happen before the driver DLL is unloaded,
|
||||
// the host takes care of this.
|
||||
//
|
||||
if (Item->DefaultThreadpoolEnv) {
|
||||
WaitForThreadpoolWaitCallbacks(Item->WaitBlock,
|
||||
FALSE // donot cancel pending waits
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Release the wait object.
|
||||
//
|
||||
CloseThreadpoolWait(Item->WaitBlock);
|
||||
}
|
||||
|
||||
if (NULL != Item->WorkItemEvent) {
|
||||
CloseHandle(Item->WorkItemEvent);
|
||||
Item->WorkItemEvent = NULL;
|
||||
}
|
||||
|
||||
::HeapFree(
|
||||
GetProcessHeap(),
|
||||
0,
|
||||
Item
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
__inline
|
||||
VOID
|
||||
MxWorkItem::Free(
|
||||
)
|
||||
{
|
||||
//
|
||||
// PLEASE NOTE that _Free waits for callback to return synchronously.
|
||||
//
|
||||
// DO NOT call Free from work item callback otherwise it would cause a
|
||||
// deadlock.
|
||||
//
|
||||
// Please see comments on the top of the file.
|
||||
//
|
||||
|
||||
if (NULL != m_WorkItem) {
|
||||
MxWorkItem::_Free(m_WorkItem);
|
||||
m_WorkItem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// FxAutoWorkitem
|
||||
//
|
||||
__inline
|
||||
MxAutoWorkItem::~MxAutoWorkItem(
|
||||
)
|
||||
{
|
||||
this->Free();
|
||||
}
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue