Author: janderwald Date: Fri May 14 17:47:00 2010 New Revision: 47197
URL: http://svn.reactos.org/svn/reactos?rev=47197&view=rev Log: [PORTCLS] - Don't request initializing delayed service request as this is the task of the miniport driver - Reimplement the service group object: - Use the initialized timer object when RequestService is called - Fix possible race conditions when adding / removing a service sink by protecting it with a lock - Acquire the service group list lock when executing the shared dpc routine
Modified: trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.cpp trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp trunk/reactos/drivers/wdm/audio/backpln/portcls/service_group.cpp
Modified: trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/backpln/p... ============================================================================== --- trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.cpp [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_dmus.cpp [iso-8859-1] Fri May 14 17:47:00 2010 @@ -602,7 +602,6 @@ DPRINT("Failed to add pin to service group\n"); return Status; } - m_ServiceGroup->SupportDelayedService(); }
Status = m_IrpQueue->Init(ConnectDetails, 0, 0, NULL);
Modified: trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/backpln/p... ============================================================================== --- trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_wavecyclic.cpp [iso-8859-1] Fri May 14 17:47:00 2010 @@ -1213,7 +1213,6 @@ return Status; }
- m_ServiceGroup->SupportDelayedService(); m_Stream->SetState(KSSTATE_STOP); m_State = KSSTATE_STOP; m_CommonBufferOffset = 0; @@ -1224,6 +1223,8 @@ m_Delay = Int32x32To64(10, -10000);
Status = m_Stream->SetNotificationFreq(10, &m_FrameSize); + PC_ASSERT(NT_SUCCESS(Status)); + PC_ASSERT(m_FrameSize);
SilenceBuffer = AllocateItem(NonPagedPool, m_FrameSize, TAG_PORTCLASS); if (!SilenceBuffer)
Modified: trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/backpln/p... ============================================================================== --- trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/backpln/portcls/pin_wavepci.cpp [iso-8859-1] Fri May 14 17:47:00 2010 @@ -815,7 +815,6 @@ DPRINT("Failed to add pin to service group\n"); return Status; } - m_ServiceGroup->SupportDelayedService(); }
// delay of 10 milisec
Modified: trunk/reactos/drivers/wdm/audio/backpln/portcls/service_group.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/wdm/audio/backpln/p... ============================================================================== --- trunk/reactos/drivers/wdm/audio/backpln/portcls/service_group.cpp [iso-8859-1] (original) +++ trunk/reactos/drivers/wdm/audio/backpln/portcls/service_group.cpp [iso-8859-1] Fri May 14 17:47:00 2010 @@ -54,12 +54,10 @@
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);
@@ -105,9 +103,16 @@
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); }
@@ -119,15 +124,34 @@
DPRINT("CServiceGroup::RequestService() Dpc at Level %u\n", KeGetCurrentIrql());
- if (KeGetCurrentIrql() > DISPATCH_LEVEL) - { - KeInsertQueueDpc(&m_Dpc, NULL, NULL); - return; - } - - KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); - KeInsertQueueDpc(&m_Dpc, NULL, NULL); - KeLowerIrql(OldIrql); + if (m_TimerInitialized) + { + LARGE_INTEGER DueTime; + + // 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); + } + } }
//--------------------------------------------------------------- @@ -140,17 +164,32 @@ 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; } @@ -162,22 +201,44 @@ { 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);
}
@@ -194,73 +255,40 @@ 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); -} - -#endif + + // release service group list lock + KeReleaseSpinLockFromDpcLevel(&This->m_Lock); +} + VOID NTAPI CServiceGroup::SupportDelayedService() { - //NTSTATUS Status; - //HANDLE ThreadHandle; - PC_ASSERT_IRQL(DISPATCH_LEVEL);
- if (m_Initialized) - return; - - 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 + // initialize the timer + KeInitializeTimer(&m_Timer); + + // use the timer to perform service requests + m_TimerInitialized = TRUE; }
VOID @@ -270,17 +298,14 @@ { 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 @@ -288,11 +313,10 @@ CServiceGroup::CancelDelayedService() { PC_ASSERT_IRQL(DISPATCH_LEVEL); - - if (m_Initialized) - { - KeCancelTimer(&m_Timer); - } + PC_ASSERT(m_TimerInitialized); + + // cancel the timer + KeCancelTimer(&m_Timer); }
NTSTATUS @@ -303,19 +327,31 @@ { 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; }