mirror of
https://github.com/reactos/reactos.git
synced 2025-03-10 10:14:44 +00:00
381 lines
7.2 KiB
C++
381 lines
7.2 KiB
C++
//
|
|
// 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_
|