summaryrefslogtreecommitdiff
path: root/network/trans/stmedit/sys/LwQueue.c
diff options
context:
space:
mode:
Diffstat (limited to 'network/trans/stmedit/sys/LwQueue.c')
-rw-r--r--network/trans/stmedit/sys/LwQueue.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/network/trans/stmedit/sys/LwQueue.c b/network/trans/stmedit/sys/LwQueue.c
new file mode 100644
index 00000000..a88186c7
--- /dev/null
+++ b/network/trans/stmedit/sys/LwQueue.c
@@ -0,0 +1,170 @@
+/*++
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+ Stream Edit Callout Driver Sample.
+ This file implements Light Weight queues using Worker Item routines.
+
+Environment:
+ Kernel mode
+
+--*/
+
+#include "LwQueue.h"
+
+IO_WORKITEM_ROUTINE LwWorker;
+
+NTSTATUS
+LwInitializeQueue(
+ _In_ PVOID IoObject,
+ _Out_ PLW_QUEUE Queue,
+ _In_ PIO_WORKITEM_ROUTINE WorkerRoutine
+ )
+/*
+ Initializes Light Weight Queue data structures!
+*/
+{
+ RtlZeroMemory(Queue, sizeof(Queue[0]));
+
+ Queue->Head = &Queue->Dummy;
+ Queue->Tail = &Queue->Dummy;
+ Queue->WorkerScheduled = FALSE;
+
+ Queue->WorkerRoutine = WorkerRoutine;
+ Queue->IoObject = IoObject;
+
+ KeInitializeSpinLock(&Queue->Lock);
+
+ Queue->WorkItem =
+ ExAllocatePoolWithTag(
+ NonPagedPool, IoSizeofWorkItem(), STMEDIT_TAG_LQWI);
+
+ if (Queue->WorkItem == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IoInitializeWorkItem(IoObject, Queue->WorkItem);
+ Queue->Initialized = TRUE;
+ return STATUS_SUCCESS;
+}
+
+VOID
+LwUninitializeQueue(
+ _Inout_ PLW_QUEUE Queue
+ )
+/*
+ De-Initializes the Light Weight Queue!
+*/
+{
+ if (Queue->Initialized == FALSE)
+ {
+ return;
+ }
+
+ Queue->Initialized = FALSE;
+
+ IoUninitializeWorkItem(Queue->WorkItem);
+ ExFreePoolWithTag(Queue->WorkItem, STMEDIT_TAG_LQWI);
+ Queue->WorkItem = NULL;
+}
+
+__drv_functionClass(IO_WORKITEM_ROUTINE)
+__drv_requiresIRQL(PASSIVE_LEVEL)
+__drv_sameIRQL
+VOID
+LwWorker(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_opt_ PVOID Context
+ )
+/*
+ Queue processing workitem routine.
+ Drains the task queue and invokes OOB Workitem to process the tasks.
+*/
+{
+ PLW_ENTRY Entry;
+ PLW_QUEUE Queue = (PLW_QUEUE)Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ NT_ASSERT(Queue != NULL);
+ Entry = LwDequeueAll(Queue);
+
+ //
+ // Why were we scheduled if there are no entries?
+ //
+ NT_ASSERT(Entry != NULL);
+
+ while (Entry != NULL)
+ {
+ //
+ // Invoke the caller's worker routine.
+ //
+ Queue->WorkerRoutine(DeviceObject, Entry);
+
+ //
+ // Check if any other entries were added while we were
+ // working.
+ //
+ Entry = LwDequeueAll(Queue);
+ }
+}
+
+VOID
+LwEnqueue(
+ _In_ PLW_QUEUE Queue,
+ _In_ PLW_ENTRY Entry
+ )
+/*
+ Queue a task into the task queue.
+*/
+{
+ KLOCK_QUEUE_HANDLE LockHandle;
+
+ NT_ASSERT(Entry != NULL);
+ NT_ASSERT(Queue != NULL);
+
+ KeAcquireInStackQueuedSpinLock(&Queue->Lock, &LockHandle);
+
+ Entry->Next = NULL;
+ Queue->Tail->Next = Entry;
+ Queue->Tail = Entry;
+
+ if (!Queue->WorkerScheduled)
+ {
+ Queue->WorkerScheduled = TRUE;
+
+ IoQueueWorkItem(
+ Queue->WorkItem, LwWorker, DelayedWorkQueue, Queue);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&LockHandle);
+}
+
+PLW_ENTRY
+LwDequeueAll(
+ _In_ PLW_QUEUE Queue
+ )
+{
+ KLOCK_QUEUE_HANDLE LockHandle;
+ PLW_ENTRY Entry = NULL;
+
+ KeAcquireInStackQueuedSpinLock(&Queue->Lock, &LockHandle);
+
+ NT_ASSERT(Queue->Head == &Queue->Dummy);
+
+ //
+ // Snap and return the entire queue contents.
+ //
+ Entry = Queue->Head->Next;
+ Queue->Head->Next = NULL;
+ Queue->Tail = Queue->Head;
+
+ if (Entry == NULL)
+ {
+ Queue->WorkerScheduled = FALSE;
+ }
+
+ KeReleaseInStackQueuedSpinLock(&LockHandle);
+ return Entry;
+}