Sync to trunk r38200
[reactos.git] / reactos / drivers / ksfilter / ks / worker.c
1 /* ===============================================================
2 Worker Management Functions
3 */
4
5 #include <ntddk.h>
6 #include <debug.h>
7 #include <ks.h>
8
9
10 typedef struct
11 {
12 KEVENT Event;
13 KSPIN_LOCK Lock;
14 WORK_QUEUE_TYPE Type;
15 LONG Counter;
16 PWORK_QUEUE_ITEM WorkItem;
17 ULONG WorkItemActive;
18 ULONG DeleteInProgress;
19 }KS_WORKER;
20
21 /*
22 @implemented
23 */
24 KSDDKAPI
25 NTSTATUS
26 NTAPI
27 KsRegisterWorker(
28 IN WORK_QUEUE_TYPE WorkQueueType,
29 OUT PKSWORKER* Worker)
30 {
31 KS_WORKER * KsWorker;
32 UNIMPLEMENTED;
33
34 if (WorkQueueType != CriticalWorkQueue &&
35 WorkQueueType != DelayedWorkQueue &&
36 WorkQueueType != HyperCriticalWorkQueue)
37 {
38 return STATUS_INVALID_PARAMETER;
39 }
40
41 KsWorker = ExAllocatePoolWithTag(NonPagedPool, sizeof(KS_WORKER), 0);
42 if (!KsWorker)
43 return STATUS_INSUFFICIENT_RESOURCES;
44
45 KsWorker->Type = WorkQueueType;
46 KsWorker->Counter = 0;
47 KsWorker->WorkItemActive = 0;
48 KsWorker->WorkItem = NULL;
49 KsWorker->DeleteInProgress = TRUE;
50 KeInitializeSpinLock(&KsWorker->Lock);
51 KeInitializeEvent(&KsWorker->Event, NotificationEvent, FALSE);
52
53 *Worker = KsWorker;
54 return STATUS_SUCCESS;
55 }
56
57 /*
58 @implemented
59 */
60 KSDDKAPI VOID NTAPI
61 KsUnregisterWorker(
62 IN PKSWORKER Worker)
63 {
64 KS_WORKER * KsWorker;
65 KIRQL OldIrql;
66 ULONG bWait = FALSE;
67
68 if (!Worker)
69 return;
70
71 KsWorker = (KS_WORKER *)Worker;
72
73 KsWorker->DeleteInProgress = TRUE;
74
75 if (KsWorker->WorkItemActive)
76 {
77 KeReleaseSpinLock(&KsWorker->Lock, OldIrql);
78 KeWaitForSingleObject(&KsWorker->Event, Executive, KernelMode, FALSE, NULL);
79 }
80 else
81 {
82 KeReleaseSpinLock(&KsWorker->Lock, OldIrql);
83 }
84
85 ExFreePoolWithTag(KsWorker, 0);
86 }
87
88 /*
89 @implemented
90 */
91 KSDDKAPI NTSTATUS NTAPI
92 KsRegisterCountedWorker(
93 IN WORK_QUEUE_TYPE WorkQueueType,
94 IN PWORK_QUEUE_ITEM CountedWorkItem,
95 OUT PKSWORKER* Worker)
96 {
97 NTSTATUS Status;
98 KS_WORKER * KsWorker;
99
100 Status = KsRegisterWorker(WorkQueueType, Worker);
101
102 if (NT_SUCCESS(Status))
103 {
104 KsWorker = (KS_WORKER *)Worker;
105 KsWorker->WorkItem = CountedWorkItem;
106 }
107
108 return Status;
109 }
110
111 /*
112 @implemented
113 */
114 KSDDKAPI
115 ULONG
116 NTAPI
117 KsDecrementCountedWorker(
118 IN PKSWORKER Worker)
119 {
120 KS_WORKER * KsWorker;
121 LONG Counter;
122
123 if (!Worker)
124 return STATUS_INVALID_PARAMETER;
125
126 KsWorker = (KS_WORKER *)Worker;
127 Counter = InterlockedDecrement(&KsWorker->Counter);
128
129 if (KsWorker->DeleteInProgress)
130 {
131 /* signal that we are done */
132 KeSetEvent(&KsWorker->Event, 0, 0);
133 }
134
135 return Counter;
136 }
137
138 /*
139 @implemented
140 */
141 KSDDKAPI
142 ULONG
143 NTAPI
144 KsIncrementCountedWorker(
145 IN PKSWORKER Worker)
146 {
147 KS_WORKER * KsWorker;
148 LONG Counter;
149
150 if (!Worker)
151 return STATUS_INVALID_PARAMETER;
152
153 KsWorker = (KS_WORKER *)Worker;
154
155 Counter = InterlockedIncrement(&KsWorker->Counter);
156 if (Counter == 1)
157 {
158 KsQueueWorkItem(Worker, KsWorker->WorkItem);
159 }
160 return Counter;
161 }
162
163 /*
164 @implemented
165 */
166 KSDDKAPI
167 NTSTATUS
168 NTAPI
169 KsQueueWorkItem(
170 IN PKSWORKER Worker,
171 IN PWORK_QUEUE_ITEM WorkItem)
172 {
173 KS_WORKER * KsWorker;
174 KIRQL OldIrql;
175 NTSTATUS Status = STATUS_SUCCESS;
176
177 if (!Worker || !WorkItem)
178 return STATUS_INVALID_PARAMETER;
179
180 KsWorker = (KS_WORKER *)Worker;
181 KeAcquireSpinLock(&KsWorker->Lock, &OldIrql);
182
183 if (!KsWorker->DeleteInProgress)
184 {
185 ExQueueWorkItem(WorkItem, KsWorker->Type);
186 Status = STATUS_UNSUCCESSFUL;
187 }
188
189 KeReleaseSpinLock(&KsWorker->Lock, OldIrql);
190 return Status;
191 }