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
12 /* ===============================================================
13 Worker Management Functions
18 WORK_QUEUE_ITEM WorkItem
;
24 LONG QueuedWorkItemCount
;
25 LIST_ENTRY QueuedWorkItems
;
27 PWORK_QUEUE_ITEM CountedWorkItem
;
28 }KSIWORKER
, *PKSIWORKER
;
37 PWORK_QUEUE_ITEM WorkItem
;
41 /* get ks worker implementation */
42 KsWorker
= (PKSIWORKER
)Context
;
44 /* acquire back the lock */
45 KeAcquireSpinLock(&KsWorker
->Lock
, &OldLevel
);
50 ASSERT(!IsListEmpty(&KsWorker
->QueuedWorkItems
));
52 /* remove first entry */
53 Entry
= RemoveHeadList(&KsWorker
->QueuedWorkItems
);
54 /* get offset to work item */
55 WorkItem
= (PWORK_QUEUE_ITEM
)CONTAINING_RECORD(Entry
, WORK_QUEUE_ITEM
, List
);
57 /* release lock as the callback might call one KsWorker functions */
58 KeReleaseSpinLock(&KsWorker
->Lock
, OldLevel
);
60 /* now dispatch the work */
61 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
63 /* acquire back the lock */
64 KeAcquireSpinLock(&KsWorker
->Lock
, &OldLevel
);
66 /* decrement queued work item count */
67 InterlockedDecrement(&KsWorker
->QueuedWorkItemCount
);
69 }while(KsWorker
->QueuedWorkItemCount
);
71 /* release the lock */
72 KeReleaseSpinLock(&KsWorker
->Lock
, OldLevel
);
74 /* signal completion event */
75 KeSetEvent(&KsWorker
->Event
, IO_NO_INCREMENT
, FALSE
);
87 IN WORK_QUEUE_TYPE WorkQueueType
,
88 OUT PKSWORKER
* Worker
)
93 if (WorkQueueType
!= CriticalWorkQueue
&&
94 WorkQueueType
!= DelayedWorkQueue
&&
95 WorkQueueType
!= HyperCriticalWorkQueue
)
97 return STATUS_INVALID_PARAMETER
;
100 /* allocate worker context */
101 KsWorker
= AllocateItem(NonPagedPool
, sizeof(KSIWORKER
));
103 return STATUS_INSUFFICIENT_RESOURCES
;
105 /* initialze the work ctx */
106 ExInitializeWorkItem(&KsWorker
->WorkItem
, WorkItemRoutine
, (PVOID
)KsWorker
);
108 KsWorker
->Type
= WorkQueueType
;
109 /* Initialize work item queue */
110 InitializeListHead(&KsWorker
->QueuedWorkItems
);
111 /* initialize work item lock */
112 KeInitializeSpinLock(&KsWorker
->Lock
);
113 /* initialize event */
114 KeInitializeEvent(&KsWorker
->Event
, NotificationEvent
, FALSE
);
117 return STATUS_SUCCESS
;
135 /* get ks worker implementation */
136 KsWorker
= (PKSIWORKER
)Worker
;
137 /* acquire spinlock */
138 KeAcquireSpinLock(&KsWorker
->Lock
, &OldIrql
);
139 /* fake status running to avoid work items to be queued by the counted worker */
140 KsWorker
->Counter
= 1;
141 /* is there currently a work item active */
142 if (KsWorker
->QueuedWorkItemCount
)
144 /* release the lock */
145 KeReleaseSpinLock(&KsWorker
->Lock
, OldIrql
);
146 /* wait for the worker routine to finish */
147 KeWaitForSingleObject(&KsWorker
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
151 /* no work item active, just release the lock */
152 KeReleaseSpinLock(&KsWorker
->Lock
, OldIrql
);
154 /* free worker context */
164 KsRegisterCountedWorker(
165 IN WORK_QUEUE_TYPE WorkQueueType
,
166 IN PWORK_QUEUE_ITEM CountedWorkItem
,
167 OUT PKSWORKER
* Worker
)
172 /* check for counted work item parameter */
173 if (!CountedWorkItem
)
174 return STATUS_INVALID_PARAMETER_2
;
176 /* create the work ctx */
177 Status
= KsRegisterWorker(WorkQueueType
, Worker
);
178 /* check for success */
179 if (NT_SUCCESS(Status
))
181 /* get ks worker implementation */
182 KsWorker
= *(PKSIWORKER
*)Worker
;
183 /* store counted work item */
184 KsWorker
->CountedWorkItem
= CountedWorkItem
;
196 KsDecrementCountedWorker(
202 /* did the caller pass a work ctx */
204 return STATUS_INVALID_PARAMETER
;
206 /* get ks worker implementation */
207 KsWorker
= (PKSIWORKER
)Worker
;
208 /* decrement counter */
209 Counter
= InterlockedDecrement(&KsWorker
->Counter
);
220 KsIncrementCountedWorker(
226 /* did the caller pass a work ctx */
228 return STATUS_INVALID_PARAMETER
;
230 /* get ks worker implementation */
231 KsWorker
= (PKSIWORKER
)Worker
;
232 /* increment counter */
233 Counter
= InterlockedIncrement(&KsWorker
->Counter
);
236 /* this is the first work item in list, so queue a real work item */
237 KsQueueWorkItem(Worker
, KsWorker
->CountedWorkItem
);
240 /* return current counter */
252 IN PWORK_QUEUE_ITEM WorkItem
)
257 /* check for all parameters */
258 if (!Worker
|| !WorkItem
)
259 return STATUS_INVALID_PARAMETER
;
261 /* get ks worker implementation */
262 KsWorker
= (PKSIWORKER
)Worker
;
263 /* lock the work queue */
264 KeAcquireSpinLock(&KsWorker
->Lock
, &OldIrql
);
265 /* insert work item to list */
266 InsertTailList(&KsWorker
->QueuedWorkItems
, &WorkItem
->List
);
267 /* increment active count */
268 InterlockedIncrement(&KsWorker
->QueuedWorkItemCount
);
269 /* is this the first work item */
270 if (KsWorker
->QueuedWorkItemCount
== 1)
273 KeClearEvent(&KsWorker
->Event
);
274 /* it is, queue it */
275 ExQueueWorkItem(&KsWorker
->WorkItem
, KsWorker
->Type
);
278 KeReleaseSpinLock(&KsWorker
->Lock
, OldIrql
);
280 return STATUS_SUCCESS
;