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.

1102 lines
33 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1993 **/
  4. /**********************************************************************/
  5. /*
  6. entrypts.cxx
  7. This file implements the Extensible Performance Objects for
  8. the iis counters.
  9. FILE HISTORY:
  10. EmilyK 24-Aug-2000 Created, based on w3ctrs code.
  11. */
  12. #include "precomp.h"
  13. //
  14. // common defines & globals
  15. //
  16. #define MAX_STRINGIZED_ULONG_CHAR_COUNT 11 // "4294967295", including the terminating null
  17. DWORD g_IIS_SecondsToNotLogFor = 60 * 60 * 12; // 60 seconds = 1 minute * 60 = 1 hour * 12 = 12 hours
  18. //
  19. // Public prototypes.
  20. //
  21. PM_OPEN_PROC OpenW3PerformanceData;
  22. PM_COLLECT_PROC CollectW3PerformanceData;
  23. PM_CLOSE_PROC CloseW3PerformanceData;
  24. //
  25. // Global object contecting to the site counters memory.
  26. //
  27. CRITICAL_SECTION g_IISMemManagerCriticalSection;
  28. PERF_SM_MANAGER* g_pIISMemManager;
  29. LONG g_IISNumberInitialized;
  30. HANDLE g_hWASProcessWait;
  31. // Pointer to the event log class so we can log problems with perf counters.
  32. EVENT_LOG* g_pEventLog = NULL;
  33. //
  34. // Private Supporting Functions
  35. //
  36. /***************************************************************************++
  37. Routine Description:
  38. Looks up in the registry all the specific counter values
  39. that we need to be able to play nice with the other counters
  40. on the machine.
  41. Arguments:
  42. None
  43. Return Value:
  44. DWORD - Win32 Error Code
  45. --***************************************************************************/
  46. DWORD EstablishIndexes()
  47. {
  48. DWORD err = NO_ERROR;
  49. HKEY hkey = NULL;
  50. DWORD size;
  51. DWORD type;
  52. DWORD dwFirstCounter;
  53. DWORD dwFirstHelp;
  54. PERF_COUNTER_DEFINITION* pDefinition = NULL;
  55. //
  56. // Open the HTTP Server service's Performance key.
  57. //
  58. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  59. REGISTRY_KEY_W3SVC_PERFORMANCE_KEY_A,
  60. 0,
  61. KEY_QUERY_VALUE,
  62. &hkey );
  63. if( err == NO_ERROR)
  64. {
  65. //
  66. // Read the first counter DWORD.
  67. //
  68. size = sizeof(DWORD);
  69. err = RegQueryValueEx( hkey,
  70. "First Counter",
  71. NULL,
  72. &type,
  73. (LPBYTE)&dwFirstCounter,
  74. &size );
  75. if( err == NO_ERROR && type == REG_DWORD )
  76. {
  77. //
  78. // Read the first help DWORD.
  79. //
  80. size = sizeof(DWORD);
  81. err = RegQueryValueEx( hkey,
  82. "First Help",
  83. NULL,
  84. &type,
  85. (LPBYTE)&dwFirstHelp,
  86. &size );
  87. if ( err == NO_ERROR && type == REG_DWORD )
  88. {
  89. //
  90. // First establish all of the W3 Service Counters
  91. // ==============================================
  92. //
  93. // Update the object & counter name & help indicies.
  94. //
  95. W3DataDefinition.W3ObjectType.ObjectNameTitleIndex
  96. += dwFirstCounter;
  97. W3DataDefinition.W3ObjectType.ObjectHelpTitleIndex
  98. += dwFirstHelp;
  99. //
  100. // Figure out the first counter definition. It starts
  101. // after the PERF_OBJECT_TYPE structure, which is the
  102. // first iten in the W3DataDefinition.
  103. //
  104. pDefinition = (PERF_COUNTER_DEFINITION*) ((LPBYTE) (&W3DataDefinition)
  105. + sizeof(PERF_OBJECT_TYPE));
  106. //
  107. // Now simply walk through the counters incrementing
  108. // the pDefinition by on PERF_COUNTER_DEFINITION as you go.
  109. //
  110. for (int i = 0; i < NUMBER_OF_W3_COUNTERS; i++, pDefinition++)
  111. {
  112. pDefinition->CounterNameTitleIndex += dwFirstCounter;
  113. pDefinition->CounterHelpTitleIndex += dwFirstHelp;
  114. }
  115. //
  116. // Now do all of the W3 Global Service Counters
  117. // ============================================
  118. //
  119. // Update the object & counter name & help indicies.
  120. //
  121. W3GlobalDataDefinition.W3GlobalObjectType.ObjectNameTitleIndex
  122. += dwFirstCounter;
  123. W3GlobalDataDefinition.W3GlobalObjectType.ObjectHelpTitleIndex
  124. += dwFirstHelp;
  125. //
  126. // Figure out the first counter definition. It starts
  127. // after the PERF_OBJECT_TYPE structure, which is the
  128. // first iten in the W3DataDefinition.
  129. //
  130. pDefinition = (PERF_COUNTER_DEFINITION*)
  131. ((LPBYTE) (&W3GlobalDataDefinition)
  132. + sizeof(PERF_OBJECT_TYPE));
  133. //
  134. // Now simply walk through the counters incrementing
  135. // the pDefinition by on PERF_COUNTER_DEFINITION as you go.
  136. //
  137. for ( int i = 0;
  138. i < NUMBER_OF_W3_GLOBAL_COUNTERS;
  139. i++, pDefinition++ )
  140. {
  141. pDefinition->CounterNameTitleIndex += dwFirstCounter;
  142. pDefinition->CounterHelpTitleIndex += dwFirstHelp;
  143. }
  144. }
  145. }
  146. if( hkey != NULL )
  147. {
  148. RegCloseKey( hkey );
  149. hkey = NULL;
  150. }
  151. }
  152. return err;
  153. }
  154. /***************************************************************************++
  155. Routine Description:
  156. Routine deletes the shared memory if it is in existence.
  157. Arguments:
  158. None
  159. Return Value:
  160. None
  161. Note: It should always be called from inside a critical section.
  162. --***************************************************************************/
  163. VOID FreeSharedManager(BOOL HandleCallbackAsWell
  164. )
  165. {
  166. //
  167. // Only clean up the callback handle if we are told
  168. // to, this is so we don't clean it up if we are
  169. // in the middle of a callback call.
  170. //
  171. if ( HandleCallbackAsWell && g_hWASProcessWait )
  172. {
  173. if ( !UnregisterWait( g_hWASProcessWait ) )
  174. {
  175. DPERROR((
  176. DBG_CONTEXT,
  177. HRESULT_FROM_WIN32(GetLastError()),
  178. "Could not unregister the old process wait handle \n"
  179. ));
  180. }
  181. g_hWASProcessWait = NULL;
  182. }
  183. //
  184. // Now clean up the shared memory object.
  185. //
  186. if ( g_pIISMemManager )
  187. {
  188. delete g_pIISMemManager;
  189. g_pIISMemManager = NULL;
  190. }
  191. }
  192. /***************************************************************************++
  193. Routine Description:
  194. Routine drops the shared memory if the managing process of the memory
  195. goes away.
  196. Arguments:
  197. LPVOID lpParameter - Unused
  198. BOOL bUnused - Unused
  199. Return Value:
  200. None
  201. --***************************************************************************/
  202. VOID CALLBACK ShutdownMemory(
  203. PVOID,
  204. BOOLEAN
  205. )
  206. {
  207. EnterCriticalSection ( &g_IISMemManagerCriticalSection );
  208. FreeSharedManager(FALSE);
  209. LeaveCriticalSection ( &g_IISMemManagerCriticalSection );
  210. }
  211. /***************************************************************************++
  212. Routine Description:
  213. Helper function to hook up to shared memory when we are ready to
  214. provide counters.
  215. Arguments:
  216. None.
  217. Return Value:
  218. DWORD - Win32 Error Code
  219. --***************************************************************************/
  220. DWORD
  221. HookUpSharedMemory()
  222. {
  223. DWORD dwErr = ERROR_SUCCESS;
  224. DWORD size = 0;
  225. DWORD type = 0;
  226. DWORD dwRegSettingValue = 0;
  227. HKEY hkey = NULL;
  228. //
  229. // If we are not hooked up to the manager than hook up.
  230. //
  231. if ( !g_pIISMemManager )
  232. {
  233. //
  234. // Hook up to the manager of the shared memory.
  235. //
  236. g_pIISMemManager = new PERF_SM_MANAGER();
  237. if ( ! g_pIISMemManager )
  238. {
  239. dwErr = ERROR_OUTOFMEMORY;
  240. goto exit;
  241. }
  242. //
  243. // Initialize the memory manager for readonly access
  244. //
  245. dwErr = g_pIISMemManager->Initialize(FALSE);
  246. if ( dwErr != ERROR_SUCCESS )
  247. {
  248. goto exit;
  249. }
  250. // This ( in the Initialize call above ) is when we read
  251. // the wait times for the perf counters
  252. // from the registry so this is when we should set the logging
  253. // wait time as well.
  254. //
  255. dwErr = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  256. REGISTRY_KEY_W3SVC_PERFORMANCE_KEY_W,
  257. 0,
  258. KEY_QUERY_VALUE,
  259. &hkey );
  260. if( dwErr == ERROR_SUCCESS)
  261. {
  262. size = sizeof(DWORD);
  263. dwErr = RegQueryValueExW( hkey,
  264. REGISTRY_VALUE_W3SVC_PERF_EVENT_LOG_DELAY_OVERRIDE_W,
  265. NULL,
  266. &type,
  267. (LPBYTE)&dwRegSettingValue,
  268. &size );
  269. if( dwErr == ERROR_SUCCESS && type == REG_DWORD )
  270. {
  271. if ( dwRegSettingValue != 0 )
  272. {
  273. g_IIS_SecondsToNotLogFor = dwRegSettingValue;
  274. }
  275. }
  276. if( hkey != NULL )
  277. {
  278. RegCloseKey( hkey );
  279. hkey = NULL;
  280. }
  281. }
  282. // Press on in the face of errors.
  283. dwErr = ERROR_SUCCESS;
  284. //
  285. //
  286. // if we re-initialized then we need to setup the
  287. // wait on the process again. it is possible that
  288. // the previous wait has not been cleaned up (since
  289. // we can't clean it up in the callback function) so
  290. // if this is the case we need to clean it up first.
  291. //
  292. if ( g_hWASProcessWait != NULL )
  293. {
  294. if ( !UnregisterWait( g_hWASProcessWait ) )
  295. {
  296. DPERROR((
  297. DBG_CONTEXT,
  298. HRESULT_FROM_WIN32(GetLastError()),
  299. "Could not unregister the old process wait handle \n"
  300. ));
  301. }
  302. g_hWASProcessWait = NULL;
  303. }
  304. //
  305. // Register to wait on the managing process,
  306. // so we release any shared memory if the managing
  307. // process shutsdown or crashes.
  308. //
  309. if ( !RegisterWaitForSingleObject( &g_hWASProcessWait,
  310. g_pIISMemManager->GetWASProcessHandle(),
  311. &ShutdownMemory,
  312. NULL,
  313. INFINITE,
  314. WT_EXECUTEONLYONCE |
  315. WT_EXECUTEINIOTHREAD ) )
  316. {
  317. dwErr = GetLastError();
  318. DPERROR((
  319. DBG_CONTEXT,
  320. HRESULT_FROM_WIN32(dwErr),
  321. "Could not register to wait on the process handle \n"
  322. ));
  323. goto exit;
  324. }
  325. //
  326. // Initialize a reader to point to the appropriate
  327. // counter set.
  328. //
  329. dwErr = g_pIISMemManager->CreateNewCounterSet( SITE_COUNTER_SET );
  330. if ( dwErr != ERROR_SUCCESS )
  331. {
  332. goto exit;
  333. }
  334. //
  335. // Initialize a reader to point to the appropriate
  336. // counter set.
  337. //
  338. dwErr = g_pIISMemManager->CreateNewCounterSet( GLOBAL_COUNTER_SET );
  339. if ( dwErr != ERROR_SUCCESS )
  340. {
  341. goto exit;
  342. }
  343. }
  344. //
  345. // Whether we just hooked up to the memory or not, we still want
  346. // to do one final check to make sure the memory is still valid.
  347. // It might have been invalidated in since the last gathering, or
  348. // it might have been invalidated while we were hooking up the
  349. // wait on the process id. Either way, if it is now not valid,
  350. // drop it.
  351. //
  352. if ( g_pIISMemManager->ReleaseIsNeeded() )
  353. {
  354. //
  355. // The exit will take care of deleteing
  356. // the memory manager which will release
  357. // the files.
  358. //
  359. dwErr = ERROR_NOT_READY;
  360. goto exit;
  361. }
  362. exit:
  363. if ( dwErr != ERROR_SUCCESS )
  364. {
  365. FreeSharedManager(TRUE);
  366. }
  367. return dwErr;
  368. }
  369. //
  370. // Public Exported functions.
  371. //
  372. /***************************************************************************++
  373. Routine Description:
  374. Is called to initialize any memory data structures needed for
  375. supporting the performance counter publishing.
  376. Arguments:
  377. Return Value:
  378. DWORD - Win32 Error Code
  379. --***************************************************************************/
  380. DWORD OpenW3PerformanceData( LPWSTR )
  381. {
  382. DWORD dwErr = ERROR_SUCCESS;
  383. static BOOL fInit = FALSE;
  384. IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
  385. {
  386. DBGPRINTF((
  387. DBG_CONTEXT,
  388. "Entering W3CTRS - OpenW3PerformanceData routine \n"
  389. ));
  390. }
  391. //
  392. // If we are the first one here then we can setup the
  393. // objects the correct way.
  394. //
  395. // Note: this is not neccessarily completely safe, but
  396. // it really isn't that big of a problem if these
  397. // objects get setup twice.
  398. //
  399. if ( !fInit )
  400. {
  401. //
  402. // Setup the event log so we can log errors.
  403. //
  404. // If this fails then the g_pEventLog will still
  405. // be null. We would not fail in this case, and
  406. // since we do not have the event viewer we really
  407. // don't have any place to log a message. We will
  408. // validate that this has been set before using it
  409. // throughout the code.
  410. //
  411. g_pEventLog = new EVENT_LOG(L"W3CTRS");
  412. //
  413. // Establish all machine static information about
  414. // the counters.
  415. //
  416. dwErr = EstablishIndexes();
  417. if ( dwErr != ERROR_SUCCESS )
  418. {
  419. if ( g_pEventLog )
  420. {
  421. g_pEventLog->
  422. LogEvent(
  423. W3_W3SVC_REGISTRATION_MAY_BE_BAD, // message id
  424. 0, // count of strings
  425. NULL, // array of strings
  426. HRESULT_FROM_WIN32(dwErr) // error code
  427. );
  428. }
  429. goto exit;
  430. }
  431. fInit = TRUE;
  432. }
  433. exit:
  434. IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
  435. {
  436. DBGPRINTF((
  437. DBG_CONTEXT,
  438. "Exiting W3CTRS - OpenW3PerformanceData routine \n"
  439. ));
  440. }
  441. return dwErr;
  442. } // OpenW3PerformanceData
  443. /***************************************************************************++
  444. Routine Description:
  445. Is called to retrieve counters from our library.
  446. Arguments:
  447. LPWSTR lpValueName - Name fo the set of counters to retrieve.
  448. LPVOID * lppData - On entry contains a pointer to the buffer to
  449. receive the completed PerfDataBlock & subordinate
  450. structures. On exit, points to the first bytes
  451. *after* the data structures added by this routine.
  452. LPDWORD lpcbTotalBytes - On entry contains a pointer to the
  453. size (in BYTEs) of the buffer referenced by lppData.
  454. On exit, contains the number of BYTEs added by this
  455. routine.
  456. LPDWORD lpNumObjectTypes - Receives the number of objects added
  457. by this routine.
  458. Return Value:
  459. DWORD - Win32 Error Code (MUST be either NO_ERROR or ERROR_MORE_DATA)
  460. --***************************************************************************/
  461. DWORD CollectW3PerformanceData(
  462. LPWSTR lpValueName,
  463. LPVOID * lppData,
  464. LPDWORD lpcbTotalBytes,
  465. LPDWORD lpNumObjectTypes
  466. )
  467. {
  468. DBG_ASSERT ( lppData );
  469. DBG_ASSERT ( lpcbTotalBytes );
  470. DBG_ASSERT ( lpNumObjectTypes );
  471. static DWORD s_FirstFailureAt = 0;
  472. static DWORD s_NumberOfTimesTookToLong = 0;
  473. LPVOID pData = *lppData;
  474. COUNTER_GLOBAL_STRUCT* pSiteObject = NULL;
  475. LPVOID pSiteInstance = NULL;
  476. COUNTER_GLOBAL_STRUCT* pGlobalObject = NULL;
  477. LPVOID pGlobalInstance = NULL;
  478. DWORD dwErr = ERROR_SUCCESS;
  479. DWORD dwSiteSize = 0;
  480. DWORD dwGlobalSize = 0;
  481. DWORD dwTotalSize = 0;
  482. DWORD dwQueryType = GetQueryType( lpValueName );
  483. BOOL fGetSites = TRUE;
  484. BOOL fGetGlobal = TRUE;
  485. DWORD NumObjects = 2;
  486. //
  487. // Figure out if it is a query type we do not support.
  488. //
  489. if (( dwQueryType == QUERY_FOREIGN ) || (dwQueryType == QUERY_COSTLY))
  490. {
  491. // We don't do foreign queries
  492. *lpcbTotalBytes = 0;
  493. *lpNumObjectTypes = 0;
  494. return ERROR_SUCCESS;
  495. }
  496. //
  497. // If it is a query by item, then figure out if we own any of the
  498. // items it is referring to.
  499. //
  500. if( dwQueryType == QUERY_ITEMS )
  501. {
  502. //
  503. // The registry is asking for a specific object. Let's
  504. // see if we're one of the chosen.
  505. //
  506. if( !IsNumberInUnicodeList(
  507. W3DataDefinition.W3ObjectType.ObjectNameTitleIndex,
  508. lpValueName ) )
  509. {
  510. fGetSites = FALSE;
  511. NumObjects--;
  512. }
  513. if( !IsNumberInUnicodeList(
  514. W3GlobalDataDefinition.W3GlobalObjectType.ObjectNameTitleIndex,
  515. lpValueName ) )
  516. {
  517. fGetGlobal = FALSE;
  518. NumObjects--;
  519. }
  520. if ( NumObjects == 0 )
  521. {
  522. *lpcbTotalBytes = 0;
  523. *lpNumObjectTypes = 0;
  524. return ERROR_SUCCESS;
  525. }
  526. }
  527. IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
  528. {
  529. DBGPRINTF((
  530. DBG_CONTEXT,
  531. "Entering W3CTRS - CollectW3PerformanceData routine \n"
  532. ));
  533. }
  534. //
  535. // if we got this far then we know that we want to get something.
  536. //
  537. EnterCriticalSection ( &g_IISMemManagerCriticalSection );
  538. dwErr = HookUpSharedMemory();
  539. if ( dwErr != ERROR_SUCCESS )
  540. {
  541. DWORD dwSizeNeeded = 0;
  542. DBG_ASSERT ( fGetSites || fGetGlobal );
  543. if ( fGetSites )
  544. {
  545. dwSizeNeeded += sizeof(W3DataDefinition) +
  546. sizeof(PERF_INSTANCE_DEFINITION) +
  547. (sizeof(WCHAR) * MAX_INSTANCE_NAME ) +
  548. sizeof(W3_COUNTER_BLOCK);
  549. }
  550. if ( fGetGlobal )
  551. {
  552. dwSizeNeeded += sizeof( W3GlobalDataDefinition )
  553. + sizeof( W3_GLOBAL_COUNTER_BLOCK );
  554. }
  555. if ( dwSizeNeeded > *lpcbTotalBytes )
  556. {
  557. *lpcbTotalBytes = 0;
  558. *lpNumObjectTypes = 0;
  559. dwErr = ERROR_MORE_DATA;
  560. }
  561. else
  562. {
  563. if ( fGetSites )
  564. {
  565. memcpy (pData, &W3DataDefinition, sizeof(W3DataDefinition));
  566. ((PERF_OBJECT_TYPE*) pData)->NumInstances = 1;
  567. ((PERF_OBJECT_TYPE*) pData)->TotalByteLength = sizeof(W3DataDefinition) +
  568. sizeof(PERF_INSTANCE_DEFINITION) +
  569. (sizeof(WCHAR) * MAX_INSTANCE_NAME) +
  570. sizeof(W3_COUNTER_BLOCK);
  571. pData = (LPBYTE) pData + sizeof(W3DataDefinition);
  572. // Copy in a _Total instance
  573. // First Setup the Instance Definition
  574. ((PERF_INSTANCE_DEFINITION*) pData)->ByteLength = sizeof(PERF_INSTANCE_DEFINITION) +
  575. MAX_INSTANCE_NAME * sizeof(WCHAR);
  576. ((PERF_INSTANCE_DEFINITION*) pData)->ParentObjectTitleIndex = 0;
  577. ((PERF_INSTANCE_DEFINITION*) pData)->ParentObjectInstance = 0;
  578. ((PERF_INSTANCE_DEFINITION*) pData)->UniqueID = PERF_NO_UNIQUE_ID;
  579. ((PERF_INSTANCE_DEFINITION*) pData)->NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
  580. ((PERF_INSTANCE_DEFINITION*) pData)->NameLength = (DWORD) ((wcslen(L"_Total") + 1) * sizeof(WCHAR));
  581. pData = (LPBYTE) pData + sizeof(PERF_INSTANCE_DEFINITION);
  582. // Next copy in the Instance Name including the
  583. // NULL, we know we have enough room because of
  584. // the check above for size.
  585. wcsncpy ( (LPWSTR) pData, L"_Total", wcslen(L"_Total") + 1 );
  586. // To avoid suttle differences we use the same MAX_INSTANCE_NAME
  587. // amount of space even for this faked up _Total Site.
  588. pData = (LPBYTE) pData + ( MAX_INSTANCE_NAME * sizeof(WCHAR));
  589. // Lastly copy in a block of zero's for the _Total site data.
  590. memset ( pData, 0, sizeof(W3_COUNTER_BLOCK) );
  591. // This is setting the size in the structure, it is the first
  592. // DWORD in the W3_CONTER_BLOCK.
  593. *((DWORD*) (pData)) = sizeof(W3_COUNTER_BLOCK);
  594. pData = (LPBYTE) pData + sizeof(W3_COUNTER_BLOCK);
  595. }
  596. if ( fGetGlobal )
  597. {
  598. memcpy (pData, &W3GlobalDataDefinition, sizeof(W3GlobalDataDefinition));
  599. ((PERF_OBJECT_TYPE*) pData)->NumInstances = PERF_NO_INSTANCES;
  600. ((PERF_OBJECT_TYPE*) pData)->TotalByteLength = sizeof(W3GlobalDataDefinition) +
  601. sizeof(W3_GLOBAL_COUNTER_BLOCK);
  602. pData = (LPBYTE) pData + sizeof(W3GlobalDataDefinition);
  603. // Copy in the actual data for global
  604. memset ( pData, 0, sizeof(W3_GLOBAL_COUNTER_BLOCK) );
  605. // This is setting the size in the structure, it is the first
  606. // DWORD in the W3_GLOBAL_CONTER_BLOCK.
  607. *((DWORD*) (pData)) = sizeof(W3_GLOBAL_COUNTER_BLOCK);
  608. pData = (LPBYTE) pData + sizeof(W3_GLOBAL_COUNTER_BLOCK);
  609. }
  610. // Make sure we didn't lie about the size.
  611. DBG_ASSERT ( dwSizeNeeded == DIFF((PCHAR) pData - (PCHAR) (*lppData)) );
  612. *lpcbTotalBytes = dwSizeNeeded;
  613. *lpNumObjectTypes = NumObjects;
  614. *lppData = pData;
  615. dwErr = ERROR_SUCCESS;
  616. }
  617. goto exit;
  618. }
  619. DBG_ASSERT ( g_pIISMemManager );
  620. //
  621. // Now check that the memory has been updated recently. If it has
  622. // not been then we need to ping WAS and let them know that we need
  623. // new data, and wait on that new data.
  624. //
  625. if ( ! g_pIISMemManager->EvaluateIfCountersAreFresh() )
  626. {
  627. if ( g_pEventLog )
  628. {
  629. IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
  630. {
  631. DBGPRINTF((
  632. DBG_CONTEXT,
  633. "Perf Counters did not refresh in a timely manner: \n"
  634. " CurrentSecondsCount = %d \n"
  635. " FirstFailure was %d \n"
  636. " Time to wait to restart is %d \n"
  637. " NumberFailures = %d \n",
  638. GetCurrentTimeInSeconds(),
  639. s_FirstFailureAt,
  640. g_IIS_SecondsToNotLogFor,
  641. s_NumberOfTimesTookToLong
  642. ));
  643. }
  644. if ( ( s_FirstFailureAt == 0 ) ||
  645. ( ( s_FirstFailureAt + g_IIS_SecondsToNotLogFor ) < GetCurrentTimeInSeconds() ) )
  646. {
  647. s_FirstFailureAt = GetCurrentTimeInSeconds();
  648. s_NumberOfTimesTookToLong = 0;
  649. }
  650. s_NumberOfTimesTookToLong++;
  651. if ( s_NumberOfTimesTookToLong == 1 )
  652. {
  653. g_pEventLog->
  654. LogEvent(
  655. W3_W3SVC_REFRESH_TAKING_TOO_LONG, // message id
  656. 0, // count of strings
  657. NULL, // array of strings
  658. 0 // error code
  659. );
  660. }
  661. if ( s_NumberOfTimesTookToLong == 2 )
  662. {
  663. DWORD Hours = g_IIS_SecondsToNotLogFor / 60 / 60;
  664. DWORD Minutes = ( g_IIS_SecondsToNotLogFor - ( Hours * 60 * 60 ) ) / 60;
  665. DWORD Seconds = g_IIS_SecondsToNotLogFor - ( Hours * 60 * 60 ) - ( Minutes * 60 );
  666. const WCHAR * EventLogStrings[1];
  667. // Format is "DWORD:DWORD:DWORD" So 3 max dwords plus two colons and a null
  668. WCHAR StringizedTimeLimit[ (MAX_STRINGIZED_ULONG_CHAR_COUNT * 3) + 3 ];
  669. _snwprintf( StringizedTimeLimit,
  670. sizeof( StringizedTimeLimit ) / sizeof ( WCHAR ),
  671. L"%lu:%02lu:%02lu",
  672. Hours,
  673. Minutes,
  674. Seconds);
  675. EventLogStrings[0] = StringizedTimeLimit;
  676. g_pEventLog->
  677. LogEvent(
  678. W3_W3SVC_REFRESH_TAKING_TOO_LONG_STOPPING_LOGGING, // message id
  679. sizeof( EventLogStrings ) / sizeof( const WCHAR * ), // count of strings
  680. EventLogStrings, // array of strings
  681. 0 // error code
  682. );
  683. // if s_NumberOfTimesTookToLong is anything else
  684. // then we don't bother printing anything.
  685. }
  686. }
  687. }
  688. if ( fGetSites)
  689. {
  690. //
  691. // Get the counter information from shared memory.
  692. //
  693. dwErr = g_pIISMemManager->GetCounterInfo(SITE_COUNTER_SET,
  694. &pSiteObject,
  695. &pSiteInstance);
  696. if ( dwErr != ERROR_SUCCESS )
  697. {
  698. if ( g_pEventLog )
  699. {
  700. g_pEventLog->
  701. LogEvent(
  702. W3_UNABLE_QUERY_W3SVC_DATA, // message id
  703. 0, // count of strings
  704. NULL, // array of strings
  705. HRESULT_FROM_WIN32(dwErr) // error code
  706. );
  707. }
  708. //
  709. // According to the perf by laws you can only
  710. // return Success or More Data from here so
  711. // we will need to log the error and then return
  712. // Success, since this does not mean we have more data.
  713. //
  714. *lpcbTotalBytes = 0;
  715. *lpNumObjectTypes = 0;
  716. dwErr = ERROR_SUCCESS;
  717. goto exit;
  718. }
  719. dwSiteSize = sizeof(W3DataDefinition) + pSiteObject->SizeData;
  720. }
  721. if ( fGetGlobal )
  722. {
  723. //
  724. // Get the counter information from shared memory.
  725. //
  726. dwErr = g_pIISMemManager->GetCounterInfo(GLOBAL_COUNTER_SET,
  727. &pGlobalObject,
  728. &pGlobalInstance);
  729. if ( dwErr != ERROR_SUCCESS )
  730. {
  731. if ( g_pEventLog )
  732. {
  733. g_pEventLog->
  734. LogEvent(
  735. W3_UNABLE_QUERY_W3SVC_DATA, // message id
  736. 0, // count of strings
  737. NULL, // array of strings
  738. HRESULT_FROM_WIN32(dwErr) // error code
  739. );
  740. }
  741. //
  742. // According to the perf by laws you can only
  743. // return Success or More Data from here so
  744. // we will need to log the error and then return
  745. // Success, since this does not mean we have more data.
  746. //
  747. *lpcbTotalBytes = 0;
  748. *lpNumObjectTypes = 0;
  749. dwErr = ERROR_SUCCESS;
  750. goto exit;
  751. }
  752. dwGlobalSize = sizeof(W3GlobalDataDefinition) +
  753. pGlobalObject->SizeData;
  754. }
  755. //
  756. // Figure out the total size of the memory
  757. //
  758. dwTotalSize = dwSiteSize + dwGlobalSize;
  759. //
  760. // If we don't have room tell the counter library.
  761. //
  762. if ( dwTotalSize > *lpcbTotalBytes )
  763. {
  764. *lpcbTotalBytes = 0;
  765. *lpNumObjectTypes = 0;
  766. dwErr = ERROR_MORE_DATA;
  767. goto exit;
  768. }
  769. if ( fGetSites )
  770. {
  771. //
  772. // Copy in the definition of the data for sites.
  773. //
  774. memcpy (pData, &W3DataDefinition, sizeof(W3DataDefinition));
  775. ((PERF_OBJECT_TYPE*) pData)->NumInstances = pSiteObject->NumInstances;
  776. ((PERF_OBJECT_TYPE*) pData)->TotalByteLength = dwSiteSize;
  777. pData = (LPBYTE) pData + sizeof(W3DataDefinition);
  778. // Copy in the actual data for sites
  779. memcpy ( pData, pSiteInstance, pSiteObject->SizeData );
  780. pData = (LPBYTE) pData + pSiteObject->SizeData;
  781. }
  782. if ( fGetGlobal )
  783. {
  784. //
  785. // Copy in the definition of the data for global
  786. //
  787. memcpy (pData, &W3GlobalDataDefinition, sizeof(W3GlobalDataDefinition));
  788. ((PERF_OBJECT_TYPE*) pData)->NumInstances = pGlobalObject->NumInstances;
  789. ((PERF_OBJECT_TYPE*) pData)->TotalByteLength = dwGlobalSize;
  790. pData = (LPBYTE) pData + sizeof(W3GlobalDataDefinition);
  791. // Copy in the actual data for global
  792. memcpy ( pData, pGlobalInstance, pGlobalObject->SizeData );
  793. pData = (LPBYTE) pData + pGlobalObject->SizeData;
  794. }
  795. // Make sure we didn't lie about the size.
  796. DBG_ASSERT ( dwTotalSize == DIFF((PCHAR) pData - (PCHAR) (*lppData)) );
  797. *lpcbTotalBytes = dwTotalSize;
  798. *lpNumObjectTypes = NumObjects;
  799. *lppData = pData;
  800. //
  801. // Let WAS know that we need new counters.
  802. //
  803. g_pIISMemManager->PingWASToRefreshCounters();
  804. exit:
  805. LeaveCriticalSection ( &g_IISMemManagerCriticalSection );
  806. IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
  807. {
  808. DBGPRINTF((
  809. DBG_CONTEXT,
  810. "Exiting W3CTRS - CollectW3PerformanceData routine \n"
  811. ));
  812. }
  813. return dwErr;
  814. } // CollectW3PerformanceData
  815. /***************************************************************************++
  816. Routine Description:
  817. Terminates the performance counters.
  818. Arguments:
  819. None.
  820. Return Value:
  821. DWORD - Win32 Error Code
  822. --***************************************************************************/
  823. DWORD CloseW3PerformanceData( VOID )
  824. {
  825. //
  826. // On tclose tell the timer queue to stop launching
  827. // the checking code.
  828. //
  829. // Note if someone calls close and then collect again
  830. // we will have stopped listening to notifications from
  831. // w3svc and will not know when to drop the memory.
  832. //
  833. IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
  834. {
  835. DBGPRINTF((
  836. DBG_CONTEXT,
  837. "Entering W3CTRS - CloseW3PerformanceData routine \n"
  838. ));
  839. }
  840. EnterCriticalSection ( &g_IISMemManagerCriticalSection );
  841. FreeSharedManager(TRUE);
  842. LeaveCriticalSection( &g_IISMemManagerCriticalSection );
  843. if ( g_pEventLog )
  844. {
  845. delete g_pEventLog;
  846. g_pEventLog = NULL;
  847. }
  848. IF_DEBUG( WEB_ADMIN_SERVICE_PERFCOUNT )
  849. {
  850. DBGPRINTF((
  851. DBG_CONTEXT,
  852. "Exiting W3CTRS - CloseW3PerformanceData routine \n"
  853. ));
  854. }
  855. return ERROR_SUCCESS;
  856. } // CloseW3PerformanceData