reactos/sdk/lib/drivers/wdf/shared/inc/private/common/fxeventqueue.hpp

382 lines
7.2 KiB
C++
Raw Normal View History

//
// Copyright (C) Microsoft. All rights reserved.
//
#ifndef _FXEVENTQUEUE_H_
#define _FXEVENTQUEUE_H_
struct FxPostProcessInfo {
FxPostProcessInfo(
VOID
)
{
m_Event = NULL;
m_DeleteObject = FALSE;
m_SetRemovedEvent = FALSE;
m_FireAndForgetIrp = NULL;
}
BOOLEAN
SomethingToDo(
VOID
)
{
return ((m_Event != NULL) || m_DeleteObject) ? TRUE : FALSE;
}
VOID
Evaluate(
__inout FxPkgPnp* PkgPnp
);
FxCREvent* m_Event;
BOOLEAN m_DeleteObject;
BOOLEAN m_SetRemovedEvent;
MdIrp m_FireAndForgetIrp;
};
typedef
VOID
(*PFN_PNP_EVENT_WORKER)(
__in FxPkgPnp* PkgPnp,
__in FxPostProcessInfo* Info,
__in PVOID Context
);
enum FxEventQueueFlags {
FxEventQueueFlagWorkItemQueued = 0x01,
FxEventQueueFlagClosed = 0x02,
FxEventQueueFlagDelayDeletion = 0x04,
};
struct FxEventQueue : public FxStump {
FxEventQueue(
__in UCHAR QueueDepth
);
_Must_inspect_result_
NTSTATUS
Initialize(
__in PFX_DRIVER_GLOBALS DriverGlobals
);
_Acquires_lock_(this->m_QueueLock)
__drv_maxIRQL(DISPATCH_LEVEL)
__drv_setsIRQL(DISPATCH_LEVEL)
VOID
Lock(
__out __drv_deref(__drv_savesIRQL)
PKIRQL Irql
)
{
m_QueueLock.Acquire(Irql);
}
_Releases_lock_(this->m_QueueLock)
__drv_requiresIRQL(DISPATCH_LEVEL)
VOID
Unlock(
__in __drv_restoresIRQL
KIRQL Irql
)
{
m_QueueLock.Release(Irql);
}
BOOLEAN
IsFull(
VOID
)
{
return ((m_QueueHead + m_QueueDepth - 1) % m_QueueDepth) == (m_QueueTail % m_QueueDepth);
}
BOOLEAN
IsEmpty(
VOID
)
{
return m_QueueHead == m_QueueTail;
}
VOID
IncrementHead(
VOID
)
{
m_QueueHead = (m_QueueHead + 1) % m_QueueDepth;
}
UCHAR
GetHead(
VOID
)
{
return m_QueueHead;
}
UCHAR
InsertAtHead(
VOID
)
{
m_QueueHead = (m_QueueHead + m_QueueDepth - 1) % m_QueueDepth;
return m_QueueHead;
}
UCHAR
InsertAtTail(
VOID
)
{
UCHAR index;
// Save the index which is the current tail
index = m_QueueTail;
// goto next slot
m_QueueTail = (m_QueueTail + 1) % m_QueueDepth;
// return the old tail as the slot to insert at
return index;
}
UCHAR
IncrementHistoryIndex(
VOID
)
{
UCHAR cur;
cur = m_HistoryIndex;
m_HistoryIndex = (m_HistoryIndex + 1) % m_QueueDepth;
return cur;
}
BOOLEAN
IsClosedLocked(
VOID
)
{
return (m_QueueFlags & FxEventQueueFlagClosed) ? TRUE : FALSE;
}
VOID
GetFinishedState(
__inout FxPostProcessInfo* Info
)
{
if (IsIdleLocked()) {
if (m_QueueFlags & FxEventQueueFlagDelayDeletion) {
m_QueueFlags &= ~FxEventQueueFlagDelayDeletion;
Info->m_DeleteObject = TRUE;
}
if (IsClosedLocked()) {
Info->m_Event = m_WorkItemFinished;
m_WorkItemFinished = NULL;
}
}
}
BOOLEAN
SetFinished(
__in FxCREvent* Event
);
VOID
SetDelayedDeletion(
VOID
);
protected:
VOID
Configure(
__in FxPkgPnp* Pnp,
__in PFN_PNP_EVENT_WORKER WorkerRoutine,
__in PVOID Context
);
BOOLEAN
QueueToThreadWorker(
VOID
);
VOID
EventQueueWorker(
VOID
);
BOOLEAN
IsIdleLocked(
VOID
)
{
//
// We are idle if there is no work item queued, no work item running,
// and there are no events in the queue. Since m_WorkItemQueued is
// cleared before we enter the state machine, we must also track the
// number of work items running.
//
if ((m_QueueFlags & FxEventQueueFlagWorkItemQueued) == 0x00 &&
m_WorkItemRunningCount == 0x0 &&
IsEmpty()) {
return TRUE;
}
else {
return FALSE;
}
}
protected:
// index into the beginning of the circular event ring buffer
UCHAR m_QueueHead;
// index into the end of the circular event ring buffer
UCHAR m_QueueTail;
// circular event ring buffer size
UCHAR m_QueueDepth;
UCHAR m_HistoryIndex;
FxPkgPnp* m_PkgPnp;
//
// Context that is passed back to the the state machine as
// part of the event worker
//
PVOID m_EventWorkerContext;
//
// Lock for the queue
//
MxLock m_QueueLock;
public:
FxWaitLockInternal m_StateMachineLock;
protected:
PFN_PNP_EVENT_WORKER m_EventWorker;
//
// Guarded by m_QueueLock. Will be set to a valid pointer value when pnp
// wants to remove the device and we want to synchronize against the work
// item running.
//
FxCREvent* m_WorkItemFinished;
//
//
union {
//
// See FxEventQueueFlags for values
//
UCHAR m_QueueFlags;
struct {
UCHAR WorkItemQueued : 1;
UCHAR Closed : 1;
UCHAR DelayDeletion : 1;
} m_QueueFlagsByName;
};
//
// Count of times the work item is running. Since m_WorkItemQueued is
// cleared before we enter the state machine, we must also track the
// number of instances to make sure we know when we are idle or not.
//
UCHAR m_WorkItemRunningCount;
};
struct FxWorkItemEventQueue : public FxEventQueue {
FxWorkItemEventQueue(
__in UCHAR QueueDepth
);
~FxWorkItemEventQueue();
_Must_inspect_result_
NTSTATUS
Init(
__inout FxPkgPnp* Pnp,
__in PFN_PNP_EVENT_WORKER WorkerRoutine,
__in PVOID WorkerContext = NULL
);
VOID
QueueToThread(
VOID
)
{
if (QueueToThreadWorker()) {
QueueWorkItem();
}
}
protected:
VOID
QueueWorkItem(
VOID
);
static
MX_WORKITEM_ROUTINE
_WorkItemCallback;
MxWorkItem m_WorkItem;
};
//
// struct that encapsulates posting a work item to the dedicated power thread
// or work item depending on the power pagable status of the stack.
//
struct FxThreadedEventQueue : public FxEventQueue {
FxThreadedEventQueue(
__in UCHAR QueueDepth
);
~FxThreadedEventQueue(
VOID
);
_Must_inspect_result_
NTSTATUS
Init(
__inout FxPkgPnp* Pnp,
__in PFN_PNP_EVENT_WORKER WorkerRoutine,
__in PVOID WorkerContext = NULL
);
VOID
QueueToThread(
VOID
)
{
if (QueueToThreadWorker()) {
QueueWorkItem();
}
}
protected:
static
WORKER_THREAD_ROUTINE
_WorkerThreadRoutine;
static
MX_WORKITEM_ROUTINE
_WorkItemCallback;
VOID
QueueWorkItem(
VOID
);
MxWorkItem m_WorkItem;
// work item used to queue to the thread
WORK_QUEUE_ITEM m_EventWorkQueueItem;
};
#endif // _FXEVENTQUEUE_H_