2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/ksfilter/ks/event.c
5 * PURPOSE: KS Event functions
6 * PROGRAMMER: Johannes Anderwald
12 KspSynchronizedEventRoutine(
13 IN KSEVENTS_LOCKTYPE EventsFlags
,
15 IN PKSEVENT_SYNCHRONIZED_ROUTINE SynchronizedRoutine
,
18 BOOLEAN Result
= FALSE
;
21 if (EventsFlags
== KSEVENTS_NONE
)
23 /* no synchronization required */
24 Result
= SynchronizedRoutine(Ctx
);
26 else if (EventsFlags
== KSEVENTS_SPINLOCK
)
29 KeAcquireSpinLock((PKSPIN_LOCK
)EventsLock
, &OldLevel
);
30 Result
= SynchronizedRoutine(Ctx
);
31 KeReleaseSpinLock((PKSPIN_LOCK
)EventsLock
, OldLevel
);
33 else if (EventsFlags
== KSEVENTS_MUTEX
)
36 KeWaitForSingleObject(EventsLock
, Executive
, KernelMode
, FALSE
, NULL
);
37 Result
= SynchronizedRoutine(Ctx
);
38 KeReleaseMutex((PRKMUTEX
)EventsLock
, FALSE
);
40 else if (EventsFlags
== KSEVENTS_FMUTEX
)
42 /* use a fast mutex */
43 ExAcquireFastMutex((PFAST_MUTEX
)EventsLock
);
44 Result
= SynchronizedRoutine(Ctx
);
45 ExReleaseFastMutex((PFAST_MUTEX
)EventsLock
);
47 else if (EventsFlags
== KSEVENTS_FMUTEXUNSAFE
)
49 /* acquire fast mutex unsafe */
50 KeEnterCriticalRegion();
51 ExAcquireFastMutexUnsafe((PFAST_MUTEX
)EventsLock
);
52 Result
= SynchronizedRoutine(Ctx
);
53 ExReleaseFastMutexUnsafe((PFAST_MUTEX
)EventsLock
);
54 KeLeaveCriticalRegion();
56 else if (EventsFlags
== KSEVENTS_INTERRUPT
)
58 /* use interrupt for locking */
59 Result
= KeSynchronizeExecution((PKINTERRUPT
)EventsLock
, (PKSYNCHRONIZE_ROUTINE
)SynchronizedRoutine
, (PVOID
)Ctx
);
61 else if (EventsFlags
== KSEVENTS_ERESOURCE
)
63 /* use an eresource */
64 KeEnterCriticalRegion();
65 ExAcquireResourceExclusiveLite((PERESOURCE
)EventsLock
, TRUE
);
66 Result
= SynchronizedRoutine(Ctx
);
67 ExReleaseResourceLite((PERESOURCE
)EventsLock
);
68 KeLeaveCriticalRegion();
79 InsertTailList(Context
->List
, &Context
->EventEntry
->ListEntry
);
86 IN ULONG EventSetsCount
,
87 IN PKSEVENT_SET EventSet
,
88 IN OUT PLIST_ENTRY EventsList OPTIONAL
,
89 IN KSEVENTS_LOCKTYPE EventsFlags OPTIONAL
,
90 IN PVOID EventsLock OPTIONAL
,
91 IN PFNKSALLOCATOR Allocator OPTIONAL
,
92 IN ULONG EventItemSize OPTIONAL
)
94 PIO_STACK_LOCATION IoStack
;
97 PKSEVENT_ITEM EventItem
, FoundEventItem
;
98 PKSEVENTDATA EventData
;
99 PKSEVENT_SET FoundEventSet
;
100 PKSEVENT_ENTRY EventEntry
;
101 ULONG Index
, SubIndex
, Size
;
106 /* get current stack location */
107 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
109 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSEVENT
))
111 /* invalid parameter */
112 return STATUS_NOT_SUPPORTED
;
115 if (Irp
->RequestorMode
== UserMode
)
119 ProbeForRead(IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
, sizeof(KSEVENT
), sizeof(UCHAR
));
120 ProbeForRead(Irp
->UserBuffer
, IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
, sizeof(UCHAR
));
121 RtlMoveMemory(&Event
, IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
, sizeof(KSEVENT
));
122 Status
= STATUS_SUCCESS
;
124 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
126 /* Exception, get the error code */
127 Status
= _SEH2_GetExceptionCode();
131 /* check for success */
132 if (!NT_SUCCESS(Status
))
134 /* failed to probe parameters */
140 /* copy event struct */
141 RtlMoveMemory(&Event
, IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
, sizeof(KSEVENT
));
144 FoundEventItem
= NULL
;
145 FoundEventSet
= NULL
;
148 if (IsEqualGUIDAligned(&Event
.Set
, &GUID_NULL
) && Event
.Id
== 0 && Event
.Flags
== KSEVENT_TYPE_SETSUPPORT
)
151 Irp
->IoStatus
.Information
= sizeof(GUID
) * EventSetsCount
;
152 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(GUID
) * EventSetsCount
)
155 return STATUS_MORE_ENTRIES
;
159 Guid
= (LPGUID
)Irp
->UserBuffer
;
161 // copy property guids from property sets
162 for(Index
= 0; Index
< EventSetsCount
; Index
++)
164 RtlMoveMemory(&Guid
[Index
], EventSet
[Index
].Set
, sizeof(GUID
));
166 return STATUS_SUCCESS
;
169 /* now try to find event set */
170 for(Index
= 0; Index
< EventSetsCount
; Index
++)
172 if (IsEqualGUIDAligned(&Event
.Set
, EventSet
[Index
].Set
))
174 EventItem
= (PKSEVENT_ITEM
)EventSet
[Index
].EventItem
;
177 ASSERT(EventSet
[Index
].EventsCount
);
180 /* now find matching event id */
181 for(SubIndex
= 0; SubIndex
< EventSet
[Index
].EventsCount
; SubIndex
++)
183 if (EventItem
[SubIndex
].EventId
== Event
.Id
)
185 /* found event item */
186 FoundEventItem
= &EventItem
[SubIndex
];
187 FoundEventSet
= &EventSet
[Index
];
199 UNICODE_STRING GuidString
;
201 RtlStringFromGUID(&Event
.Set
, &GuidString
);
203 DPRINT("Guid %S Id %u Flags %x not found\n", GuidString
.Buffer
, Event
.Id
, Event
.Flags
);
204 RtlFreeUnicodeString(&GuidString
);
205 return STATUS_PROPSET_NOT_FOUND
;
210 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< FoundEventItem
->DataInput
)
212 /* buffer too small */
213 DPRINT1("Got %u expected %u\n", IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
, FoundEventItem
->DataInput
);
214 return STATUS_SUCCESS
;
217 if (!FoundEventItem
->AddHandler
&& !EventsList
)
219 /* no add handler and no list to add the new entry to */
220 return STATUS_INVALID_PARAMETER
;
224 EventData
= Irp
->UserBuffer
;
229 if (Irp
->RequestorMode
== UserMode
)
231 if (EventData
->NotificationType
== KSEVENTF_SEMAPHORE_HANDLE
)
233 /* get semaphore object handle */
234 Status
= ObReferenceObjectByHandle(EventData
->SemaphoreHandle
.Semaphore
, SEMAPHORE_MODIFY_STATE
, ExSemaphoreObjectType
, Irp
->RequestorMode
, &Object
, NULL
);
236 if (!NT_SUCCESS(Status
))
238 /* invalid semaphore handle */
239 return STATUS_INVALID_PARAMETER
;
242 else if (EventData
->NotificationType
== KSEVENTF_EVENT_HANDLE
)
244 /* get event object handle */
245 Status
= ObReferenceObjectByHandle(EventData
->EventHandle
.Event
, EVENT_MODIFY_STATE
, ExEventObjectType
, Irp
->RequestorMode
, &Object
, NULL
);
247 if (!NT_SUCCESS(Status
))
249 /* invalid event handle */
250 return STATUS_INVALID_PARAMETER
;
255 /* user mode client can only pass an event or semaphore handle */
256 return STATUS_INVALID_PARAMETER
;
261 if (EventData
->NotificationType
!= KSEVENTF_EVENT_OBJECT
&&
262 EventData
->NotificationType
!= KSEVENTF_SEMAPHORE_OBJECT
&&
263 EventData
->NotificationType
!= KSEVENTF_DPC
&&
264 EventData
->NotificationType
!= KSEVENTF_WORKITEM
&&
265 EventData
->NotificationType
!= KSEVENTF_KSWORKITEM
)
267 /* invalid type requested */
268 return STATUS_INVALID_PARAMETER
;
273 /* calculate request size */
274 Size
= sizeof(KSEVENT_ENTRY
) + FoundEventItem
->ExtraEntryData
;
276 /* do we have an allocator */
279 /* allocate event entry */
280 Status
= Allocator(Irp
, Size
, FALSE
);
282 if (!NT_SUCCESS(Status
))
288 /* assume the caller put it there */
289 EventEntry
= KSEVENT_ENTRY_IRP_STORAGE(Irp
);
294 /* allocate it from nonpaged pool */
295 EventEntry
= AllocateItem(NonPagedPool
, Size
);
300 /* not enough memory */
301 return STATUS_INSUFFICIENT_RESOURCES
;
304 /* zero event entry */
305 RtlZeroMemory(EventEntry
, Size
);
307 /* initialize event entry */
308 EventEntry
->EventData
= EventData
;
309 EventEntry
->NotificationType
= EventData
->NotificationType
;
310 EventEntry
->EventItem
= FoundEventItem
;
311 EventEntry
->EventSet
= FoundEventSet
;
312 EventEntry
->FileObject
= IoStack
->FileObject
;
314 switch(EventEntry
->NotificationType
)
316 case KSEVENTF_EVENT_HANDLE
:
317 EventEntry
->Object
= Object
;
318 EventEntry
->Reserved
= 0;
320 case KSEVENTF_SEMAPHORE_HANDLE
:
321 EventEntry
->Object
= Object
;
322 EventEntry
->SemaphoreAdjustment
= EventData
->SemaphoreHandle
.Adjustment
;
323 EventEntry
->Reserved
= 0;
325 case KSEVENTF_EVENT_OBJECT
:
326 EventEntry
->Object
= EventData
->EventObject
.Event
;
327 EventEntry
->Reserved
= EventData
->EventObject
.Increment
;
329 case KSEVENTF_SEMAPHORE_OBJECT
:
330 EventEntry
->Object
= EventData
->SemaphoreObject
.Semaphore
;
331 EventEntry
->SemaphoreAdjustment
= EventData
->SemaphoreObject
.Adjustment
;
332 EventEntry
->Reserved
= EventData
->SemaphoreObject
.Increment
;
335 EventEntry
->Object
= EventData
->Dpc
.Dpc
;
336 EventData
->Dpc
.ReferenceCount
= 0;
338 case KSEVENTF_WORKITEM
:
339 EventEntry
->Object
= EventData
->WorkItem
.WorkQueueItem
;
340 EventEntry
->BufferItem
= (PKSBUFFER_ITEM
)UlongToPtr(EventData
->WorkItem
.WorkQueueType
);
342 case KSEVENTF_KSWORKITEM
:
343 EventEntry
->Object
= EventData
->KsWorkItem
.KsWorkerObject
;
344 EventEntry
->DpcItem
= (PKSDPC_ITEM
)EventData
->KsWorkItem
.WorkQueueItem
;
347 /* should not happen */
351 if (FoundEventItem
->AddHandler
)
353 /* now add the event */
354 Status
= FoundEventItem
->AddHandler(Irp
, EventData
, EventEntry
);
356 if (!NT_SUCCESS(Status
))
358 /* discard event entry */
359 KsDiscardEvent(EventEntry
);
365 Ctx
.List
= EventsList
;
366 Ctx
.EventEntry
= EventEntry
;
369 (void)KspSynchronizedEventRoutine(EventsFlags
, EventsLock
, SyncAddEvent
, &Ctx
);
371 Status
= STATUS_SUCCESS
;
386 IN ULONG EventSetsCount
,
387 IN KSEVENT_SET
* EventSet
,
388 IN OUT PLIST_ENTRY EventsList OPTIONAL
,
389 IN KSEVENTS_LOCKTYPE EventsFlags OPTIONAL
,
390 IN PVOID EventsLock OPTIONAL
)
392 return KspEnableEvent(Irp
, EventSetsCount
, EventSet
, EventsList
, EventsFlags
, EventsLock
, NULL
, 0);
401 KsEnableEventWithAllocator(
403 IN ULONG EventSetsCount
,
404 IN PKSEVENT_SET EventSet
,
405 IN OUT PLIST_ENTRY EventsList OPTIONAL
,
406 IN KSEVENTS_LOCKTYPE EventsFlags OPTIONAL
,
407 IN PVOID EventsLock OPTIONAL
,
408 IN PFNKSALLOCATOR Allocator OPTIONAL
,
409 IN ULONG EventItemSize OPTIONAL
)
411 return KspEnableEvent(Irp
, EventSetsCount
, EventSet
, EventsList
, EventsFlags
, EventsLock
, Allocator
, EventItemSize
);
419 PIO_STACK_LOCATION IoStack
;
420 PKSEVENTDATA EventData
;
421 PKSEVENT_ENTRY EventEntry
;
424 /* get current irp stack location */
425 IoStack
= IoGetCurrentIrpStackLocation(Ctx
->Irp
);
428 EventData
= (PKSEVENTDATA
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
430 if (!Ctx
|| !Ctx
->List
|| !Ctx
->FileObject
|| !Ctx
->Irp
)
432 /* invalid parameter */
436 /* point to first entry */
437 Entry
= Ctx
->List
->Flink
;
439 while(Entry
!= Ctx
->List
)
441 /* get event entry */
442 EventEntry
= (PKSEVENT_ENTRY
)CONTAINING_RECORD(Entry
, KSEVENT_ENTRY
, ListEntry
);
444 if (EventEntry
->EventData
== EventData
&& EventEntry
->FileObject
== Ctx
->FileObject
)
446 /* found the entry */
447 RemoveEntryList(&EventEntry
->ListEntry
);
448 Ctx
->EventEntry
= EventEntry
;
452 /* move to next item */
453 Entry
= Entry
->Flink
;
455 /* entry not found */
467 IN OUT PLIST_ENTRY EventsList
,
468 IN KSEVENTS_LOCKTYPE EventsFlags
,
471 PIO_STACK_LOCATION IoStack
;
474 /* get current irp stack location */
475 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
477 /* is there a event entry */
478 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSEVENTDATA
))
480 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
== 0)
482 /* caller wants to free event items */
483 KsFreeEventList(IoStack
->FileObject
, EventsList
, EventsFlags
, EventsLock
);
484 return STATUS_SUCCESS
;
486 /* invalid parameter */
487 return STATUS_INVALID_BUFFER_SIZE
;
490 /* setup event ctx */
491 Ctx
.List
= EventsList
;
492 Ctx
.FileObject
= IoStack
->FileObject
;
494 Ctx
.EventEntry
= NULL
;
496 if (KspSynchronizedEventRoutine(EventsFlags
, EventsLock
, KspDisableEvent
, &Ctx
))
498 /* was the event entry found */
502 KsDiscardEvent(Ctx
.EventEntry
);
503 return STATUS_SUCCESS
;
505 /* event was not found */
506 return STATUS_UNSUCCESSFUL
;
509 /* invalid parameters */
510 return STATUS_INVALID_PARAMETER
;
520 IN PKSEVENT_ENTRY EventEntry
)
523 ASSERT(EventEntry
->Object
);
525 if (EventEntry
->NotificationType
== KSEVENTF_SEMAPHORE_HANDLE
|| EventEntry
->NotificationType
== KSEVENTF_EVENT_HANDLE
)
528 ObDereferenceObject(EventEntry
->Object
);
531 /* free event entry */
532 FreeItem(EventEntry
);
542 PKSEVENT_ENTRY EventEntry
;
544 /* check valid input */
545 if (!Ctx
|| !Ctx
->List
)
548 if (IsListEmpty(Ctx
->List
))
551 /* remove first entry */
552 Entry
= RemoveHeadList(Ctx
->List
);
555 /* list is empty, bye-bye */
559 /* get event entry */
560 EventEntry
= (PKSEVENT_ENTRY
)CONTAINING_RECORD(Entry
, KSEVENT_ENTRY
, ListEntry
);
562 /* store event entry */
563 Ctx
->EventEntry
= EventEntry
;
576 IN PFILE_OBJECT FileObject
,
577 IN OUT PLIST_ENTRY EventsList
,
578 IN KSEVENTS_LOCKTYPE EventsFlags
,
583 /* setup event ctx */
584 Ctx
.List
= EventsList
;
585 Ctx
.FileObject
= FileObject
;
586 Ctx
.EventEntry
= NULL
;
588 while(KspSynchronizedEventRoutine(EventsFlags
, EventsLock
, KspFreeEventList
, &Ctx
))
592 KsDiscardEvent(Ctx
.EventEntry
);
605 IN PKSEVENT_ENTRY EntryEvent
)
607 if (EntryEvent
->NotificationType
== KSEVENTF_EVENT_HANDLE
|| EntryEvent
->NotificationType
== KSEVENTF_EVENT_OBJECT
)
610 KeSetEvent(EntryEvent
->Object
, EntryEvent
->Reserved
, FALSE
);
612 else if (EntryEvent
->NotificationType
== KSEVENTF_SEMAPHORE_HANDLE
|| EntryEvent
->NotificationType
== KSEVENTF_SEMAPHORE_OBJECT
)
614 /* release semaphore */
615 KeReleaseSemaphore(EntryEvent
->Object
, EntryEvent
->Reserved
, EntryEvent
->SemaphoreAdjustment
, FALSE
);
617 else if (EntryEvent
->NotificationType
== KSEVENTF_DPC
)
619 /* increment reference count to indicate dpc is pending */
620 InterlockedIncrement((PLONG
)&EntryEvent
->EventData
->Dpc
.ReferenceCount
);
622 KeInsertQueueDpc((PRKDPC
)EntryEvent
->Object
, NULL
, NULL
);
624 else if (EntryEvent
->NotificationType
== KSEVENTF_WORKITEM
)
626 /* queue work item */
627 ExQueueWorkItem((PWORK_QUEUE_ITEM
)EntryEvent
->Object
, PtrToUlong(EntryEvent
->BufferItem
));
629 else if (EntryEvent
->NotificationType
== KSEVENTF_KSWORKITEM
)
631 /* queue work item of ks worker */
632 return KsQueueWorkItem((PKSWORKER
)EntryEvent
->Object
, (PWORK_QUEUE_ITEM
)EntryEvent
->DpcItem
);
636 /* unsupported type requested */
637 return STATUS_INVALID_PARAMETER
;
640 return STATUS_SUCCESS
;
650 IN PKSEVENT_ENTRY EventEntry
,
655 return STATUS_UNSUCCESSFUL
;
665 IN GUID
* Set OPTIONAL
,
667 IN PLIST_ENTRY EventsList
,
668 IN KSEVENTS_LOCKTYPE EventsFlags
,
682 IN PKSEVENT_ENTRY EventEntry
)
684 PKSBASIC_HEADER Header
= (PKSBASIC_HEADER
)((ULONG_PTR
)Object
- sizeof(KSBASIC_HEADER
));
686 ExInterlockedInsertTailList(&Header
->EventList
, &EventEntry
->ListEntry
, &Header
->EventListLock
);
694 KsDefaultAddEventHandler(
696 IN PKSEVENTDATA EventData
,
697 IN OUT PKSEVENT_ENTRY EventEntry
)
699 PIO_STACK_LOCATION IoStack
;
700 PKSIOBJECT_HEADER ObjectHeader
;
701 PKSBASIC_HEADER Header
;
703 /* first get the io stack location */
704 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
706 /* now get the object header */
707 ObjectHeader
=(PKSIOBJECT_HEADER
)IoStack
->FileObject
->FsContext2
;
710 ASSERT(ObjectHeader
->ObjectType
);
712 /* obtain basic header */
713 Header
= (PKSBASIC_HEADER
)((ULONG_PTR
)ObjectHeader
->ObjectType
- sizeof(KSBASIC_HEADER
));
715 /* now insert the event entry */
716 ExInterlockedInsertTailList(&Header
->EventList
, &EventEntry
->ListEntry
, &Header
->EventListLock
);
719 return STATUS_SUCCESS
;
732 IN
const GUID
* EventSet OPTIONAL
,
735 IN PVOID Data OPTIONAL
,
736 IN PFNKSGENERATEEVENTCALLBACK CallBack OPTIONAL
,
737 IN PVOID CallBackContext OPTIONAL
)