Source code of Windows XP (NT5)
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.

523 lines
10 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. wpipm.cxx
  5. Abstract:
  6. Contains the WPIPM class that handles communication with
  7. the admin service. WPIPM responds to pings, and tells
  8. the process when to shut down.
  9. Author:
  10. Michael Courage (MCourage) 22-Feb-1999
  11. Revision History:
  12. --*/
  13. #include <precomp.hxx>
  14. #include "ipm.hxx"
  15. #include "wpipm.hxx"
  16. #include "ipm_io_c.hxx"
  17. extern PFN_ULATQ_COLLECT_PERF_COUNTERS g_pfnCollectCounters;
  18. /**
  19. *
  20. * Routine Description:
  21. *
  22. * Initializes WPIPM.
  23. *
  24. * Arguments:
  25. *
  26. * pWpContext - pointer to the wp context (so we can tell it to shutdown)
  27. *
  28. * Return Value:
  29. *
  30. * HRESULT
  31. */
  32. HRESULT
  33. WP_IPM::Initialize(
  34. WP_CONTEXT * pWpContext
  35. )
  36. {
  37. HRESULT hr = S_OK;
  38. IO_FACTORY_C * pFactory;
  39. STRU strPipeName;
  40. MESSAGE_PIPE * pPipe = NULL;
  41. m_pWpContext = pWpContext;
  42. m_pMessageGlobal = NULL;
  43. m_pPipe = NULL;
  44. m_hTerminateEvent = NULL;
  45. //
  46. // create MESSAGE_GLOBAL
  47. //
  48. pFactory = new IO_FACTORY_C();
  49. if (pFactory) {
  50. m_pMessageGlobal = new MESSAGE_GLOBAL(pFactory);
  51. if (m_pMessageGlobal) {
  52. hr = m_pMessageGlobal->InitializeMessageGlobal();
  53. } else {
  54. delete pFactory;
  55. pFactory = NULL;
  56. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  57. }
  58. } else {
  59. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  60. }
  61. //
  62. // create connect event
  63. //
  64. if (SUCCEEDED(hr)) {
  65. m_hConnectEvent = CreateEvent(
  66. NULL, // default security
  67. TRUE, // manual reset
  68. FALSE, // initial state
  69. NULL // unnamed event
  70. );
  71. if (m_hConnectEvent) {
  72. hr = m_pMessageGlobal->CreateMessagePipe(
  73. this,
  74. &pPipe
  75. );
  76. } else {
  77. hr = HRESULT_FROM_WIN32(GetLastError());
  78. }
  79. }
  80. //
  81. // create the MESSAGE_PIPE and termination event
  82. //
  83. if (SUCCEEDED(hr)) {
  84. m_hTerminateEvent = CreateEvent(
  85. NULL, // default security
  86. TRUE, // manual reset
  87. FALSE, // initial state
  88. NULL // unnamed
  89. );
  90. if (m_hTerminateEvent) {
  91. hr = m_pMessageGlobal->CreateMessagePipe(
  92. this,
  93. &pPipe
  94. );
  95. } else {
  96. hr = HRESULT_FROM_WIN32(GetLastError());
  97. }
  98. }
  99. //
  100. // connect the MESSAGE_PIPE
  101. //
  102. if (SUCCEEDED(hr)) {
  103. hr = strPipeName.Copy(IPM_NAMED_PIPE_NAME);
  104. if (SUCCEEDED(hr)) {
  105. hr = m_pMessageGlobal->ConnectMessagePipe(
  106. strPipeName,
  107. pWpContext->_pConfigInfo->QueryNamedPipeId(),
  108. pPipe
  109. );
  110. }
  111. }
  112. if (SUCCEEDED(hr)) {
  113. m_pPipe = pPipe;
  114. //
  115. // wait for connect
  116. //
  117. WaitForSingleObject(m_hConnectEvent, INFINITE);
  118. } else {
  119. // pipe takes care of itself
  120. Terminate();
  121. }
  122. return hr;
  123. }
  124. /**
  125. *
  126. * Routine Description:
  127. *
  128. * Terminates WPIPM.
  129. *
  130. * If the message pipe is open this function will disconnect it
  131. * and wait for the pipe's disconnection callback.
  132. *
  133. * Arguments:
  134. *
  135. * None.
  136. *
  137. * Return Value:
  138. *
  139. * HRESULT
  140. */
  141. HRESULT
  142. WP_IPM::Terminate(
  143. VOID
  144. )
  145. {
  146. HRESULT hr = S_OK;
  147. HRESULT hrGlobalTerminate;
  148. DWORD dwWaitResult;
  149. if (m_pMessageGlobal) {
  150. if (m_pPipe) {
  151. hr = m_pMessageGlobal->DisconnectMessagePipe(m_pPipe);
  152. m_pPipe = NULL;
  153. // pipe deletes itself
  154. if (SUCCEEDED(hr)) {
  155. dwWaitResult = WaitForSingleObject(
  156. m_hTerminateEvent,
  157. INFINITE
  158. );
  159. }
  160. }
  161. hrGlobalTerminate = m_pMessageGlobal->TerminateMessageGlobal();
  162. if (SUCCEEDED(hr)) {
  163. hr = hrGlobalTerminate;
  164. }
  165. m_pMessageGlobal = NULL;
  166. }
  167. m_pWpContext = NULL;
  168. if (m_hTerminateEvent) {
  169. CloseHandle(m_hTerminateEvent);
  170. m_hTerminateEvent = NULL;
  171. }
  172. if (m_hConnectEvent) {
  173. CloseHandle(m_hConnectEvent);
  174. m_hConnectEvent = NULL;
  175. }
  176. return hr;
  177. }
  178. /**
  179. *
  180. *
  181. * Routine Description:
  182. *
  183. * This is a callback from the message pipe that means
  184. * the pipe has received a message.
  185. *
  186. * We decode the message and respond appropriately.
  187. *
  188. * Arguments:
  189. *
  190. * pPipeMessage - the message that we received
  191. *
  192. * Return Value:
  193. *
  194. * HRESULT
  195. *
  196. */
  197. HRESULT
  198. WP_IPM::AcceptMessage(
  199. IN const MESSAGE * pPipeMessage
  200. )
  201. {
  202. HRESULT hr;
  203. switch (pPipeMessage->GetOpcode()) {
  204. case IPM_OP_PING:
  205. hr = HandlePing();
  206. break;
  207. case IPM_OP_SHUTDOWN:
  208. hr = HandleShutdown(
  209. *( reinterpret_cast<const BOOL *>( pPipeMessage->GetData() ) )
  210. );
  211. break;
  212. case IPM_OP_REQUEST_COUNTERS:
  213. hr = HandleCounterRequest();
  214. break;
  215. case IPM_OP_PERIODIC_PROCESS_RESTART_PERIOD_IN_MINUTES:
  216. // Issue 01/21/01: Jaroslad - Enable or remove for Beta3
  217. hr = NO_ERROR;
  218. break;
  219. case IPM_OP_PERIODIC_PROCESS_RESTART_REQUEST_COUNT:
  220. // Issue 01/21/01: Jaroslad - Enable or remove for Beta3
  221. hr = NO_ERROR;
  222. break;
  223. case IPM_OP_PERIODIC_PROCESS_RESTART_MEMORY_USAGE_IN_KB:
  224. DBG_ASSERT( pPipeMessage->GetData() != NULL );
  225. hr = WP_RECYCLER::StartMemoryBased(
  226. *( reinterpret_cast<const DWORD *>( pPipeMessage->GetData() ) )
  227. );
  228. hr = NO_ERROR;
  229. break;
  230. case IPM_OP_PERIODIC_PROCESS_RESTART_SCHEDULE:
  231. DBG_ASSERT( pPipeMessage->GetData() != NULL );
  232. hr = WP_RECYCLER::StartScheduleBased(
  233. ( reinterpret_cast<const WCHAR *>( pPipeMessage->GetData() ) )
  234. );
  235. hr = NO_ERROR;
  236. break;
  237. default:
  238. DBG_ASSERT(FALSE);
  239. hr = E_FAIL;
  240. break;
  241. }
  242. return hr;
  243. }
  244. /**
  245. *
  246. * Routine Description:
  247. *
  248. * This is a callback from the message pipe that means
  249. * the pipe has been connected and is ready for use.
  250. *
  251. * Arguments:
  252. *
  253. * None.
  254. *
  255. * Return Value:
  256. *
  257. * HRESULT
  258. */
  259. HRESULT
  260. WP_IPM::PipeConnected(
  261. VOID
  262. )
  263. {
  264. DBG_ASSERT(m_hConnectEvent);
  265. DBG_REQUIRE( SetEvent(m_hConnectEvent) );
  266. return S_OK;
  267. }
  268. /**
  269. *
  270. * Routine Description:
  271. *
  272. * This is a callback from the message pipe that means
  273. * the pipe has been disconnected and you won't be receiving
  274. * any more messages.
  275. *
  276. * Tells WPIPM::Terminate that it's ok to exit now.
  277. *
  278. * Arguments:
  279. *
  280. * hr - the error code associated with the pipe disconnection
  281. *
  282. * Return Value:
  283. *
  284. * HRESULT
  285. */
  286. HRESULT
  287. WP_IPM::PipeDisconnected(
  288. IN HRESULT hr
  289. )
  290. {
  291. //
  292. // CODEWORK: should we do something with the parameter?
  293. //
  294. if (FAILED(hr))
  295. {
  296. WpTrace(WPIPM, (DBG_CONTEXT, "PipeDisconnected with hr ( %d).\n", hr));
  297. }
  298. //
  299. // If the pipe disappears out from under us, assume the WAS has
  300. // gone bad, and initiate fast shutdown of this worker process.
  301. //
  302. m_pWpContext->IndicateShutdown( TRUE );
  303. if (SetEvent(m_hTerminateEvent)) {
  304. return S_OK;
  305. } else {
  306. return HRESULT_FROM_WIN32(GetLastError());
  307. }
  308. }
  309. /**
  310. *
  311. * Routine Description:
  312. *
  313. * Handles the ping message. Sends the ping response message.
  314. *
  315. * Arguments:
  316. *
  317. * None.
  318. *
  319. * Return Value:
  320. *
  321. * HRESULT
  322. */
  323. HRESULT
  324. WP_IPM::HandlePing(
  325. VOID
  326. )
  327. {
  328. HRESULT hr;
  329. WpTrace(WPIPM, (DBG_CONTEXT, "Handle Ping\n\n"));
  330. hr = m_pPipe->WriteMessage(
  331. IPM_OP_PING_REPLY, // ping reply opcode
  332. 0, // no data to send
  333. NULL // pointer to no data
  334. );
  335. return hr;
  336. }
  337. /**
  338. *
  339. * Routine Description:
  340. *
  341. * Handles the counter request message.
  342. *
  343. * Arguments:
  344. *
  345. * None.
  346. *
  347. * Return Value:
  348. *
  349. * HRESULT
  350. */
  351. HRESULT
  352. WP_IPM::HandleCounterRequest(
  353. VOID
  354. )
  355. {
  356. WpTrace(WPIPM, (DBG_CONTEXT, "Handle Counter Request\n\n"));
  357. HRESULT hr;
  358. PBYTE pCounterData;
  359. DWORD dwCounterData;
  360. if (FAILED(hr = g_pfnCollectCounters(&pCounterData, &dwCounterData)))
  361. {
  362. return hr;
  363. }
  364. return m_pPipe->WriteMessage(IPM_OP_SEND_COUNTERS, // ping reply opcode
  365. dwCounterData, // no data to send
  366. pCounterData); // pointer to no data
  367. }
  368. /**
  369. *
  370. * Routine Description:
  371. *
  372. *
  373. * Handles the shutdown message. Shuts down the process
  374. *
  375. * Arguments:
  376. *
  377. * None.
  378. *
  379. * Return Value:
  380. *
  381. * HRESULT
  382. */
  383. HRESULT
  384. WP_IPM::HandleShutdown(
  385. BOOL fDoImmediate
  386. )
  387. {
  388. HRESULT hr = S_OK;
  389. WpTrace(WPIPM, (DBG_CONTEXT, "Handle ******************** Shutdown\n\n"));
  390. m_pWpContext->IndicateShutdown( fDoImmediate );
  391. return hr;
  392. }
  393. /**
  394. *
  395. * Routine Description:
  396. *
  397. * Sends the message to indicate the worker process has either finished
  398. * initializing or has failed to initialize.
  399. *
  400. * Arguments:
  401. *
  402. * HRESULT indicating success/failure of initialization
  403. *
  404. * Return Value:
  405. *
  406. * HRESULT
  407. */
  408. HRESULT
  409. WP_IPM::SendInitCompleteMessage(
  410. HRESULT hrToSend
  411. )
  412. {
  413. return m_pPipe->WriteMessage(
  414. IPM_OP_HRESULT, // opcode
  415. sizeof( hrToSend ), // data length
  416. reinterpret_cast<BYTE*>( &hrToSend ) // pointer to data
  417. );
  418. }
  419. /**
  420. *
  421. * Routine Description:
  422. *
  423. * Sends the message to indicate the worker process has reach certain state.
  424. * Main use is in shutdown. See IPM_WP_SHUTDOWN_MSG for reasons.
  425. *
  426. * Arguments:
  427. *
  428. * None.
  429. *
  430. * Return Value:
  431. *
  432. * HRESULT
  433. */
  434. HRESULT
  435. WP_IPM::SendMsgToAdminProcess(
  436. IPM_WP_SHUTDOWN_MSG reason
  437. )
  438. {
  439. return m_pPipe->WriteMessage(
  440. IPM_OP_WORKER_REQUESTS_SHUTDOWN, // sends message indicate shutdown
  441. sizeof(reason), // no data to send
  442. (BYTE *)&reason // pointer to no data
  443. );
  444. }