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
15 KspSynchronizedEventRoutine(
16 IN KSEVENTS_LOCKTYPE EventsFlags
,
18 IN PKSEVENT_SYNCHRONIZED_ROUTINE SynchronizedRoutine
,
21 BOOLEAN Result
= FALSE
;
24 if (EventsFlags
== KSEVENTS_NONE
)
26 /* no synchronization required */
27 Result
= SynchronizedRoutine(Ctx
);
29 else if (EventsFlags
== KSEVENTS_SPINLOCK
)
32 KeAcquireSpinLock((PKSPIN_LOCK
)EventsLock
, &OldLevel
);
33 Result
= SynchronizedRoutine(Ctx
);
34 KeReleaseSpinLock((PKSPIN_LOCK
)EventsLock
, OldLevel
);
36 else if (EventsFlags
== KSEVENTS_MUTEX
)
39 KeWaitForSingleObject(EventsLock
, Executive
, KernelMode
, FALSE
, NULL
);
40 Result
= SynchronizedRoutine(Ctx
);
41 KeReleaseMutex((PRKMUTEX
)EventsLock
, FALSE
);
43 else if (EventsFlags
== KSEVENTS_FMUTEX
)
45 /* use a fast mutex */
46 ExAcquireFastMutex((PFAST_MUTEX
)EventsLock
);
47 Result
= SynchronizedRoutine(Ctx
);
48 ExReleaseFastMutex((PFAST_MUTEX
)EventsLock
);
50 else if (EventsFlags
== KSEVENTS_FMUTEXUNSAFE
)
52 /* acquire fast mutex unsafe */
53 KeEnterCriticalRegion();
54 ExAcquireFastMutexUnsafe((PFAST_MUTEX
)EventsLock
);
55 Result
= SynchronizedRoutine(Ctx
);
56 ExReleaseFastMutexUnsafe((PFAST_MUTEX
)EventsLock
);
57 KeLeaveCriticalRegion();
59 else if (EventsFlags
== KSEVENTS_INTERRUPT
)
61 /* use interrupt for locking */
62 Result
= KeSynchronizeExecution((PKINTERRUPT
)EventsLock
, (PKSYNCHRONIZE_ROUTINE
)SynchronizedRoutine
, (PVOID
)Ctx
);
64 else if (EventsFlags
== KSEVENTS_ERESOURCE
)
66 /* use an eresource */
67 KeEnterCriticalRegion();
68 ExAcquireResourceExclusiveLite((PERESOURCE
)EventsLock
, TRUE
);
69 Result
= SynchronizedRoutine(Ctx
);
70 ExReleaseResourceLite((PERESOURCE
)EventsLock
);
71 KeLeaveCriticalRegion();
82 InsertTailList(Context
->List
, &Context
->EventEntry
->ListEntry
);
89 IN ULONG EventSetsCount
,
90 IN
const KSEVENT_SET
* EventSet
,
91 IN OUT PLIST_ENTRY EventsList OPTIONAL
,
92 IN KSEVENTS_LOCKTYPE EventsFlags OPTIONAL
,
93 IN PVOID EventsLock OPTIONAL
,
94 IN PFNKSALLOCATOR Allocator OPTIONAL
,
95 IN ULONG EventItemSize OPTIONAL
)
97 PIO_STACK_LOCATION IoStack
;
100 PKSEVENT_ITEM EventItem
, FoundEventItem
;
101 PKSEVENTDATA EventData
;
102 const KSEVENT_SET
*FoundEventSet
;
103 PKSEVENT_ENTRY EventEntry
;
104 ULONG Index
, SubIndex
, Size
;
109 /* get current stack location */
110 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
112 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSEVENT
))
114 /* invalid parameter */
115 return STATUS_NOT_SUPPORTED
;
118 if (Irp
->RequestorMode
== UserMode
)
122 ProbeForRead(IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
, sizeof(KSEVENT
), sizeof(UCHAR
));
123 ProbeForRead(Irp
->UserBuffer
, IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
, sizeof(UCHAR
));
124 RtlMoveMemory(&Event
, IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
, sizeof(KSEVENT
));
125 Status
= STATUS_SUCCESS
;
127 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
129 /* Exception, get the error code */
130 Status
= _SEH2_GetExceptionCode();
134 /* check for success */
135 if (!NT_SUCCESS(Status
))
137 /* failed to probe parameters */
143 /* copy event struct */
144 RtlMoveMemory(&Event
, IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
, sizeof(KSEVENT
));
147 FoundEventItem
= NULL
;
148 FoundEventSet
= NULL
;
151 if (IsEqualGUIDAligned(&Event
.Set
, &GUID_NULL
) && Event
.Id
== 0 && Event
.Flags
== KSEVENT_TYPE_SETSUPPORT
)
154 Irp
->IoStatus
.Information
= sizeof(GUID
) * EventSetsCount
;
155 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(GUID
) * EventSetsCount
)
158 return STATUS_MORE_ENTRIES
;
162 Guid
= (LPGUID
)Irp
->UserBuffer
;
164 // copy property guids from property sets
165 for(Index
= 0; Index
< EventSetsCount
; Index
++)
167 RtlMoveMemory(&Guid
[Index
], EventSet
[Index
].Set
, sizeof(GUID
));
169 return STATUS_SUCCESS
;
172 /* now try to find event set */
173 for(Index
= 0; Index
< EventSetsCount
; Index
++)
175 if (IsEqualGUIDAligned(&Event
.Set
, EventSet
[Index
].Set
))
177 EventItem
= (PKSEVENT_ITEM
)EventSet
[Index
].EventItem
;
180 ASSERT(EventSet
[Index
].EventsCount
);
183 /* now find matching event id */
184 for(SubIndex
= 0; SubIndex
< EventSet
[Index
].EventsCount
; SubIndex
++)
186 if (EventItem
[SubIndex
].EventId
== Event
.Id
)
188 /* found event item */
189 FoundEventItem
= &EventItem
[SubIndex
];
190 FoundEventSet
= &EventSet
[Index
];
202 UNICODE_STRING GuidString
;
204 RtlStringFromGUID(&Event
.Set
, &GuidString
);
206 DPRINT("Guid %S Id %u Flags %x not found\n", GuidString
.Buffer
, Event
.Id
, Event
.Flags
);
207 RtlFreeUnicodeString(&GuidString
);
208 return STATUS_PROPSET_NOT_FOUND
;
213 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< FoundEventItem
->DataInput
)
215 /* buffer too small */
216 DPRINT1("Got %u expected %u\n", IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
, FoundEventItem
->DataInput
);
217 return STATUS_SUCCESS
;
220 if (!FoundEventItem
->AddHandler
&& !EventsList
)
222 /* no add handler and no list to add the new entry to */
223 return STATUS_INVALID_PARAMETER
;
227 EventData
= Irp
->UserBuffer
;
232 if (Irp
->RequestorMode
== UserMode
)
234 if (EventData
->NotificationType
== KSEVENTF_SEMAPHORE_HANDLE
)
236 /* get semaphore object handle */
237 Status
= ObReferenceObjectByHandle(EventData
->SemaphoreHandle
.Semaphore
, SEMAPHORE_MODIFY_STATE
, *ExSemaphoreObjectType
, Irp
->RequestorMode
, &Object
, NULL
);
239 if (!NT_SUCCESS(Status
))
241 /* invalid semaphore handle */
242 return STATUS_INVALID_PARAMETER
;
245 else if (EventData
->NotificationType
== KSEVENTF_EVENT_HANDLE
)
247 /* get event object handle */
248 Status
= ObReferenceObjectByHandle(EventData
->EventHandle
.Event
, EVENT_MODIFY_STATE
, *ExEventObjectType
, Irp
->RequestorMode
, &Object
, NULL
);
250 if (!NT_SUCCESS(Status
))
252 /* invalid event handle */
253 return STATUS_INVALID_PARAMETER
;
258 /* user mode client can only pass an event or semaphore handle */
259 return STATUS_INVALID_PARAMETER
;
264 if (EventData
->NotificationType
!= KSEVENTF_EVENT_OBJECT
&&
265 EventData
->NotificationType
!= KSEVENTF_SEMAPHORE_OBJECT
&&
266 EventData
->NotificationType
!= KSEVENTF_DPC
&&
267 EventData
->NotificationType
!= KSEVENTF_WORKITEM
&&
268 EventData
->NotificationType
!= KSEVENTF_KSWORKITEM
)
270 /* invalid type requested */
271 return STATUS_INVALID_PARAMETER
;
276 /* calculate request size */
277 Size
= sizeof(KSEVENT_ENTRY
) + FoundEventItem
->ExtraEntryData
;
279 /* do we have an allocator */
282 /* allocate event entry */
283 Status
= Allocator(Irp
, Size
, FALSE
);
285 if (!NT_SUCCESS(Status
))
291 /* assume the caller put it there */
292 EventEntry
= KSEVENT_ENTRY_IRP_STORAGE(Irp
);
297 /* allocate it from nonpaged pool */
298 EventEntry
= AllocateItem(NonPagedPool
, Size
);
303 /* not enough memory */
304 return STATUS_INSUFFICIENT_RESOURCES
;
307 /* zero event entry */
308 RtlZeroMemory(EventEntry
, Size
);
310 /* initialize event entry */
311 EventEntry
->EventData
= EventData
;
312 EventEntry
->NotificationType
= EventData
->NotificationType
;
313 EventEntry
->EventItem
= FoundEventItem
;
314 EventEntry
->EventSet
= FoundEventSet
;
315 EventEntry
->FileObject
= IoStack
->FileObject
;
317 switch(EventEntry
->NotificationType
)
319 case KSEVENTF_EVENT_HANDLE
:
320 EventEntry
->Object
= Object
;
321 EventEntry
->Reserved
= 0;
323 case KSEVENTF_SEMAPHORE_HANDLE
:
324 EventEntry
->Object
= Object
;
325 EventEntry
->SemaphoreAdjustment
= EventData
->SemaphoreHandle
.Adjustment
;
326 EventEntry
->Reserved
= 0;
328 case KSEVENTF_EVENT_OBJECT
:
329 EventEntry
->Object
= EventData
->EventObject
.Event
;
330 EventEntry
->Reserved
= EventData
->EventObject
.Increment
;
332 case KSEVENTF_SEMAPHORE_OBJECT
:
333 EventEntry
->Object
= EventData
->SemaphoreObject
.Semaphore
;
334 EventEntry
->SemaphoreAdjustment
= EventData
->SemaphoreObject
.Adjustment
;
335 EventEntry
->Reserved
= EventData
->SemaphoreObject
.Increment
;
338 EventEntry
->Object
= EventData
->Dpc
.Dpc
;
339 EventData
->Dpc
.ReferenceCount
= 0;
341 case KSEVENTF_WORKITEM
:
342 EventEntry
->Object
= EventData
->WorkItem
.WorkQueueItem
;
343 EventEntry
->BufferItem
= (PKSBUFFER_ITEM
)UlongToPtr(EventData
->WorkItem
.WorkQueueType
);
345 case KSEVENTF_KSWORKITEM
:
346 EventEntry
->Object
= EventData
->KsWorkItem
.KsWorkerObject
;
347 EventEntry
->DpcItem
= (PKSDPC_ITEM
)EventData
->KsWorkItem
.WorkQueueItem
;
350 /* should not happen */
354 if (FoundEventItem
->AddHandler
)
356 /* now add the event */
357 Status
= FoundEventItem
->AddHandler(Irp
, EventData
, EventEntry
);
359 if (!NT_SUCCESS(Status
))
361 /* discard event entry */
362 KsDiscardEvent(EventEntry
);
368 Ctx
.List
= EventsList
;
369 Ctx
.EventEntry
= EventEntry
;
372 (void)KspSynchronizedEventRoutine(EventsFlags
, EventsLock
, SyncAddEvent
, &Ctx
);
374 Status
= STATUS_SUCCESS
;
389 IN ULONG EventSetsCount
,
390 IN KSEVENT_SET
* EventSet
,
391 IN OUT PLIST_ENTRY EventsList OPTIONAL
,
392 IN KSEVENTS_LOCKTYPE EventsFlags OPTIONAL
,
393 IN PVOID EventsLock OPTIONAL
)
395 return KspEnableEvent(Irp
, EventSetsCount
, EventSet
, EventsList
, EventsFlags
, EventsLock
, NULL
, 0);
401 _IRQL_requires_max_(PASSIVE_LEVEL
)
405 KsEnableEventWithAllocator(
407 _In_ ULONG EventSetsCount
,
408 _In_reads_(EventSetsCount
) const KSEVENT_SET
* EventSet
,
409 _Inout_opt_ PLIST_ENTRY EventsList
,
410 _In_opt_ KSEVENTS_LOCKTYPE EventsFlags
,
411 _In_opt_ PVOID EventsLock
,
412 _In_opt_ PFNKSALLOCATOR Allocator
,
413 _In_opt_ ULONG EventItemSize
)
415 return KspEnableEvent(Irp
, EventSetsCount
, EventSet
, EventsList
, EventsFlags
, EventsLock
, Allocator
, EventItemSize
);
423 PIO_STACK_LOCATION IoStack
;
424 PKSEVENTDATA EventData
;
425 PKSEVENT_ENTRY EventEntry
;
428 if (!Ctx
|| !Ctx
->List
|| !Ctx
->FileObject
|| !Ctx
->Irp
)
430 /* invalid parameter */
434 /* get current irp stack location */
435 IoStack
= IoGetCurrentIrpStackLocation(Ctx
->Irp
);
438 EventData
= (PKSEVENTDATA
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
440 /* point to first entry */
441 Entry
= Ctx
->List
->Flink
;
443 while(Entry
!= Ctx
->List
)
445 /* get event entry */
446 EventEntry
= (PKSEVENT_ENTRY
)CONTAINING_RECORD(Entry
, KSEVENT_ENTRY
, ListEntry
);
448 if (EventEntry
->EventData
== EventData
&& EventEntry
->FileObject
== Ctx
->FileObject
)
450 /* found the entry */
451 RemoveEntryList(&EventEntry
->ListEntry
);
452 Ctx
->EventEntry
= EventEntry
;
456 /* move to next item */
457 Entry
= Entry
->Flink
;
459 /* entry not found */
471 IN OUT PLIST_ENTRY EventsList
,
472 IN KSEVENTS_LOCKTYPE EventsFlags
,
475 PIO_STACK_LOCATION IoStack
;
478 /* get current irp stack location */
479 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
481 /* is there a event entry */
482 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSEVENTDATA
))
484 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
== 0)
486 /* caller wants to free event items */
487 KsFreeEventList(IoStack
->FileObject
, EventsList
, EventsFlags
, EventsLock
);
488 return STATUS_SUCCESS
;
490 /* invalid parameter */
491 return STATUS_INVALID_BUFFER_SIZE
;
494 /* setup event ctx */
495 Ctx
.List
= EventsList
;
496 Ctx
.FileObject
= IoStack
->FileObject
;
498 Ctx
.EventEntry
= NULL
;
500 if (KspSynchronizedEventRoutine(EventsFlags
, EventsLock
, KspDisableEvent
, &Ctx
))
502 /* was the event entry found */
506 KsDiscardEvent(Ctx
.EventEntry
);
507 return STATUS_SUCCESS
;
509 /* event was not found */
510 return STATUS_UNSUCCESSFUL
;
513 /* invalid parameters */
514 return STATUS_INVALID_PARAMETER
;
524 IN PKSEVENT_ENTRY EventEntry
)
527 ASSERT(EventEntry
->Object
);
529 if (EventEntry
->NotificationType
== KSEVENTF_SEMAPHORE_HANDLE
|| EventEntry
->NotificationType
== KSEVENTF_EVENT_HANDLE
)
532 ObDereferenceObject(EventEntry
->Object
);
535 /* free event entry */
536 FreeItem(EventEntry
);
546 PKSEVENT_ENTRY EventEntry
;
548 /* check valid input */
549 if (!Ctx
|| !Ctx
->List
)
552 if (IsListEmpty(Ctx
->List
))
555 /* remove first entry */
556 Entry
= RemoveHeadList(Ctx
->List
);
559 /* list is empty, bye-bye */
563 /* get event entry */
564 EventEntry
= (PKSEVENT_ENTRY
)CONTAINING_RECORD(Entry
, KSEVENT_ENTRY
, ListEntry
);
566 /* store event entry */
567 Ctx
->EventEntry
= EventEntry
;
580 IN PFILE_OBJECT FileObject
,
581 IN OUT PLIST_ENTRY EventsList
,
582 IN KSEVENTS_LOCKTYPE EventsFlags
,
587 /* setup event ctx */
588 Ctx
.List
= EventsList
;
589 Ctx
.FileObject
= FileObject
;
590 Ctx
.EventEntry
= NULL
;
592 while(KspSynchronizedEventRoutine(EventsFlags
, EventsLock
, KspFreeEventList
, &Ctx
))
596 KsDiscardEvent(Ctx
.EventEntry
);
609 IN PKSEVENT_ENTRY EntryEvent
)
611 if (EntryEvent
->NotificationType
== KSEVENTF_EVENT_HANDLE
|| EntryEvent
->NotificationType
== KSEVENTF_EVENT_OBJECT
)
614 KeSetEvent(EntryEvent
->Object
, EntryEvent
->Reserved
, FALSE
);
616 else if (EntryEvent
->NotificationType
== KSEVENTF_SEMAPHORE_HANDLE
|| EntryEvent
->NotificationType
== KSEVENTF_SEMAPHORE_OBJECT
)
618 /* release semaphore */
619 KeReleaseSemaphore(EntryEvent
->Object
, EntryEvent
->Reserved
, EntryEvent
->SemaphoreAdjustment
, FALSE
);
621 else if (EntryEvent
->NotificationType
== KSEVENTF_DPC
)
623 /* increment reference count to indicate dpc is pending */
624 InterlockedIncrement((PLONG
)&EntryEvent
->EventData
->Dpc
.ReferenceCount
);
626 KeInsertQueueDpc((PRKDPC
)EntryEvent
->Object
, NULL
, NULL
);
628 else if (EntryEvent
->NotificationType
== KSEVENTF_WORKITEM
)
630 /* queue work item */
631 ExQueueWorkItem((PWORK_QUEUE_ITEM
)EntryEvent
->Object
, PtrToUlong(EntryEvent
->BufferItem
));
633 else if (EntryEvent
->NotificationType
== KSEVENTF_KSWORKITEM
)
635 /* queue work item of ks worker */
636 return KsQueueWorkItem((PKSWORKER
)EntryEvent
->Object
, (PWORK_QUEUE_ITEM
)EntryEvent
->DpcItem
);
640 /* unsupported type requested */
641 return STATUS_INVALID_PARAMETER
;
644 return STATUS_SUCCESS
;
654 IN PKSEVENT_ENTRY EventEntry
,
659 return STATUS_UNSUCCESSFUL
;
669 IN GUID
* Set OPTIONAL
,
671 IN PLIST_ENTRY EventsList
,
672 IN KSEVENTS_LOCKTYPE EventsFlags
,
686 IN PKSEVENT_ENTRY EventEntry
)
688 PKSBASIC_HEADER Header
= (PKSBASIC_HEADER
)((ULONG_PTR
)Object
- sizeof(KSBASIC_HEADER
));
690 ExInterlockedInsertTailList(&Header
->EventList
, &EventEntry
->ListEntry
, &Header
->EventListLock
);
698 KsDefaultAddEventHandler(
700 IN PKSEVENTDATA EventData
,
701 IN OUT PKSEVENT_ENTRY EventEntry
)
703 PIO_STACK_LOCATION IoStack
;
704 PKSIOBJECT_HEADER ObjectHeader
;
705 PKSBASIC_HEADER Header
;
707 /* first get the io stack location */
708 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
710 /* now get the object header */
711 ObjectHeader
=(PKSIOBJECT_HEADER
)IoStack
->FileObject
->FsContext2
;
714 ASSERT(ObjectHeader
->ObjectType
);
716 /* obtain basic header */
717 Header
= (PKSBASIC_HEADER
)((ULONG_PTR
)ObjectHeader
->ObjectType
- sizeof(KSBASIC_HEADER
));
719 /* now insert the event entry */
720 ExInterlockedInsertTailList(&Header
->EventList
, &EventEntry
->ListEntry
, &Header
->EventListLock
);
723 return STATUS_SUCCESS
;
736 IN
const GUID
* EventSet OPTIONAL
,
739 IN PVOID Data OPTIONAL
,
740 IN PFNKSGENERATEEVENTCALLBACK CallBack OPTIONAL
,
741 IN PVOID CallBackContext OPTIONAL
)