1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
/*++
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
--*/
#define POOL_ZERO_DOWN_LEVEL_SUPPORT
#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 =
ExAllocatePool2(
POOL_FLAG_NON_PAGED, 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;
}
|