[KS]
[reactos.git] / reactos / drivers / ksfilter / ks / bag.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/ksfilter/ks/bag.c
5 * PURPOSE: KS Object Bag functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "precomp.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 typedef struct
15 {
16 LIST_ENTRY Entry;
17 PVOID Item;
18 PFNKSFREE Free;
19 ULONG References;
20 }KSIOBJECT_BAG_ENTRY, *PKSIOBJECT_BAG_ENTRY;
21
22
23 /*
24 @implemented
25 */
26 KSDDKAPI
27 NTSTATUS
28 NTAPI
29 KsAllocateObjectBag(
30 IN PKSDEVICE Device,
31 OUT KSOBJECT_BAG* ObjectBag)
32 {
33 PKSIDEVICE_HEADER DeviceHeader;
34 PKSIOBJECT_BAG Bag;
35 IKsDevice *KsDevice;
36
37 /* get real device header */
38 DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
39
40 /* allocate a object bag ctx */
41 Bag = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG));
42 if (!Bag)
43 return STATUS_INSUFFICIENT_RESOURCES;
44
45 /* get device interface */
46 KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
47
48 /* initialize object bag */
49 return KsDevice->lpVtbl->InitializeObjectBag(KsDevice, Bag, NULL);
50 }
51
52 PKSIOBJECT_BAG_ENTRY
53 KspFindObjectBagItem(
54 IN PLIST_ENTRY ObjectList,
55 IN PVOID Item)
56 {
57 PLIST_ENTRY Entry;
58 PKSIOBJECT_BAG_ENTRY BagEntry;
59
60 /* point to first item */
61 Entry = ObjectList->Flink;
62 /* first scan the list if the item is already inserted */
63 while(Entry != ObjectList)
64 {
65 /* get bag entry */
66 BagEntry = (PKSIOBJECT_BAG_ENTRY)CONTAINING_RECORD(Entry, KSIOBJECT_BAG_ENTRY, Entry);
67
68 if (BagEntry->Item == Item)
69 {
70 /* found entry */
71 return BagEntry;
72 }
73 /* move to next entry */
74 Entry = Entry->Flink;
75 }
76 /* item not in this object bag */
77 return NULL;
78 }
79
80
81 /*
82 @implemented
83 */
84 NTSTATUS
85 NTAPI
86 KsAddItemToObjectBag(
87 IN KSOBJECT_BAG ObjectBag,
88 IN PVOID Item,
89 IN PFNKSFREE Free OPTIONAL)
90 {
91 PKSIOBJECT_BAG Bag;
92 PKSIOBJECT_BAG_ENTRY BagEntry;
93
94 DPRINT("KsAddItemToObjectBag\n");
95
96 /* get real object bag */
97 Bag = (PKSIOBJECT_BAG)ObjectBag;
98
99 /* acquire bag mutex */
100 KeWaitForSingleObject(Bag->BagMutex, Executive, KernelMode, FALSE, NULL);
101
102 /* is the item already present in this object bag */
103 BagEntry = KspFindObjectBagItem(&Bag->ObjectList, Item);
104
105 if (BagEntry)
106 {
107 /* is is, update reference count */
108 InterlockedIncrement((PLONG)&BagEntry->References);
109 /* release mutex */
110 KeReleaseMutex(Bag->BagMutex, FALSE);
111 /* return result */
112 return STATUS_SUCCESS;
113 }
114
115 /* item is new, allocate entry */
116 BagEntry = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG_ENTRY));
117 if (!BagEntry)
118 {
119 /* no memory */
120 KeReleaseMutex(Bag->BagMutex, FALSE);
121 /* return result */
122 return STATUS_INSUFFICIENT_RESOURCES;
123 }
124
125 /* initialize bag entry */
126 BagEntry->References = 1;
127 BagEntry->Item = Item;
128 if (Free)
129 BagEntry->Free = Free;
130 else
131 BagEntry->Free = ExFreePool;
132
133 /* insert item */
134 InsertTailList(&Bag->ObjectList, &BagEntry->Entry);
135
136 /* release mutex */
137 KeReleaseMutex(Bag->BagMutex, FALSE);
138
139 /* done */
140 return STATUS_SUCCESS;
141 }
142
143 ULONG
144 KspGetObjectItemReferenceCount(
145 IN PKSIDEVICE_HEADER DeviceHeader,
146 IN PVOID Item)
147 {
148 PLIST_ENTRY Entry;
149 PKSIOBJECT_BAG OtherBag;
150 PKSIOBJECT_BAG_ENTRY OtherBagEntry;
151 ULONG TotalRefs = 0;
152
153 /* scan all object bags and see if item is present there */
154 Entry = DeviceHeader->ObjectBags.Flink;
155 while(Entry != &DeviceHeader->ObjectBags)
156 {
157 /* get other bag */
158 OtherBag = (PKSIOBJECT_BAG)CONTAINING_RECORD(Entry, KSIOBJECT_BAG, Entry);
159
160 /* is the item present there */
161 OtherBagEntry = KspFindObjectBagItem(&OtherBag->ObjectList, Item);
162
163 if (OtherBagEntry)
164 TotalRefs++;
165
166 /* move to next item */
167 Entry = Entry->Flink;
168 }
169
170 return TotalRefs;
171 }
172
173 /*
174 @implemented
175 */
176 KSDDKAPI
177 ULONG
178 NTAPI
179 KsRemoveItemFromObjectBag(
180 IN KSOBJECT_BAG ObjectBag,
181 IN PVOID Item,
182 IN BOOLEAN Free)
183 {
184 PKSIOBJECT_BAG Bag;
185 PKSIOBJECT_BAG_ENTRY BagEntry;
186 ULONG TotalRefs;
187
188 /* get real object bag */
189 Bag = (PKSIOBJECT_BAG)ObjectBag;
190
191 /* acquire bag mutex */
192 KeWaitForSingleObject(Bag->BagMutex, Executive, KernelMode, FALSE, NULL);
193
194 /* is the item already present in this object bag */
195 BagEntry = KspFindObjectBagItem(&Bag->ObjectList, Item);
196
197 if (!BagEntry)
198 {
199 /* item was not in this object bag */
200 KeReleaseMutex(Bag->BagMutex, FALSE);
201 return 0;
202 }
203
204 /* set current refs count */
205 TotalRefs = BagEntry->References;
206
207 /* get total refs count */
208 TotalRefs += KspGetObjectItemReferenceCount((PKSIDEVICE_HEADER)Bag->DeviceHeader, Item);
209
210 /* decrease reference count */
211 InterlockedDecrement((PLONG)&BagEntry->References);
212
213 if (BagEntry->References == 0)
214 {
215 /* remove the entry */
216 RemoveEntryList(&BagEntry->Entry);
217 }
218
219 if (TotalRefs == 1)
220 {
221 /* does the caller want to free the item */
222 if (Free)
223 {
224 /* free the item */
225 BagEntry->Free(BagEntry->Item);
226 }
227 }
228 if (BagEntry->References == 0)
229 {
230 /* free bag item entry */
231 FreeItem(BagEntry);
232 }
233
234 /* release mutex */
235 KeReleaseMutex(Bag->BagMutex, FALSE);
236
237
238 return TotalRefs;
239 }
240
241 /*
242 @implemented
243 */
244 KSDDKAPI
245 NTSTATUS
246 NTAPI
247 KsCopyObjectBagItems(
248 IN KSOBJECT_BAG ObjectBagDestination,
249 IN KSOBJECT_BAG ObjectBagSource)
250 {
251 PKSIOBJECT_BAG ObjectBagDest, ObjectBagSrc;
252 PLIST_ENTRY Entry;
253 PKSIOBJECT_BAG_ENTRY BagEntry;
254 NTSTATUS Status = STATUS_SUCCESS;
255
256 /* get object bag src */
257 ObjectBagSrc = (PKSIOBJECT_BAG)ObjectBagSource;
258
259 /* get object bag dst */
260 ObjectBagDest = (PKSIOBJECT_BAG)ObjectBagDestination;
261
262 /* acquire source mutex */
263 KeWaitForSingleObject(ObjectBagSrc->BagMutex, Executive, KernelMode, FALSE, NULL);
264
265 if (ObjectBagSrc->BagMutex != ObjectBagDest->BagMutex)
266 {
267 /* acquire destination mutex */
268 KeWaitForSingleObject(ObjectBagDest->BagMutex, Executive, KernelMode, FALSE, NULL);
269 }
270
271 /* point to first item */
272 Entry = ObjectBagSrc->ObjectList.Flink;
273 /* first scan the list if the item is already inserted */
274 while(Entry != &ObjectBagSrc->ObjectList)
275 {
276 /* get bag entry */
277 BagEntry = (PKSIOBJECT_BAG_ENTRY)CONTAINING_RECORD(Entry, KSIOBJECT_BAG_ENTRY, Entry);
278
279 /* add the item */
280 Status = KsAddItemToObjectBag(ObjectBagDestination, BagEntry->Item, BagEntry->Free);
281
282 /* check for success */
283 if (!NT_SUCCESS(Status))
284 break;
285
286 /* move to next entry */
287 Entry = Entry->Flink;
288 }
289
290 if (ObjectBagSrc->BagMutex != ObjectBagDest->BagMutex)
291 {
292 /* release destination mutex */
293 KeReleaseMutex(ObjectBagDest->BagMutex, FALSE);
294 }
295
296 /* release source mutex */
297 KeReleaseMutex(ObjectBagSrc->BagMutex, FALSE);
298
299 return Status;
300 }
301
302 /*
303 @implemented
304 */
305 KSDDKAPI
306 VOID
307 NTAPI
308 KsFreeObjectBag(
309 IN KSOBJECT_BAG ObjectBag)
310 {
311 PLIST_ENTRY Entry;
312 PKSIOBJECT_BAG Bag;
313 PKSIOBJECT_BAG_ENTRY BagEntry;
314 ULONG TotalRefs;
315
316 /* get real object bag */
317 Bag = (PKSIOBJECT_BAG)ObjectBag;
318
319 /* acquire bag mutex */
320 KeWaitForSingleObject(Bag->BagMutex, Executive, KernelMode, FALSE, NULL);
321
322 while(!IsListEmpty(&Bag->ObjectList))
323 {
324 /* get an bag entry */
325 Entry = RemoveHeadList(&Bag->ObjectList);
326 /* access bag entry item */
327 BagEntry = (PKSIOBJECT_BAG_ENTRY)CONTAINING_RECORD(Entry, KSIOBJECT_BAG, Entry);
328
329 /* check if the item is present in some other bag */
330 TotalRefs = KspGetObjectItemReferenceCount((PKSIDEVICE_HEADER)Bag->DeviceHeader, &BagEntry->Item);
331
332 if (TotalRefs == 0)
333 {
334 /* item is ready to be freed */
335 BagEntry->Free(BagEntry->Item);
336 }
337
338 /* free bag entry item */
339 FreeItem(BagEntry);
340 }
341
342 /* remove bag entry from device object list */
343 RemoveEntryList(&Bag->Entry);
344
345 /* release bag mutex */
346 KeReleaseMutex(Bag->BagMutex, FALSE);
347
348 /* now free object bag */
349 FreeItem(Bag);
350 }
351
352 /*
353 @implemented
354 */
355 KSDDKAPI
356 NTSTATUS
357 NTAPI
358 _KsEdit(
359 IN KSOBJECT_BAG ObjectBag,
360 IN OUT PVOID* PointerToPointerToItem,
361 IN ULONG NewSize,
362 IN ULONG OldSize,
363 IN ULONG Tag)
364 {
365 PKSIOBJECT_BAG Bag;
366 PKSIOBJECT_BAG_ENTRY BagEntry;
367 PVOID Item;
368 NTSTATUS Status;
369
370 DPRINT("_KsEdit\n");
371
372 /* get real object bag */
373 Bag = (PKSIOBJECT_BAG)ObjectBag;
374
375 /* acquire bag mutex */
376 KeWaitForSingleObject(Bag->BagMutex, Executive, KernelMode, FALSE, NULL);
377
378
379 if (*PointerToPointerToItem)
380 {
381 /* search object bag for this entry */
382 BagEntry = KspFindObjectBagItem(&Bag->ObjectList, *PointerToPointerToItem);
383 }
384 else
385 {
386 /* pointer to null, allocate new entry */
387 BagEntry = NULL;
388 }
389
390 if (!BagEntry || NewSize > OldSize)
391 {
392 /* entry does not exist or new entry must be allocated */
393 Item = AllocateItem(NonPagedPool, NewSize);
394
395 if (!Item)
396 {
397 /* not enough resources */
398 KeReleaseMutex(Bag->BagMutex, FALSE);
399 return STATUS_INSUFFICIENT_RESOURCES;
400 }
401
402 /* now add the item to the object bag */
403 Status = KsAddItemToObjectBag((KSOBJECT_BAG)Bag, Item, NULL);
404 /* check for success */
405 if (!NT_SUCCESS(Status))
406 {
407 /* failed to add item */
408 FreeItem(Item);
409 KeReleaseMutex(Bag->BagMutex, FALSE);
410 return Status;
411 }
412
413 if (*PointerToPointerToItem)
414 {
415 /* object exists */
416 if (OldSize >= NewSize)
417 {
418 /* copy old contents */
419 RtlMoveMemory(Item, *PointerToPointerToItem, NewSize);
420 }
421 else
422 {
423 /* copy new contents */
424 RtlMoveMemory(Item, *PointerToPointerToItem, OldSize);
425 }
426 }
427
428 if (BagEntry)
429 {
430 /* remove old entry */
431 KsRemoveItemFromObjectBag(ObjectBag, BagEntry->Item, TRUE);
432 }
433
434 /* store item */
435 *PointerToPointerToItem = Item;
436 }
437
438 /* release bag mutex */
439 KeReleaseMutex(Bag->BagMutex, FALSE);
440
441 return STATUS_SUCCESS;
442 }
443
444