Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

528 lines
13 KiB

/*****************************************************************************
* service.cpp - service group object implementation
*****************************************************************************
* Copyright (c) 1997-2000 Microsoft Corporation. All Rights Reserved.
*/
#include "private.h"
/*****************************************************************************
* CServiceGroup
*****************************************************************************
* Service group implementation.
*/
class CServiceGroup
: public IServiceGroup
, public CUnknown
{
private:
KDPC m_kDpc;
KSPIN_LOCK m_kSpinLock;
LIST_ENTRY m_listEntry;
KTIMER m_kTimer;
BOOLEAN m_bDelayedService;
static
VOID
NTAPI
ServiceDpc
(
IN PKDPC pKDpc,
IN PVOID pvDeferredContext,
IN PVOID pvSystemArgument1,
IN PVOID pvSystemArgument2
);
public:
DECLARE_STD_UNKNOWN();
CServiceGroup(PUNKNOWN pUnknownOuter);
~CServiceGroup();
IMP_IServiceGroup;
friend
PKSPIN_LOCK
GetServiceGroupSpinLock (
PSERVICEGROUP pServiceGroup
);
};
PKSPIN_LOCK
GetServiceGroupSpinLock (
PSERVICEGROUP pServiceGroup
)
{
CServiceGroup *ServiceGroup = (CServiceGroup *) pServiceGroup;
return &ServiceGroup->m_kSpinLock;
}
/*****************************************************************************
* SERVICEGROUPMEMBER
*****************************************************************************
* A structure representing a service group member.
*/
struct SERVICEGROUPMEMBER
{
LIST_ENTRY listEntry;
PSERVICESINK pServiceSink;
};
typedef SERVICEGROUPMEMBER *PSERVICEGROUPMEMBER;
/*****************************************************************************
* Factory.
*/
#pragma code_seg("PAGE")
/*****************************************************************************
* CreateServiceGroup()
*****************************************************************************
* Creates a service group object.
*/
NTSTATUS
CreateServiceGroup
(
OUT PUNKNOWN * ppUnknown,
IN REFCLSID,
IN PUNKNOWN pUnknownOuter OPTIONAL,
IN POOL_TYPE poolType
)
{
PAGED_CODE();
ASSERT(ppUnknown);
_DbgPrintF(DEBUGLVL_LIFETIME,("Creating SERVICEGROUP"));
STD_CREATE_BODY
(
CServiceGroup,
ppUnknown,
pUnknownOuter,
poolType
);
}
/*****************************************************************************
* PcNewServiceGroup()
*****************************************************************************
* Creates and initializes a service group.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcNewServiceGroup
(
OUT PSERVICEGROUP * ppServiceGroup,
IN PUNKNOWN pUnknownOuter OPTIONAL
)
{
PAGED_CODE();
ASSERT(ppServiceGroup);
//
// Validate Parameters.
//
if (NULL == ppServiceGroup)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcNewServiceGroup : Invalid Parameter"));
return STATUS_INVALID_PARAMETER;
}
PUNKNOWN pUnknown;
NTSTATUS ntStatus =
CreateServiceGroup
(
&pUnknown,
GUID_NULL,
pUnknownOuter,
NonPagedPool
);
if (NT_SUCCESS(ntStatus))
{
PSERVICEGROUP pServiceGroup;
ntStatus =
pUnknown->QueryInterface
(
IID_IServiceGroup,
(PVOID *) &pServiceGroup
);
if (NT_SUCCESS(ntStatus))
{
*ppServiceGroup = pServiceGroup;
}
else
{
pServiceGroup->Release();
}
pUnknown->Release();
}
return ntStatus;
}
/*****************************************************************************
* Member functions.
*/
/*****************************************************************************
* CServiceGroup::CServiceGroup()
*****************************************************************************
* Constructor.
*/
CServiceGroup::
CServiceGroup
(
IN PUNKNOWN pUnknownOuter
)
: CUnknown(pUnknownOuter)
{
PAGED_CODE();
_DbgPrintF(DEBUGLVL_LIFETIME,("Initializing SERVICEGROUP (0x%08x)",this));
KeInitializeDpc(&m_kDpc,ServiceDpc,PVOID(this));
KeInitializeSpinLock(&m_kSpinLock);
InitializeListHead(&m_listEntry);
}
#pragma code_seg()
/*****************************************************************************
* CServiceGroup::~CServiceGroup()
*****************************************************************************
* Destructor.
*/
CServiceGroup::
~CServiceGroup
( void
)
{
_DbgPrintF(DEBUGLVL_LIFETIME,("Destroying SERVICEGROUP (0x%08x)",this));
//
// Make sure that the timer is shut down if using deferred service
//
if( m_bDelayedService )
{
KeCancelTimer( &m_kTimer );
}
//
// Make sure the DPC is not queued.
//
KeRemoveQueueDpc(&m_kDpc);
//
// Acquire the spin lock in order to wait for a running DPC to wind down.
// TODO: Is there a window here where we can have a DPC running on
// another processor about to take the spinlock, but we get it
// first? That would mean it would wait for us to release the
// spinlock and then run as we destruct the service group.
//
KIRQL kIrqlOld;
KeAcquireSpinLock(&m_kSpinLock,&kIrqlOld);
//
// Get rid of any remaining members.
//
while (! IsListEmpty(&m_listEntry))
{
PLIST_ENTRY pListEntry =
RemoveHeadList(&m_listEntry);
PSERVICEGROUPMEMBER pServiceGroupMember =
PSERVICEGROUPMEMBER(pListEntry);
pServiceGroupMember->pServiceSink->Release();
delete pServiceGroupMember;
}
KeReleaseSpinLock(&m_kSpinLock,kIrqlOld);
}
#pragma code_seg("PAGE")
/*****************************************************************************
* CServiceGroup::NonDelegatingQueryInterface()
*****************************************************************************
* Obtains an interface.
*/
STDMETHODIMP_(NTSTATUS)
CServiceGroup::
NonDelegatingQueryInterface
(
IN REFIID refIid,
OUT PVOID * ppvObject
)
{
PAGED_CODE();
ASSERT(ppvObject);
if
( (IsEqualGUIDAligned(refIid,IID_IUnknown)) ||
(IsEqualGUIDAligned(refIid,IID_IServiceSink)) ||
(IsEqualGUIDAligned(refIid,IID_IServiceGroup)) )
{
*ppvObject = PVOID(PSERVICEGROUP(this));
}
else
{
*ppvObject = NULL;
}
if (*ppvObject)
{
PUNKNOWN(*ppvObject)->AddRef();
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}
#pragma code_seg()
/*****************************************************************************
* ServiceDpc()
*****************************************************************************
* Deferred procedure to be executed as a result of service request.
*/
VOID
NTAPI
CServiceGroup::
ServiceDpc
(
IN PKDPC pKDpc,
IN PVOID pvDeferredContext,
IN PVOID pvSystemArgument1,
IN PVOID pvSystemArgument2
)
{
_DbgPrintF(DEBUGLVL_BLAB,("CServiceGroup::ServiceDpc start"));
ASSERT(pvDeferredContext);
if( pvDeferredContext )
{
//
// The deferred context is the service group object.
//
CServiceGroup *pServiceGroup = (CServiceGroup *) pvDeferredContext;
KeAcquireSpinLockAtDpcLevel(&pServiceGroup->m_kSpinLock);
//
// Request service on all members.
//
for
( PLIST_ENTRY pListEntry = pServiceGroup->m_listEntry.Flink;
pListEntry != &pServiceGroup->m_listEntry;
pListEntry = pListEntry->Flink )
{
PSERVICEGROUPMEMBER(pListEntry)->pServiceSink->RequestService();
}
KeReleaseSpinLockFromDpcLevel(&pServiceGroup->m_kSpinLock);
}
_DbgPrintF(DEBUGLVL_BLAB,("CServiceGroup::ServiceDpc stop"));
}
/*****************************************************************************
* CServiceGroup::RequestService()
*****************************************************************************
* Service group function to indicate that service is requested for the group.
*/
STDMETHODIMP_(void)
CServiceGroup::
RequestService
( void
)
{
_DbgPrintF(DEBUGLVL_BLAB,("CServiceGroup::RequestService start"));
if (m_bDelayedService)
{
LARGE_INTEGER largeInteger;
largeInteger.QuadPart = 0;
KeSetTimer(&m_kTimer,largeInteger,&m_kDpc);
}
else
if (KeGetCurrentIrql() < DISPATCH_LEVEL)
{
KIRQL kIrqlOld;
KeRaiseIrql(DISPATCH_LEVEL,&kIrqlOld);
KeInsertQueueDpc
(
&m_kDpc,
NULL,
NULL
);
KeLowerIrql(kIrqlOld);
}
else
{
KeInsertQueueDpc
(
&m_kDpc,
NULL,
NULL
);
}
_DbgPrintF(DEBUGLVL_BLAB,("CServiceGroup::RequestService end"));
}
/*****************************************************************************
* CServiceGroup::AddMember()
*****************************************************************************
* Service group function to add a member.
*/
STDMETHODIMP_(NTSTATUS)
CServiceGroup::
AddMember
(
IN PSERVICESINK pServiceSink
)
{
//
// Create a new member.
//
PSERVICEGROUPMEMBER pServiceGroupMember =
new(NonPagedPool,'mScP') SERVICEGROUPMEMBER;
NTSTATUS ntStatus = STATUS_SUCCESS;
if (pServiceGroupMember)
{
//
// Member structure holds a reference to the sink.
//
pServiceGroupMember->pServiceSink = pServiceSink;
pServiceSink->AddRef();
//
// Add the member to the list.
//
KIRQL kIrqlOld;
KeAcquireSpinLock(&m_kSpinLock,&kIrqlOld);
InsertTailList
(
&m_listEntry,
&pServiceGroupMember->listEntry
);
KeReleaseSpinLock(&m_kSpinLock,kIrqlOld);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
return ntStatus;
}
/*****************************************************************************
* CServiceGroup::RemoveMember()
*****************************************************************************
* Service group function to remove a member.
*/
STDMETHODIMP_(void)
CServiceGroup::
RemoveMember
(
IN PSERVICESINK pServiceSink
)
{
//
// Remove the member structure from the list.
//
KIRQL kIrqlOld;
KeAcquireSpinLock(&m_kSpinLock,&kIrqlOld);
for( PLIST_ENTRY pListEntry = m_listEntry.Flink;
pListEntry != &m_listEntry;
pListEntry = pListEntry->Flink )
{
PSERVICEGROUPMEMBER pServiceGroupMember =
PSERVICEGROUPMEMBER(pListEntry);
if (pServiceGroupMember->pServiceSink == pServiceSink)
{
RemoveEntryList(pListEntry);
pServiceGroupMember->pServiceSink->Release();
delete pServiceGroupMember;
break;
}
}
KeReleaseSpinLock(&m_kSpinLock,kIrqlOld);
}
/*****************************************************************************
* CServiceGroup::SupportDelayedService()
*****************************************************************************
* Indicate service group should support delayed service.
*/
STDMETHODIMP_(void)
CServiceGroup::
SupportDelayedService
( void
)
{
m_bDelayedService = TRUE;
KeInitializeTimer(&m_kTimer);
}
/*****************************************************************************
* CServiceGroup::RequestDelayedService()
*****************************************************************************
* Request service after a delay.
*/
STDMETHODIMP_(void)
CServiceGroup::
RequestDelayedService
(
IN ULONGLONG ullDelay
)
{
LARGE_INTEGER largeInteger;
largeInteger.QuadPart = ullDelay;
KeSetTimer(&m_kTimer,largeInteger,&m_kDpc);
}
/*****************************************************************************
* CServiceGroup::CancelDelayedService()
*****************************************************************************
* Cancel delayed service.
*/
STDMETHODIMP_(void)
CServiceGroup::
CancelDelayedService
( void
)
{
KeCancelTimer(&m_kTimer);
}