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

  1. /*****************************************************************************
  2. * service.cpp - service group object implementation
  3. *****************************************************************************
  4. * Copyright (c) 1997-2000 Microsoft Corporation. All Rights Reserved.
  5. */
  6. #include "private.h"
  7. /*****************************************************************************
  8. * CServiceGroup
  9. *****************************************************************************
  10. * Service group implementation.
  11. */
  12. class CServiceGroup
  13. : public IServiceGroup
  14. , public CUnknown
  15. {
  16. private:
  17. KDPC m_kDpc;
  18. KSPIN_LOCK m_kSpinLock;
  19. LIST_ENTRY m_listEntry;
  20. KTIMER m_kTimer;
  21. BOOLEAN m_bDelayedService;
  22. static
  23. VOID
  24. NTAPI
  25. ServiceDpc
  26. (
  27. IN PKDPC pKDpc,
  28. IN PVOID pvDeferredContext,
  29. IN PVOID pvSystemArgument1,
  30. IN PVOID pvSystemArgument2
  31. );
  32. public:
  33. DECLARE_STD_UNKNOWN();
  34. CServiceGroup(PUNKNOWN pUnknownOuter);
  35. ~CServiceGroup();
  36. IMP_IServiceGroup;
  37. friend
  38. PKSPIN_LOCK
  39. GetServiceGroupSpinLock (
  40. PSERVICEGROUP pServiceGroup
  41. );
  42. };
  43. PKSPIN_LOCK
  44. GetServiceGroupSpinLock (
  45. PSERVICEGROUP pServiceGroup
  46. )
  47. {
  48. CServiceGroup *ServiceGroup = (CServiceGroup *) pServiceGroup;
  49. return &ServiceGroup->m_kSpinLock;
  50. }
  51. /*****************************************************************************
  52. * SERVICEGROUPMEMBER
  53. *****************************************************************************
  54. * A structure representing a service group member.
  55. */
  56. struct SERVICEGROUPMEMBER
  57. {
  58. LIST_ENTRY listEntry;
  59. PSERVICESINK pServiceSink;
  60. };
  61. typedef SERVICEGROUPMEMBER *PSERVICEGROUPMEMBER;
  62. /*****************************************************************************
  63. * Factory.
  64. */
  65. #pragma code_seg("PAGE")
  66. /*****************************************************************************
  67. * CreateServiceGroup()
  68. *****************************************************************************
  69. * Creates a service group object.
  70. */
  71. NTSTATUS
  72. CreateServiceGroup
  73. (
  74. OUT PUNKNOWN * ppUnknown,
  75. IN REFCLSID,
  76. IN PUNKNOWN pUnknownOuter OPTIONAL,
  77. IN POOL_TYPE poolType
  78. )
  79. {
  80. PAGED_CODE();
  81. ASSERT(ppUnknown);
  82. _DbgPrintF(DEBUGLVL_LIFETIME,("Creating SERVICEGROUP"));
  83. STD_CREATE_BODY
  84. (
  85. CServiceGroup,
  86. ppUnknown,
  87. pUnknownOuter,
  88. poolType
  89. );
  90. }
  91. /*****************************************************************************
  92. * PcNewServiceGroup()
  93. *****************************************************************************
  94. * Creates and initializes a service group.
  95. */
  96. PORTCLASSAPI
  97. NTSTATUS
  98. NTAPI
  99. PcNewServiceGroup
  100. (
  101. OUT PSERVICEGROUP * ppServiceGroup,
  102. IN PUNKNOWN pUnknownOuter OPTIONAL
  103. )
  104. {
  105. PAGED_CODE();
  106. ASSERT(ppServiceGroup);
  107. //
  108. // Validate Parameters.
  109. //
  110. if (NULL == ppServiceGroup)
  111. {
  112. _DbgPrintF(DEBUGLVL_TERSE, ("PcNewServiceGroup : Invalid Parameter"));
  113. return STATUS_INVALID_PARAMETER;
  114. }
  115. PUNKNOWN pUnknown;
  116. NTSTATUS ntStatus =
  117. CreateServiceGroup
  118. (
  119. &pUnknown,
  120. GUID_NULL,
  121. pUnknownOuter,
  122. NonPagedPool
  123. );
  124. if (NT_SUCCESS(ntStatus))
  125. {
  126. PSERVICEGROUP pServiceGroup;
  127. ntStatus =
  128. pUnknown->QueryInterface
  129. (
  130. IID_IServiceGroup,
  131. (PVOID *) &pServiceGroup
  132. );
  133. if (NT_SUCCESS(ntStatus))
  134. {
  135. *ppServiceGroup = pServiceGroup;
  136. }
  137. else
  138. {
  139. pServiceGroup->Release();
  140. }
  141. pUnknown->Release();
  142. }
  143. return ntStatus;
  144. }
  145. /*****************************************************************************
  146. * Member functions.
  147. */
  148. /*****************************************************************************
  149. * CServiceGroup::CServiceGroup()
  150. *****************************************************************************
  151. * Constructor.
  152. */
  153. CServiceGroup::
  154. CServiceGroup
  155. (
  156. IN PUNKNOWN pUnknownOuter
  157. )
  158. : CUnknown(pUnknownOuter)
  159. {
  160. PAGED_CODE();
  161. _DbgPrintF(DEBUGLVL_LIFETIME,("Initializing SERVICEGROUP (0x%08x)",this));
  162. KeInitializeDpc(&m_kDpc,ServiceDpc,PVOID(this));
  163. KeInitializeSpinLock(&m_kSpinLock);
  164. InitializeListHead(&m_listEntry);
  165. }
  166. #pragma code_seg()
  167. /*****************************************************************************
  168. * CServiceGroup::~CServiceGroup()
  169. *****************************************************************************
  170. * Destructor.
  171. */
  172. CServiceGroup::
  173. ~CServiceGroup
  174. ( void
  175. )
  176. {
  177. _DbgPrintF(DEBUGLVL_LIFETIME,("Destroying SERVICEGROUP (0x%08x)",this));
  178. //
  179. // Make sure that the timer is shut down if using deferred service
  180. //
  181. if( m_bDelayedService )
  182. {
  183. KeCancelTimer( &m_kTimer );
  184. }
  185. //
  186. // Make sure the DPC is not queued.
  187. //
  188. KeRemoveQueueDpc(&m_kDpc);
  189. //
  190. // Acquire the spin lock in order to wait for a running DPC to wind down.
  191. // TODO: Is there a window here where we can have a DPC running on
  192. // another processor about to take the spinlock, but we get it
  193. // first? That would mean it would wait for us to release the
  194. // spinlock and then run as we destruct the service group.
  195. //
  196. KIRQL kIrqlOld;
  197. KeAcquireSpinLock(&m_kSpinLock,&kIrqlOld);
  198. //
  199. // Get rid of any remaining members.
  200. //
  201. while (! IsListEmpty(&m_listEntry))
  202. {
  203. PLIST_ENTRY pListEntry =
  204. RemoveHeadList(&m_listEntry);
  205. PSERVICEGROUPMEMBER pServiceGroupMember =
  206. PSERVICEGROUPMEMBER(pListEntry);
  207. pServiceGroupMember->pServiceSink->Release();
  208. delete pServiceGroupMember;
  209. }
  210. KeReleaseSpinLock(&m_kSpinLock,kIrqlOld);
  211. }
  212. #pragma code_seg("PAGE")
  213. /*****************************************************************************
  214. * CServiceGroup::NonDelegatingQueryInterface()
  215. *****************************************************************************
  216. * Obtains an interface.
  217. */
  218. STDMETHODIMP_(NTSTATUS)
  219. CServiceGroup::
  220. NonDelegatingQueryInterface
  221. (
  222. IN REFIID refIid,
  223. OUT PVOID * ppvObject
  224. )
  225. {
  226. PAGED_CODE();
  227. ASSERT(ppvObject);
  228. if
  229. ( (IsEqualGUIDAligned(refIid,IID_IUnknown)) ||
  230. (IsEqualGUIDAligned(refIid,IID_IServiceSink)) ||
  231. (IsEqualGUIDAligned(refIid,IID_IServiceGroup)) )
  232. {
  233. *ppvObject = PVOID(PSERVICEGROUP(this));
  234. }
  235. else
  236. {
  237. *ppvObject = NULL;
  238. }
  239. if (*ppvObject)
  240. {
  241. PUNKNOWN(*ppvObject)->AddRef();
  242. return STATUS_SUCCESS;
  243. }
  244. return STATUS_INVALID_PARAMETER;
  245. }
  246. #pragma code_seg()
  247. /*****************************************************************************
  248. * ServiceDpc()
  249. *****************************************************************************
  250. * Deferred procedure to be executed as a result of service request.
  251. */
  252. VOID
  253. NTAPI
  254. CServiceGroup::
  255. ServiceDpc
  256. (
  257. IN PKDPC pKDpc,
  258. IN PVOID pvDeferredContext,
  259. IN PVOID pvSystemArgument1,
  260. IN PVOID pvSystemArgument2
  261. )
  262. {
  263. _DbgPrintF(DEBUGLVL_BLAB,("CServiceGroup::ServiceDpc start"));
  264. ASSERT(pvDeferredContext);
  265. if( pvDeferredContext )
  266. {
  267. //
  268. // The deferred context is the service group object.
  269. //
  270. CServiceGroup *pServiceGroup = (CServiceGroup *) pvDeferredContext;
  271. KeAcquireSpinLockAtDpcLevel(&pServiceGroup->m_kSpinLock);
  272. //
  273. // Request service on all members.
  274. //
  275. for
  276. ( PLIST_ENTRY pListEntry = pServiceGroup->m_listEntry.Flink;
  277. pListEntry != &pServiceGroup->m_listEntry;
  278. pListEntry = pListEntry->Flink )
  279. {
  280. PSERVICEGROUPMEMBER(pListEntry)->pServiceSink->RequestService();
  281. }
  282. KeReleaseSpinLockFromDpcLevel(&pServiceGroup->m_kSpinLock);
  283. }
  284. _DbgPrintF(DEBUGLVL_BLAB,("CServiceGroup::ServiceDpc stop"));
  285. }
  286. /*****************************************************************************
  287. * CServiceGroup::RequestService()
  288. *****************************************************************************
  289. * Service group function to indicate that service is requested for the group.
  290. */
  291. STDMETHODIMP_(void)
  292. CServiceGroup::
  293. RequestService
  294. ( void
  295. )
  296. {
  297. _DbgPrintF(DEBUGLVL_BLAB,("CServiceGroup::RequestService start"));
  298. if (m_bDelayedService)
  299. {
  300. LARGE_INTEGER largeInteger;
  301. largeInteger.QuadPart = 0;
  302. KeSetTimer(&m_kTimer,largeInteger,&m_kDpc);
  303. }
  304. else
  305. if (KeGetCurrentIrql() < DISPATCH_LEVEL)
  306. {
  307. KIRQL kIrqlOld;
  308. KeRaiseIrql(DISPATCH_LEVEL,&kIrqlOld);
  309. KeInsertQueueDpc
  310. (
  311. &m_kDpc,
  312. NULL,
  313. NULL
  314. );
  315. KeLowerIrql(kIrqlOld);
  316. }
  317. else
  318. {
  319. KeInsertQueueDpc
  320. (
  321. &m_kDpc,
  322. NULL,
  323. NULL
  324. );
  325. }
  326. _DbgPrintF(DEBUGLVL_BLAB,("CServiceGroup::RequestService end"));
  327. }
  328. /*****************************************************************************
  329. * CServiceGroup::AddMember()
  330. *****************************************************************************
  331. * Service group function to add a member.
  332. */
  333. STDMETHODIMP_(NTSTATUS)
  334. CServiceGroup::
  335. AddMember
  336. (
  337. IN PSERVICESINK pServiceSink
  338. )
  339. {
  340. //
  341. // Create a new member.
  342. //
  343. PSERVICEGROUPMEMBER pServiceGroupMember =
  344. new(NonPagedPool,'mScP') SERVICEGROUPMEMBER;
  345. NTSTATUS ntStatus = STATUS_SUCCESS;
  346. if (pServiceGroupMember)
  347. {
  348. //
  349. // Member structure holds a reference to the sink.
  350. //
  351. pServiceGroupMember->pServiceSink = pServiceSink;
  352. pServiceSink->AddRef();
  353. //
  354. // Add the member to the list.
  355. //
  356. KIRQL kIrqlOld;
  357. KeAcquireSpinLock(&m_kSpinLock,&kIrqlOld);
  358. InsertTailList
  359. (
  360. &m_listEntry,
  361. &pServiceGroupMember->listEntry
  362. );
  363. KeReleaseSpinLock(&m_kSpinLock,kIrqlOld);
  364. }
  365. else
  366. {
  367. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  368. }
  369. return ntStatus;
  370. }
  371. /*****************************************************************************
  372. * CServiceGroup::RemoveMember()
  373. *****************************************************************************
  374. * Service group function to remove a member.
  375. */
  376. STDMETHODIMP_(void)
  377. CServiceGroup::
  378. RemoveMember
  379. (
  380. IN PSERVICESINK pServiceSink
  381. )
  382. {
  383. //
  384. // Remove the member structure from the list.
  385. //
  386. KIRQL kIrqlOld;
  387. KeAcquireSpinLock(&m_kSpinLock,&kIrqlOld);
  388. for( PLIST_ENTRY pListEntry = m_listEntry.Flink;
  389. pListEntry != &m_listEntry;
  390. pListEntry = pListEntry->Flink )
  391. {
  392. PSERVICEGROUPMEMBER pServiceGroupMember =
  393. PSERVICEGROUPMEMBER(pListEntry);
  394. if (pServiceGroupMember->pServiceSink == pServiceSink)
  395. {
  396. RemoveEntryList(pListEntry);
  397. pServiceGroupMember->pServiceSink->Release();
  398. delete pServiceGroupMember;
  399. break;
  400. }
  401. }
  402. KeReleaseSpinLock(&m_kSpinLock,kIrqlOld);
  403. }
  404. /*****************************************************************************
  405. * CServiceGroup::SupportDelayedService()
  406. *****************************************************************************
  407. * Indicate service group should support delayed service.
  408. */
  409. STDMETHODIMP_(void)
  410. CServiceGroup::
  411. SupportDelayedService
  412. ( void
  413. )
  414. {
  415. m_bDelayedService = TRUE;
  416. KeInitializeTimer(&m_kTimer);
  417. }
  418. /*****************************************************************************
  419. * CServiceGroup::RequestDelayedService()
  420. *****************************************************************************
  421. * Request service after a delay.
  422. */
  423. STDMETHODIMP_(void)
  424. CServiceGroup::
  425. RequestDelayedService
  426. (
  427. IN ULONGLONG ullDelay
  428. )
  429. {
  430. LARGE_INTEGER largeInteger;
  431. largeInteger.QuadPart = ullDelay;
  432. KeSetTimer(&m_kTimer,largeInteger,&m_kDpc);
  433. }
  434. /*****************************************************************************
  435. * CServiceGroup::CancelDelayedService()
  436. *****************************************************************************
  437. * Cancel delayed service.
  438. */
  439. STDMETHODIMP_(void)
  440. CServiceGroup::
  441. CancelDelayedService
  442. ( void
  443. )
  444. {
  445. KeCancelTimer(&m_kTimer);
  446. }