2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/ksfilter/ks/worker.c
5 * PURPOSE: KS Allocator functions
6 * PROGRAMMER: Johannes Anderwald
14 /* ===============================================================
15 Worker Management Functions
20 WORK_QUEUE_ITEM WorkItem
;
26 LONG QueuedWorkItemCount
;
27 LIST_ENTRY QueuedWorkItems
;
29 PWORK_QUEUE_ITEM CountedWorkItem
;
30 }KSIWORKER
, *PKSIWORKER
;
39 PWORK_QUEUE_ITEM WorkItem
;
43 /* get ks worker implementation */
44 KsWorker
= (PKSIWORKER
)Context
;
46 /* acquire back the lock */
47 KeAcquireSpinLock(&KsWorker
->Lock
, &OldLevel
);
52 ASSERT(!IsListEmpty(&KsWorker
->QueuedWorkItems
));
54 /* remove first entry */
55 Entry
= RemoveHeadList(&KsWorker
->QueuedWorkItems
);
56 /* get offset to work item */
57 WorkItem
= (PWORK_QUEUE_ITEM
)CONTAINING_RECORD(Entry
, WORK_QUEUE_ITEM
, List
);
59 /* release lock as the callback might call one KsWorker functions */
60 KeReleaseSpinLock(&KsWorker
->Lock
, OldLevel
);
62 /* now dispatch the work */
63 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
65 /* acquire back the lock */
66 KeAcquireSpinLock(&KsWorker
->Lock
, &OldLevel
);
68 /* decrement queued work item count */
69 InterlockedDecrement(&KsWorker
->QueuedWorkItemCount
);
71 }while(KsWorker
->QueuedWorkItemCount
);
73 /* release the lock */
74 KeReleaseSpinLock(&KsWorker
->Lock
, OldLevel
);
76 /* signal completion event */
77 KeSetEvent(&KsWorker
->Event
, IO_NO_INCREMENT
, FALSE
);
89 IN WORK_QUEUE_TYPE WorkQueueType
,
90 OUT PKSWORKER
* Worker
)
95 if (WorkQueueType
!= CriticalWorkQueue
&&
96 WorkQueueType
!= DelayedWorkQueue
&&
97 WorkQueueType
!= HyperCriticalWorkQueue
)
99 return STATUS_INVALID_PARAMETER
;
102 /* allocate worker context */
103 KsWorker
= AllocateItem(NonPagedPool
, sizeof(KSIWORKER
));
105 return STATUS_INSUFFICIENT_RESOURCES
;
107 /* initialize the work ctx */
108 ExInitializeWorkItem(&KsWorker
->WorkItem
, WorkItemRoutine
, (PVOID
)KsWorker
);
110 KsWorker
->Type
= WorkQueueType
;
111 /* Initialize work item queue */
112 InitializeListHead(&KsWorker
->QueuedWorkItems
);
113 /* initialize work item lock */
114 KeInitializeSpinLock(&KsWorker
->Lock
);
115 /* initialize event */
116 KeInitializeEvent(&KsWorker
->Event
, NotificationEvent
, FALSE
);
119 return STATUS_SUCCESS
;
137 /* get ks worker implementation */
138 KsWorker
= (PKSIWORKER
)Worker
;
139 /* acquire spinlock */
140 KeAcquireSpinLock(&KsWorker
->Lock
, &OldIrql
);
141 /* fake status running to avoid work items to be queued by the counted worker */
142 KsWorker
->Counter
= 1;
143 /* is there currently a work item active */
144 if (KsWorker
->QueuedWorkItemCount
)
146 /* release the lock */
147 KeReleaseSpinLock(&KsWorker
->Lock
, OldIrql
);
148 /* wait for the worker routine to finish */
149 KeWaitForSingleObject(&KsWorker
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
153 /* no work item active, just release the lock */
154 KeReleaseSpinLock(&KsWorker
->Lock
, OldIrql
);
156 /* free worker context */
166 KsRegisterCountedWorker(
167 IN WORK_QUEUE_TYPE WorkQueueType
,
168 IN PWORK_QUEUE_ITEM CountedWorkItem
,
169 OUT PKSWORKER
* Worker
)
174 /* check for counted work item parameter */
175 if (!CountedWorkItem
)
176 return STATUS_INVALID_PARAMETER_2
;
178 /* create the work ctx */
179 Status
= KsRegisterWorker(WorkQueueType
, Worker
);
180 /* check for success */
181 if (NT_SUCCESS(Status
))
183 /* get ks worker implementation */
184 KsWorker
= *(PKSIWORKER
*)Worker
;
185 /* store counted work item */
186 KsWorker
->CountedWorkItem
= CountedWorkItem
;
198 KsDecrementCountedWorker(
204 /* did the caller pass a work ctx */
206 return STATUS_INVALID_PARAMETER
;
208 /* get ks worker implementation */
209 KsWorker
= (PKSIWORKER
)Worker
;
210 /* decrement counter */
211 Counter
= InterlockedDecrement(&KsWorker
->Counter
);
222 KsIncrementCountedWorker(
228 /* did the caller pass a work ctx */
230 return STATUS_INVALID_PARAMETER
;
232 /* get ks worker implementation */
233 KsWorker
= (PKSIWORKER
)Worker
;
234 /* increment counter */
235 Counter
= InterlockedIncrement(&KsWorker
->Counter
);
238 /* this is the first work item in list, so queue a real work item */
239 KsQueueWorkItem(Worker
, KsWorker
->CountedWorkItem
);
242 /* return current counter */
254 IN PWORK_QUEUE_ITEM WorkItem
)
259 /* check for all parameters */
260 if (!Worker
|| !WorkItem
)
261 return STATUS_INVALID_PARAMETER
;
263 /* get ks worker implementation */
264 KsWorker
= (PKSIWORKER
)Worker
;
265 /* lock the work queue */
266 KeAcquireSpinLock(&KsWorker
->Lock
, &OldIrql
);
267 /* insert work item to list */
268 InsertTailList(&KsWorker
->QueuedWorkItems
, &WorkItem
->List
);
269 /* increment active count */
270 InterlockedIncrement(&KsWorker
->QueuedWorkItemCount
);
271 /* is this the first work item */
272 if (KsWorker
->QueuedWorkItemCount
== 1)
275 KeClearEvent(&KsWorker
->Event
);
276 /* it is, queue it */
277 ExQueueWorkItem(&KsWorker
->WorkItem
, KsWorker
->Type
);
280 KeReleaseSpinLock(&KsWorker
->Lock
, OldIrql
);
282 return STATUS_SUCCESS
;