LIST_ENTRY m_ServiceSinkHead;
- BOOL m_Initialized;
- BOOL m_TimerActive;
+ BOOL m_TimerInitialized;
KTIMER m_Timer;
KDPC m_Dpc;
- KEVENT m_Event;
- LONG m_ThreadActive;
+ KSPIN_LOCK m_Lock;
friend VOID NTAPI IServiceGroupDpc(IN struct _KDPC *Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
CServiceGroup::CServiceGroup(IUnknown * OuterUnknown)
{
+ // initialize dpc
KeInitializeDpc(&m_Dpc, IServiceGroupDpc, (PVOID)this);
+
+ // set highest importance
KeSetImportanceDpc(&m_Dpc, HighImportance);
- KeInitializeEvent(&m_Event, NotificationEvent, FALSE);
+
+ // initialize service group list lock
+ KeInitializeSpinLock(&m_Lock);
+
+ // initialize service group list
InitializeListHead(&m_ServiceSinkHead);
}
DPRINT("CServiceGroup::RequestService() Dpc at Level %u\n", KeGetCurrentIrql());
- if (KeGetCurrentIrql() > DISPATCH_LEVEL)
+ if (m_TimerInitialized)
{
- KeInsertQueueDpc(&m_Dpc, NULL, NULL);
- return;
- }
+ LARGE_INTEGER DueTime;
- KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
- KeInsertQueueDpc(&m_Dpc, NULL, NULL);
- KeLowerIrql(OldIrql);
+ // no due time
+ DueTime.QuadPart = 0LL;
+
+ // delayed service requested
+ KeSetTimer(&m_Timer, DueTime, &m_Dpc);
+ }
+ else
+ {
+ // check curent irql
+ if (KeGetCurrentIrql() > DISPATCH_LEVEL)
+ {
+ //insert dpc to queue
+ KeInsertQueueDpc(&m_Dpc, NULL, NULL);
+ }
+ else
+ {
+ // raise irql to dispatch level to make dpc fire immediately
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ // insert dpc to queue
+ KeInsertQueueDpc(&m_Dpc, NULL, NULL);
+ // lower irql to old level
+ KeLowerIrql(OldIrql);
+ }
+ }
}
//---------------------------------------------------------------
IN PSERVICESINK pServiceSink)
{
PGROUP_ENTRY Entry;
+ KIRQL OldLevel;
+ // sanity check
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
+ // allocate service sink entry
Entry = (PGROUP_ENTRY)AllocateItem(NonPagedPool, sizeof(GROUP_ENTRY), TAG_PORTCLASS);
if (!Entry)
+ {
+ // out of memory
return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ // initialize service sink entry
Entry->pServiceSink = pServiceSink;
+ // increment reference count
pServiceSink->AddRef();
+ // acquire service group list lock
+ KeAcquireSpinLock(&m_Lock, &OldLevel);
+
+ // insert into service sink list
InsertTailList(&m_ServiceSinkHead, &Entry->Entry);
+ // release service group list lock
+ KeReleaseSpinLock(&m_Lock, OldLevel);
+
return STATUS_SUCCESS;
}
{
PLIST_ENTRY CurEntry;
PGROUP_ENTRY Entry;
+ KIRQL OldLevel;
+ // sanity check
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
+ // acquire service group list lock
+ KeAcquireSpinLock(&m_Lock, &OldLevel);
+
+ // grab first entry
CurEntry = m_ServiceSinkHead.Flink;
+
+ // loop list until the passed entry is found
while (CurEntry != &m_ServiceSinkHead)
{
+ // grab entry
Entry = CONTAINING_RECORD(CurEntry, GROUP_ENTRY, Entry);
+
+ // check if it matches the passed entry
if (Entry->pServiceSink == pServiceSink)
{
+ // remove entry from list
RemoveEntryList(&Entry->Entry);
+
+ // release service sink reference
pServiceSink->Release();
+
+ // free service sink entry
FreeItem(Entry, TAG_PORTCLASS);
- return;
+
+ // leave loop
+ break;
}
+ // move to next entry
CurEntry = CurEntry->Flink;
}
+ // release service group list lock
+ KeReleaseSpinLock(&m_Lock, OldLevel);
+
}
VOID
PGROUP_ENTRY Entry;
CServiceGroup * This = (CServiceGroup*)DeferredContext;
+ // acquire service group list lock
+ KeAcquireSpinLockAtDpcLevel(&This->m_Lock);
+
+ // grab first entry
CurEntry = This->m_ServiceSinkHead.Flink;
+
+ // loop the list and call the attached service sink/group
while (CurEntry != &This->m_ServiceSinkHead)
{
+ //grab current entry
Entry = (PGROUP_ENTRY)CONTAINING_RECORD(CurEntry, GROUP_ENTRY, Entry);
+
+ // call service sink/group
Entry->pServiceSink->RequestService();
+
+ // move to next entry
CurEntry = CurEntry->Flink;
}
-}
-
-
-#if 0
-VOID
-NTAPI
-ServiceGroupThread(IN PVOID StartContext)
-{
- NTSTATUS Status;
- KWAIT_BLOCK WaitBlockArray[2];
- PVOID WaitObjects[2];
- CServiceGroup * This = (CServiceGroup*)StartContext;
- // Set thread state
- InterlockedIncrement(&This->m_ThreadActive);
-
- // Setup the wait objects
- WaitObjects[0] = &m_Timer;
- WaitObjects[1] = &m_Event;
-
- do
- {
- // Wait on our objects
- Status = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, Executive, KernelMode, FALSE, NULL, WaitBlockArray);
-
- switch(Status)
- {
- case STATUS_WAIT_0:
- IServiceGroupDpc(&This->m_Dpc, (PVOID)This, NULL, NULL);
- break;
- case STATUS_WAIT_1:
- PsTerminateSystemThread(STATUS_SUCCESS);
- return;
- }
- }while(TRUE);
+ // release service group list lock
+ KeReleaseSpinLockFromDpcLevel(&This->m_Lock);
}
-#endif
VOID
NTAPI
CServiceGroup::SupportDelayedService()
{
- //NTSTATUS Status;
- //HANDLE ThreadHandle;
-
PC_ASSERT_IRQL(DISPATCH_LEVEL);
- if (m_Initialized)
- return;
+ // initialize the timer
+ KeInitializeTimer(&m_Timer);
- KeInitializeTimerEx(&m_Timer, NotificationTimer);
-
-#if 0
- Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, NULL, 0, NULL, ServiceGroupThread, (PVOID)This);
- if (NT_SUCCESS(Status))
- {
- ZwClose(ThreadHandle);
- m_Initialized = TRUE;
- }
-#endif
+ // use the timer to perform service requests
+ m_TimerInitialized = TRUE;
}
VOID
{
LARGE_INTEGER DueTime;
+ // sanity check
PC_ASSERT_IRQL(DISPATCH_LEVEL);
+ PC_ASSERT(m_TimerInitialized);
DueTime.QuadPart = ullDelay;
- if (m_Initialized)
- {
- if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
- KeSetTimer(&m_Timer, DueTime, &m_Dpc);
- else
- KeInsertQueueDpc(&m_Dpc, NULL, NULL);
- }
+ // set the timer
+ KeSetTimer(&m_Timer, DueTime, &m_Dpc);
}
VOID
CServiceGroup::CancelDelayedService()
{
PC_ASSERT_IRQL(DISPATCH_LEVEL);
+ PC_ASSERT(m_TimerInitialized);
- if (m_Initialized)
- {
- KeCancelTimer(&m_Timer);
- }
+ // cancel the timer
+ KeCancelTimer(&m_Timer);
}
NTSTATUS
{
CServiceGroup * This;
NTSTATUS Status;
+
DPRINT("PcNewServiceGroup entered\n");
+ //FIXME support aggregation
+ PC_ASSERT(OuterUnknown == NULL);
+
+ // allocate a service group object
This = new(NonPagedPool, TAG_PORTCLASS)CServiceGroup(OuterUnknown);
+
if (!This)
+ {
+ // out of memory
return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ // request IServiceSink interface
Status = This->QueryInterface(IID_IServiceSink, (PVOID*)OutServiceGroup);
if (!NT_SUCCESS(Status))
{
+ // failed to acquire service sink interface
delete This;
return Status;
}
+ // done
return Status;
}