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.

2120 lines
73 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 1992-1994 Microsoft Corporation
  3. Module Name:
  4. perflib.c
  5. Abstract:
  6. This file implements the Configuration Registry
  7. for the purposes of the Performance Monitor.
  8. This file contains the code which implements the Performance part
  9. of the Configuration Registry.
  10. Author:
  11. Russ Blake 11/15/91
  12. Revision History:
  13. 04/20/91 - russbl - Converted to lib in Registry
  14. from stand-alone .dll form.
  15. 11/04/92 - a-robw - added pagefile and image counter routines
  16. 11/01/96 - bobw - revamped to support dynamic loading and
  17. unloading of performance modules
  18. --*/
  19. #define UNICODE
  20. //
  21. // Include files
  22. //
  23. #pragma warning(disable:4306)
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. #include <ntregapi.h>
  28. #include <ntprfctr.h>
  29. #include <windows.h>
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include <winperf.h>
  33. #include <rpc.h>
  34. #include "regrpc.h"
  35. #include "ntconreg.h"
  36. #include "prflbmsg.h" // event log messages
  37. #include <initguid.h>
  38. #include <guiddef.h>
  39. #include <strsafe.h>
  40. #define _INIT_WINPERFP_
  41. #include "perflib.h"
  42. #pragma warning (default:4306)
  43. #define NUM_VALUES 2
  44. //
  45. // performance gathering thead priority
  46. //
  47. #define DEFAULT_THREAD_PRIORITY THREAD_BASE_PRIORITY_LOWRT
  48. //
  49. // constants
  50. //
  51. const WCHAR DLLValue[] = L"Library";
  52. const CHAR OpenValue[] = "Open";
  53. const CHAR CloseValue[] = "Close";
  54. const CHAR CollectValue[] = "Collect";
  55. const CHAR QueryValue[] = "Query";
  56. const WCHAR ObjListValue[] = L"Object List";
  57. const WCHAR LinkageKey[] = L"\\Linkage";
  58. const WCHAR ExportValue[] = L"Export";
  59. const WCHAR PerflibKey[] = L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
  60. const WCHAR HKLMPerflibKey[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
  61. const WCHAR CounterValue[] = L"Counter";
  62. const WCHAR HelpValue[] = L"Help";
  63. const WCHAR PerfSubKey[] = L"\\Performance";
  64. const WCHAR ExtPath[] = L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services";
  65. const WCHAR OpenTimeout[] = L"Open Timeout";
  66. const WCHAR CollectTimeout[] = L"Collect Timeout";
  67. const WCHAR EventLogLevel[] = L"EventLogLevel";
  68. const WCHAR ExtCounterTestLevel[] = L"ExtCounterTestLevel";
  69. const WCHAR OpenProcedureWaitTime[] = L"OpenProcedureWaitTime";
  70. const WCHAR TotalInstanceName[] = L"TotalInstanceName";
  71. const WCHAR LibraryUnloadTime[] = L"Library Unload Time";
  72. const WCHAR KeepResident[] = L"Keep Library Resident";
  73. const WCHAR NULL_STRING[] = L"\0"; // pointer to null string
  74. const WCHAR UseCollectionThread[] = L"UseCollectionThread";
  75. const WCHAR cszLibraryValidationData[] = L"Library Validation Code";
  76. const WCHAR cszSuccessfulFileData[] = L"Successful File Date";
  77. const WCHAR cszPerflibFlags[] = L"Configuration Flags";
  78. const WCHAR FirstCounter[] = L"First Counter";
  79. const WCHAR LastCounter[] = L"Last Counter";
  80. const WCHAR FirstHelp[] = L"First Help";
  81. const WCHAR LastHelp[] = L"Last Help";
  82. const WCHAR cszFailureCount[] = L"Error Count";
  83. const WCHAR cszFailureLimit[] = L"Error Count Limit";
  84. const WCHAR cszBusy[] = L"Updating";
  85. //
  86. // external variables defined in perfname.c
  87. //
  88. extern WCHAR DefaultLangId[];
  89. WCHAR NativeLangId[8] = L"\0";
  90. //
  91. // Data collection thread variables
  92. //
  93. #define COLLECTION_WAIT_TIME 10000L // 10 seconds to get all the data
  94. HANDLE hCollectThread = NULL;
  95. #define COLLECT_THREAD_PROCESS_EVENT 0
  96. #define COLLECT_THREAD_EXIT_EVENT 1
  97. #define COLLECT_THREAD_LOOP_EVENT_COUNT 2
  98. #define COLLECT_THREAD_DONE_EVENT 2
  99. #define COLLECT_THREAD_EVENT_COUNT 3
  100. HANDLE hCollectEvents[COLLECT_THREAD_EVENT_COUNT];
  101. BOOL bThreadHung = FALSE;
  102. DWORD CollectThreadFunction (LPVOID dwArg);
  103. #define COLL_FLAG_USE_SEPARATE_THREAD 1
  104. DWORD dwCollectionFlags = 0;
  105. //
  106. // Global variable Definitions
  107. //
  108. // event log handle for perflib generated errors
  109. //
  110. HANDLE hEventLog = NULL;
  111. //
  112. // used to count concurrent opens.
  113. //
  114. LONG NumberOfOpens = 0;
  115. //
  116. // Synchronization objects for Multi-threaded access
  117. //
  118. HANDLE hGlobalDataMutex = NULL; // sync for ctr object list
  119. //
  120. // computer name cache buffers. Initialized in predefh.c
  121. //
  122. DWORD ComputerNameLength;
  123. LPWSTR pComputerName = NULL;
  124. // The next pointer is used to point to an array of addresses of
  125. // Open/Collect/Close routines found by searching the Configuration Registry.
  126. // object list head
  127. PEXT_OBJECT ExtensibleObjects = NULL;
  128. //
  129. // count of active list users (threads)
  130. DWORD dwExtObjListRefCount = 0;
  131. //
  132. // event to indicate the object list is not in use
  133. HANDLE hExtObjListIsNotInUse = NULL;
  134. //
  135. // Number of Extensible Objects found during the "open" call
  136. DWORD NumExtensibleObjects = 0;
  137. //
  138. // see if the perflib data is restricted to ADMIN's ONLY or just anyone
  139. //
  140. LONG lCheckProfileSystemRight = CPSR_NOT_DEFINED;
  141. //
  142. // flag to see if the ProfileSystemPerformance priv should be set.
  143. // if it is attempted and the caller does not have permission to use this priv.
  144. // it won't be set. This is only attempted once.
  145. //
  146. BOOL bEnableProfileSystemPerfPriv = FALSE;
  147. //
  148. // timeout value (in mS) for timing threads & libraries
  149. //
  150. DWORD dwThreadAndLibraryTimeout = PERFLIB_TIMING_THREAD_TIMEOUT;
  151. // global key for access to HKLM\Software\....\Perflib
  152. //
  153. HKEY ghKeyPerflib = NULL;
  154. //
  155. // Error report frequency
  156. DWORD dwErrorFrequency = 1;
  157. LONG lEventLogLevel = LOG_USER;
  158. LONG lPerflibConfigFlags = PLCF_DEFAULT;
  159. DWORD dwErrorCount = 0;
  160. ERROR_LOG PerfpErrorLog;
  161. // performance data block entries
  162. WCHAR szPerflibSectionFile[MAX_PATH];
  163. WCHAR szPerflibSectionName[MAX_PATH];
  164. WCHAR szUpdatingServiceName[MAX_PATH];
  165. HANDLE hPerflibSectionFile = NULL;
  166. HANDLE hPerflibSectionMap = NULL;
  167. LPVOID lpPerflibSectionAddr = NULL;
  168. BOOL bPerflibOpen = FALSE;
  169. DWORD dwBoostPriority = 1;
  170. #define dwPerflibSectionMaxEntries 127L
  171. const DWORD dwPerflibSectionSize = (sizeof(PERFDATA_SECTION_HEADER) + \
  172. (sizeof(PERFDATA_SECTION_RECORD) * dwPerflibSectionMaxEntries));
  173. // forward function references
  174. LONG
  175. PerfEnumTextValue (
  176. IN HKEY hKey,
  177. IN DWORD dwIndex,
  178. OUT PUNICODE_STRING lpValueName,
  179. OUT LPDWORD lpReserved OPTIONAL,
  180. OUT LPDWORD lpType OPTIONAL,
  181. OUT LPBYTE lpData,
  182. IN OUT LPDWORD lpcbData,
  183. OUT LPDWORD lpcbLen OPTIONAL
  184. );
  185. #if 0 // collection thread functions are not supported
  186. DWORD
  187. OpenCollectionThread (
  188. )
  189. {
  190. BOOL bError = FALSE;
  191. DWORD dwThreadID;
  192. assert (hCollectThread == NULL);
  193. // if it's already created, then just return
  194. if (hCollectThread != NULL) return ERROR_SUCCESS;
  195. bThreadHung = FALSE;
  196. hCollectEvents[COLLECT_THREAD_PROCESS_EVENT] = CreateEvent (
  197. NULL, // default security
  198. FALSE, // auto reset
  199. FALSE, // non-signaled
  200. NULL); // no name
  201. bError = hCollectEvents[COLLECT_THREAD_PROCESS_EVENT] == NULL;
  202. assert (hCollectEvents[COLLECT_THREAD_PROCESS_EVENT] != NULL);
  203. hCollectEvents[COLLECT_THREAD_EXIT_EVENT] = CreateEvent (
  204. NULL, // default security
  205. FALSE, // auto reset
  206. FALSE, // non-signaled
  207. NULL); // no name
  208. bError = (hCollectEvents[COLLECT_THREAD_EXIT_EVENT] == NULL) | bError;
  209. assert (hCollectEvents[COLLECT_THREAD_EXIT_EVENT] != NULL);
  210. hCollectEvents[COLLECT_THREAD_DONE_EVENT] = CreateEvent (
  211. NULL, // default security
  212. FALSE, // auto reset
  213. FALSE, // non-signaled
  214. NULL); // no name
  215. bError = (hCollectEvents[COLLECT_THREAD_DONE_EVENT] == NULL) | bError;
  216. assert (hCollectEvents[COLLECT_THREAD_DONE_EVENT] != NULL);
  217. if (!bError) {
  218. // create data collection thread
  219. hCollectThread = CreateThread (
  220. NULL, // default security
  221. 0, // default stack size
  222. (LPTHREAD_START_ROUTINE)CollectThreadFunction,
  223. NULL, // no argument
  224. 0, // no flags
  225. &dwThreadID); // we don't need the ID so it's in an automatic variable
  226. if (hCollectThread == NULL) {
  227. bError = TRUE;
  228. }
  229. assert (hCollectThread != NULL);
  230. }
  231. if (bError) {
  232. if (hCollectEvents[COLLECT_THREAD_PROCESS_EVENT] != NULL) {
  233. CloseHandle (hCollectEvents[COLLECT_THREAD_PROCESS_EVENT]);
  234. hCollectEvents[COLLECT_THREAD_PROCESS_EVENT] = NULL;
  235. }
  236. if (hCollectEvents[COLLECT_THREAD_EXIT_EVENT] != NULL) {
  237. CloseHandle (hCollectEvents[COLLECT_THREAD_EXIT_EVENT]);
  238. hCollectEvents[COLLECT_THREAD_EXIT_EVENT] = NULL;
  239. }
  240. if (hCollectEvents[COLLECT_THREAD_DONE_EVENT] != NULL) {
  241. CloseHandle (hCollectEvents[COLLECT_THREAD_DONE_EVENT] = NULL);
  242. hCollectEvents[COLLECT_THREAD_DONE_EVENT] = NULL;
  243. }
  244. if (hCollectThread != NULL) {
  245. CloseHandle (hCollectThread);
  246. hCollectThread = NULL;
  247. }
  248. return (GetLastError());
  249. } else {
  250. return ERROR_SUCCESS;
  251. }
  252. }
  253. DWORD
  254. CloseCollectionThread (
  255. )
  256. {
  257. if (hCollectThread != NULL) {
  258. // close the data collection thread
  259. if (bThreadHung) {
  260. // then kill it the hard way
  261. // this might cause problems, but it's better than
  262. // a thread leak
  263. TerminateThread (hCollectThread, ERROR_TIMEOUT);
  264. } else {
  265. // then ask it to leave
  266. SetEvent (hCollectEvents[COLLECT_THREAD_EXIT_EVENT]);
  267. }
  268. // wait for thread to leave
  269. WaitForSingleObject (hCollectThread, COLLECTION_WAIT_TIME);
  270. // close the handles and clear the variables
  271. CloseHandle (hCollectThread);
  272. hCollectThread = NULL;
  273. CloseHandle (hCollectEvents[COLLECT_THREAD_PROCESS_EVENT]);
  274. hCollectEvents[COLLECT_THREAD_PROCESS_EVENT] = NULL;
  275. CloseHandle (hCollectEvents[COLLECT_THREAD_EXIT_EVENT]);
  276. hCollectEvents[COLLECT_THREAD_EXIT_EVENT] = NULL;
  277. CloseHandle (hCollectEvents[COLLECT_THREAD_DONE_EVENT]);
  278. hCollectEvents[COLLECT_THREAD_DONE_EVENT] = NULL;
  279. } else {
  280. // nothing was opened
  281. }
  282. return ERROR_SUCCESS;
  283. }
  284. #endif
  285. DWORD
  286. PerfOpenKey (
  287. IN HKEY hKey
  288. )
  289. {
  290. LARGE_INTEGER liPerfDataWaitTime;
  291. PLARGE_INTEGER pTimeout;
  292. NTSTATUS status = STATUS_SUCCESS;
  293. DWORD dwFnStatus = ERROR_SUCCESS; // status code to be returned
  294. DWORD dwError = ERROR_SUCCESS;
  295. DWORD dwType, dwSize, dwValue;
  296. HANDLE hDataMutex;
  297. OSVERSIONINFOEXW OsVersion;
  298. if (hGlobalDataMutex == NULL) {
  299. hDataMutex = CreateMutex(NULL, FALSE, NULL);
  300. if (hDataMutex == NULL) {
  301. DebugPrint((0, "Perf Data Mutex Not Initialized\n"));
  302. goto OPD_Error_Exit_NoSemaphore;
  303. }
  304. if (InterlockedCompareExchangePointer(
  305. &hGlobalDataMutex,
  306. hDataMutex,
  307. NULL) != NULL) {
  308. CloseHandle(hDataMutex); // mutex just got created by another thread
  309. hDataMutex = NULL;
  310. }
  311. }
  312. if ((dwThreadAndLibraryTimeout == 0) ||
  313. (dwThreadAndLibraryTimeout == INFINITE)) {
  314. pTimeout = NULL;
  315. }
  316. else {
  317. liPerfDataWaitTime.QuadPart = MakeTimeOutValue(dwThreadAndLibraryTimeout);
  318. pTimeout = &liPerfDataWaitTime;
  319. }
  320. status = NtWaitForSingleObject (
  321. hGlobalDataMutex, // Mutex
  322. FALSE, // not alertable
  323. pTimeout); // wait time
  324. if (status != STATUS_SUCCESS) {
  325. // unable to contine, return error;
  326. dwFnStatus = PerfpDosError(status);
  327. DebugPrint((0, "Status=%X in waiting for global mutex",
  328. status));
  329. goto OPD_Error_Exit_NoSemaphore;
  330. }
  331. // if here, then the data semaphore has been acquired by this thread
  332. if (InterlockedIncrement(& NumberOfOpens) == 1) {
  333. if (ghKeyPerflib == NULL) {
  334. HKEY lhKeyPerflib = NULL;
  335. dwFnStatus = (DWORD) RegOpenKeyExW(HKEY_LOCAL_MACHINE, HKLMPerflibKey, 0L, KEY_READ, & lhKeyPerflib);
  336. if (dwFnStatus != ERROR_SUCCESS) {
  337. DebugPrint((0, "Error=%d in RegOpenKeyExW call (%d)",
  338. dwFnStatus, __LINE__));
  339. goto OPD_Error_Exit_NoSemaphore;
  340. }
  341. else {
  342. if (InterlockedCompareExchangePointer(& ghKeyPerflib, lhKeyPerflib, NULL) != NULL) {
  343. RegCloseKey(lhKeyPerflib);
  344. lhKeyPerflib = NULL;
  345. }
  346. }
  347. }
  348. assert (ghKeyPerflib != NULL);
  349. // check if we are in the middle of Lodctr/unlodctr. If so, don't open the performance data stuff.
  350. //
  351. dwSize = MAX_PATH * sizeof(WCHAR);
  352. dwType = 0;
  353. ZeroMemory(szUpdatingServiceName, dwSize);
  354. dwFnStatus = PrivateRegQueryValueExW(ghKeyPerflib,
  355. cszBusy,
  356. NULL,
  357. & dwType,
  358. (LPBYTE) szUpdatingServiceName,
  359. & dwSize);
  360. if (dwFnStatus == ERROR_SUCCESS) {
  361. // someone is running lodctr/unlodctr, bail out now.
  362. //
  363. InterlockedDecrement(& NumberOfOpens);
  364. if (hGlobalDataMutex != NULL) {
  365. ReleaseMutex(hGlobalDataMutex);
  366. }
  367. dwFnStatus = ERROR_SUCCESS;
  368. goto OPD_Error_Exit_NoSemaphore;
  369. }
  370. dwSize = sizeof(dwValue);
  371. dwValue = dwType = 0;
  372. dwFnStatus = PrivateRegQueryValueExW (
  373. ghKeyPerflib,
  374. DisablePerformanceCounters,
  375. NULL,
  376. &dwType,
  377. (LPBYTE)&dwValue,
  378. &dwSize);
  379. if ((dwFnStatus == ERROR_SUCCESS) &&
  380. (dwType == REG_DWORD) &&
  381. (dwValue == 1)) {
  382. // then DON'T Load any libraries and unload any that have been
  383. // loaded
  384. InterlockedDecrement(&NumberOfOpens); // since it didn't open.
  385. dwFnStatus = ERROR_SERVICE_DISABLED;
  386. } else {
  387. dwFnStatus = ERROR_SUCCESS;
  388. ComputerNameLength = 0;
  389. GetComputerNameW(pComputerName, &ComputerNameLength);
  390. ComputerNameLength++; // account for the NULL terminator
  391. pComputerName = ALLOCMEM(ComputerNameLength * sizeof(WCHAR));
  392. if (pComputerName == NULL) {
  393. ComputerNameLength = 0;
  394. }
  395. else {
  396. if ( !GetComputerNameW(pComputerName, &ComputerNameLength) ) {
  397. //
  398. // Signal failure to data collection routine
  399. //
  400. ComputerNameLength = 0;
  401. } else {
  402. pComputerName[ComputerNameLength] = UNICODE_NULL;
  403. ComputerNameLength = (ComputerNameLength+1) * sizeof(WCHAR);
  404. }
  405. }
  406. WinPerfStartTrace(ghKeyPerflib);
  407. // create event and indicate the list is busy
  408. hExtObjListIsNotInUse = CreateEvent (NULL, TRUE, FALSE, NULL);
  409. // read collection thread flag
  410. dwType = 0;
  411. dwSize = sizeof(DWORD);
  412. dwError = PrivateRegQueryValueExW (ghKeyPerflib,
  413. cszPerflibFlags,
  414. NULL,
  415. &dwType,
  416. (LPBYTE)&lPerflibConfigFlags,
  417. &dwSize);
  418. if ((dwError == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
  419. // then keep it
  420. } else {
  421. // apply default value
  422. lPerflibConfigFlags = PLCF_DEFAULT;
  423. }
  424. //
  425. // Create global section for perf data on perflibs
  426. // NOTE: This is optional only
  427. //
  428. if ((hPerflibSectionFile == NULL) && (lPerflibConfigFlags & PLCF_ENABLE_PERF_SECTION)) {
  429. PPERFDATA_SECTION_HEADER pHead;
  430. WCHAR szPID[32];
  431. HRESULT hErr;
  432. size_t nDestSize, nCharsLeft;
  433. PWCHAR szSectionName, szTail;
  434. dwError = ERROR_SUCCESS;
  435. // create section name
  436. nDestSize = MAX_PATH;
  437. _ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
  438. // create filename
  439. szSectionName = &szPerflibSectionName[0];
  440. hErr = StringCchCopyExW(szSectionName, nDestSize,
  441. (LPCWSTR)L"%TEMP%\\Perflib_Perfdata_",
  442. &szTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  443. if (SUCCEEDED(hErr)) {
  444. szSectionName = szTail;
  445. nDestSize = nCharsLeft;
  446. hErr = StringCchCopyExW(szSectionName, nDestSize,
  447. szPID, &szTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  448. }
  449. if (SUCCEEDED(hErr)) {
  450. szSectionName = szTail;
  451. nDestSize = nCharsLeft;
  452. hErr = StringCchCopyExW(szSectionName, nDestSize, (LPCWSTR)L".dat",
  453. &szTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  454. }
  455. if (SUCCEEDED(hErr)) {
  456. nDestSize = ExpandEnvironmentStrings
  457. (szPerflibSectionName, szPerflibSectionFile, MAX_PATH);
  458. if ((nDestSize == 0) || (nDestSize > MAX_PATH)) {
  459. dwError = ERROR_MORE_DATA;
  460. }
  461. }
  462. else {
  463. dwError = ERROR_MORE_DATA;
  464. }
  465. if (dwError == ERROR_SUCCESS) {
  466. hPerflibSectionFile = CreateFile (szPerflibSectionFile,
  467. GENERIC_READ | GENERIC_WRITE,
  468. FILE_SHARE_READ | FILE_SHARE_WRITE,
  469. NULL,
  470. OPEN_ALWAYS,
  471. FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_TEMPORARY,
  472. NULL);
  473. }
  474. if ((hPerflibSectionFile != INVALID_HANDLE_VALUE) &&
  475. (hPerflibSectionFile != NULL)) {
  476. // create file mapping object
  477. hPerflibSectionMap = CreateFileMapping (
  478. hPerflibSectionFile,
  479. NULL,
  480. PAGE_READWRITE,
  481. 0, dwPerflibSectionSize,
  482. szPerflibSectionName);
  483. if (hPerflibSectionMap != NULL) {
  484. // map view of file
  485. lpPerflibSectionAddr = MapViewOfFile (
  486. hPerflibSectionMap,
  487. FILE_MAP_WRITE,
  488. 0,0, dwPerflibSectionSize);
  489. if (lpPerflibSectionAddr != NULL) {
  490. // init section if not already
  491. pHead = (PPERFDATA_SECTION_HEADER)lpPerflibSectionAddr;
  492. if (pHead->dwInitSignature != PDSH_INIT_SIG) {
  493. // then init
  494. // clear file to 0
  495. memset (pHead, 0, dwPerflibSectionSize);
  496. pHead->dwEntriesInUse = 0;
  497. pHead->dwMaxEntries = dwPerflibSectionMaxEntries;
  498. pHead->dwMissingEntries = 0;
  499. pHead->dwInitSignature = PDSH_INIT_SIG;
  500. } else {
  501. // already initialized so leave it
  502. }
  503. } else {
  504. // unable to map file so close
  505. TRACE((WINPERF_DBG_TRACE_WARNING),
  506. (&PerflibGuid, __LINE__, PERF_OPEN_KEY, 0, 0, NULL));
  507. CloseHandle (hPerflibSectionMap);
  508. hPerflibSectionMap = NULL;
  509. CloseHandle (hPerflibSectionFile);
  510. hPerflibSectionFile = NULL;
  511. }
  512. } else {
  513. // unable to create file mapping so close file
  514. TRACE((WINPERF_DBG_TRACE_WARNING),
  515. (&PerflibGuid, __LINE__, PERF_OPEN_KEY, 0, 0, NULL));
  516. CloseHandle (hPerflibSectionFile);
  517. hPerflibSectionFile = NULL;
  518. }
  519. } else {
  520. // unable to open file so no perf stats available
  521. TRACE((WINPERF_DBG_TRACE_WARNING),
  522. (&PerflibGuid, __LINE__, PERF_OPEN_KEY, 0, 0, NULL));
  523. hPerflibSectionFile = NULL;
  524. }
  525. }
  526. // find and open perf counters
  527. OpenExtensibleObjects();
  528. bPerflibOpen = TRUE;
  529. dwExtObjListRefCount = 0;
  530. SetEvent (hExtObjListIsNotInUse); // indicate the list is not busy
  531. // read collection thread flag
  532. dwType = 0;
  533. dwSize = sizeof(DWORD);
  534. dwError = PrivateRegQueryValueExW (ghKeyPerflib,
  535. UseCollectionThread,
  536. NULL,
  537. &dwType,
  538. (LPBYTE)&dwCollectionFlags,
  539. &dwSize);
  540. if ((dwError == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
  541. // validate the answer
  542. switch (dwCollectionFlags) {
  543. case 0:
  544. // this is a valid value
  545. break;
  546. case COLL_FLAG_USE_SEPARATE_THREAD:
  547. // this feature is not supported so skip through
  548. default:
  549. // this is for invalid values
  550. dwCollectionFlags = 0;
  551. // dwCollectionFlags = COLL_FLAG_USE_SEPARATE_THREAD;
  552. break;
  553. }
  554. }
  555. if (dwError != ERROR_SUCCESS) {
  556. dwCollectionFlags = 0;
  557. // dwCollectionFlags = COLL_FLAG_USE_SEPARATE_THREAD;
  558. }
  559. if (dwCollectionFlags == COLL_FLAG_USE_SEPARATE_THREAD) {
  560. // create data collection thread
  561. // a seperate thread is required for COM/OLE compatibity as some
  562. // client threads may be COM initialized incorrectly for the
  563. // extensible counter DLL's that may be called
  564. // status = OpenCollectionThread ();
  565. } else {
  566. hCollectEvents[COLLECT_THREAD_PROCESS_EVENT] = NULL;
  567. hCollectEvents[COLLECT_THREAD_EXIT_EVENT] = NULL;
  568. hCollectEvents[COLLECT_THREAD_DONE_EVENT] = NULL;
  569. hCollectThread = NULL;
  570. }
  571. dwError = ERROR_SUCCESS;
  572. }
  573. RtlZeroMemory(&OsVersion, sizeof(OsVersion));
  574. OsVersion.dwOSVersionInfoSize = sizeof(OsVersion);
  575. status = RtlGetVersion((POSVERSIONINFOW) &OsVersion);
  576. if (NT_SUCCESS(status)) {
  577. if (OsVersion.wProductType == VER_NT_WORKSTATION) {
  578. dwBoostPriority = 0;
  579. }
  580. }
  581. }
  582. if ((hKey != HKEY_PERFORMANCE_DATA) && (dwFnStatus != ERROR_SERVICE_DISABLED)) {
  583. InterlockedDecrement(&NumberOfOpens);
  584. }
  585. // KdPrint(("PERFLIB: [Open] Pid: %d, Number Of PerflibHandles: %d\n",
  586. // GetCurrentProcessId(), NumberOfOpens));
  587. if (hGlobalDataMutex != NULL) ReleaseMutex (hGlobalDataMutex);
  588. OPD_Error_Exit_NoSemaphore:
  589. TRACE((WINPERF_DBG_TRACE_INFO),
  590. (&PerflibGuid, __LINE__, PERF_OPEN_KEY, 0, status,
  591. &NumberOfOpens, sizeof(NumberOfOpens), NULL));
  592. return dwFnStatus;
  593. }
  594. LONG
  595. PerfRegQueryValue (
  596. IN HKEY hKey,
  597. IN PUNICODE_STRING lpValueName,
  598. OUT LPDWORD lpReserved OPTIONAL,
  599. OUT LPDWORD lpType OPTIONAL,
  600. OUT LPBYTE lpData,
  601. OUT LPDWORD lpcbData,
  602. OUT LPDWORD lpcbLen OPTIONAL
  603. )
  604. /*++
  605. PerfRegQueryValue - Get data
  606. Inputs:
  607. hKey - Predefined handle to open remote
  608. machine
  609. lpValueName - Name of the value to be returned;
  610. could be "ForeignComputer:<computername>
  611. or perhaps some other objects, separated
  612. by ~; must be Unicode string
  613. lpReserved - should be omitted (NULL)
  614. lpType - should be omitted (NULL)
  615. lpData - pointer to a buffer to receive the
  616. performance data
  617. lpcbData - pointer to a variable containing the
  618. size in bytes of the output buffer;
  619. on output, will receive the number
  620. of bytes actually returned
  621. lpcbLen - Return the number of bytes to transmit to
  622. the client (used by RPC) (optional).
  623. Return Value:
  624. DOS error code indicating status of call or
  625. ERROR_SUCCESS if all ok
  626. --*/
  627. {
  628. DWORD dwQueryType; // type of request
  629. DWORD TotalLen; // Length of the total return block
  630. DWORD Win32Error; // Failure code
  631. DWORD lFnStatus = ERROR_SUCCESS; // Win32 status to return to caller
  632. DWORD dwcbData = 0; // Content of *lpcbData
  633. DWORD dwcbLen = 0; // Content of *lpcbLen
  634. LPVOID pDataDefinition; // Pointer to next object definition
  635. UNICODE_STRING usLocalValue = {0,0, NULL};
  636. PERF_DATA_BLOCK *pPerfDataBlock = (PERF_DATA_BLOCK *)lpData;
  637. LARGE_INTEGER liQueryWaitTime ;
  638. THREAD_BASIC_INFORMATION tbiData;
  639. LONG lOldPriority, lNewPriority;
  640. NTSTATUS status = STATUS_SUCCESS;
  641. LPWSTR lpLangId = NULL;
  642. DBG_UNREFERENCED_PARAMETER(lpReserved);
  643. HEAP_PROBE();
  644. lOldPriority = lNewPriority = -1;
  645. // make a local copy of the value string if the arg references
  646. // the static buffer since it can be overwritten by
  647. // some of the RegistryEventSource call made by this routine
  648. pDataDefinition = NULL;
  649. if (lpValueName != NULL) {
  650. if (lpValueName->Buffer == NULL) {
  651. lFnStatus = ERROR_INVALID_PARAMETER;
  652. goto PRQV_ErrorExit1;
  653. }
  654. if (lpValueName == &NtCurrentTeb( )->StaticUnicodeString) {
  655. if (RtlCreateUnicodeString (
  656. &usLocalValue, lpValueName->Buffer)) {
  657. lFnStatus = ERROR_SUCCESS;
  658. } else {
  659. // unable to create string
  660. lFnStatus = ERROR_INVALID_PARAMETER;
  661. }
  662. } else {
  663. // copy the arg to the local structure
  664. try {
  665. memcpy (&usLocalValue, lpValueName, sizeof(UNICODE_STRING));
  666. } except (EXCEPTION_EXECUTE_HANDLER) {
  667. lFnStatus = GetExceptionCode();
  668. }
  669. }
  670. }
  671. else {
  672. lFnStatus = ERROR_INVALID_PARAMETER;
  673. goto PRQV_ErrorExit1;
  674. }
  675. if (lFnStatus != ERROR_SUCCESS) {
  676. goto PRQV_ErrorExit1;
  677. }
  678. if (hGlobalDataMutex == NULL || bPerflibOpen == FALSE) {
  679. // if a Mutex was not allocated then the key needs to be opened.
  680. // Without synchronization, it's too easy for threads to get
  681. // tangled up
  682. lFnStatus = PerfOpenKey(hKey);
  683. if (lFnStatus == ERROR_SUCCESS) {
  684. if (!TestClientForAccess ()) {
  685. if (THROTTLE_PERFLIB(PERFLIB_ACCESS_DENIED)) {
  686. LPTSTR szMessageArray[2];
  687. TCHAR szUserName[128];
  688. TCHAR szModuleName[MAX_PATH];
  689. DWORD dwUserNameLength;
  690. dwUserNameLength = sizeof(szUserName)/sizeof(TCHAR);
  691. if (!GetUserName (szUserName, &dwUserNameLength)) {
  692. szUserName[0] = 0;
  693. }
  694. if (!GetModuleFileName (NULL, szModuleName,
  695. sizeof(szModuleName)/sizeof(TCHAR))) {
  696. szModuleName[0] = 0;
  697. }
  698. szMessageArray[0] = szUserName;
  699. szMessageArray[1] = szModuleName;
  700. ReportEvent (hEventLog,
  701. EVENTLOG_ERROR_TYPE, // error type
  702. 0, // category (not used)
  703. (DWORD)PERFLIB_ACCESS_DENIED, // event,
  704. NULL, // SID (not used),
  705. 2, // number of strings
  706. 0, // sizeof raw data
  707. szMessageArray, // message text array
  708. NULL); // raw data
  709. }
  710. lFnStatus = ERROR_ACCESS_DENIED;
  711. TRACE((WINPERF_DBG_TRACE_FATAL),
  712. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, lFnStatus, NULL));
  713. }
  714. }
  715. }
  716. if (lFnStatus != ERROR_SUCCESS) {
  717. // goto the exit point
  718. goto PRQV_ErrorExit1;
  719. }
  720. if (dwBoostPriority != 0) {
  721. status = NtQueryInformationThread (
  722. NtCurrentThread(),
  723. ThreadBasicInformation,
  724. &tbiData,
  725. sizeof(tbiData),
  726. NULL);
  727. if (NT_SUCCESS(status)) {
  728. lOldPriority = tbiData.Priority;
  729. } else {
  730. TRACE((WINPERF_DBG_TRACE_WARNING),
  731. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0,
  732. status, NULL));
  733. lOldPriority = -1;
  734. }
  735. lNewPriority = DEFAULT_THREAD_PRIORITY; // perfmon's favorite priority
  736. //
  737. // Only RAISE the priority here. Don't lower it if it's high
  738. //
  739. if ((lOldPriority > 0) && (lOldPriority < lNewPriority)) {
  740. status = NtSetInformationThread(
  741. NtCurrentThread(),
  742. ThreadPriority,
  743. &lNewPriority,
  744. sizeof(lNewPriority)
  745. );
  746. if (!NT_SUCCESS(status)) {
  747. TRACE((WINPERF_DBG_TRACE_WARNING),
  748. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0,
  749. status, NULL));
  750. lOldPriority = -1;
  751. }
  752. } else {
  753. lOldPriority = -1; // to save resetting at the end
  754. }
  755. }
  756. //
  757. // Set the length parameter to zero so that in case of an error,
  758. // nothing will be transmitted back to the client and the client won't
  759. // attempt to unmarshall anything.
  760. //
  761. dwcbData = 0;
  762. dwcbLen = 0;
  763. try {
  764. if( ARGUMENT_PRESENT( lpcbLen )) {
  765. *lpcbLen = 0;
  766. }
  767. if( lpcbData != NULL ) {
  768. dwcbData = *lpcbData;
  769. }
  770. } except (EXCEPTION_EXECUTE_HANDLER) {
  771. lFnStatus = Win32Error = GetExceptionCode();
  772. }
  773. // if here, then assume the caller has the necessary access
  774. /*
  775. determine query type, can be one of the following
  776. Global
  777. get all objects
  778. List
  779. get objects in list (usLocalValue)
  780. Foreign Computer
  781. call extensible Counter Routine only
  782. Costly
  783. costly object items
  784. Counter
  785. get counter names for the specified language Id
  786. Help
  787. get help names for the specified language Id
  788. */
  789. dwQueryType = GetQueryType (usLocalValue.Buffer);
  790. TRACE((WINPERF_DBG_TRACE_INFO),
  791. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, dwQueryType, NULL));
  792. if (dwQueryType == QUERY_COUNTER || dwQueryType == QUERY_HELP ||
  793. dwQueryType == QUERY_ADDCOUNTER || dwQueryType == QUERY_ADDHELP ) {
  794. liQueryWaitTime.QuadPart = MakeTimeOutValue(QUERY_WAIT_TIME);
  795. status = NtWaitForSingleObject (
  796. hGlobalDataMutex, // semaphore
  797. FALSE, // not alertable
  798. &liQueryWaitTime); // wait 'til timeout
  799. if (status != STATUS_SUCCESS) {
  800. lFnStatus = ERROR_BUSY;
  801. Win32Error = ERROR_BUSY;
  802. TotalLen = dwcbData;
  803. TRACE((WINPERF_DBG_TRACE_FATAL),
  804. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, status, NULL));
  805. } else {
  806. try {
  807. TRACE((WINPERF_DBG_TRACE_INFO),
  808. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, status, NULL));
  809. if (hKey == HKEY_PERFORMANCE_DATA) {
  810. lpLangId = NULL;
  811. } else if (hKey == HKEY_PERFORMANCE_TEXT) {
  812. lpLangId = DefaultLangId;
  813. } else if (hKey == HKEY_PERFORMANCE_NLSTEXT) {
  814. RtlZeroMemory(NativeLangId, 8 * sizeof(WCHAR));
  815. lpLangId = &NativeLangId[0];
  816. PerfGetLangId(NativeLangId);
  817. }
  818. status = PerfGetNames (
  819. dwQueryType,
  820. &usLocalValue,
  821. lpData,
  822. lpcbData,
  823. lpcbLen,
  824. lpLangId);
  825. TRACE((WINPERF_DBG_TRACE_INFO),
  826. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, status,
  827. &hKey, sizeof(hKey), NULL));
  828. if (! NT_SUCCESS(status) && (hKey == HKEY_PERFORMANCE_NLSTEXT)) {
  829. // Sublanguage doesn't exist, so try the real one
  830. //
  831. TRACE((WINPERF_DBG_TRACE_WARNING),
  832. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, status, NULL));
  833. RtlZeroMemory(NativeLangId, 8 * sizeof(WCHAR));
  834. PerfGetPrimaryLangId(GetUserDefaultUILanguage(), NativeLangId);
  835. if (lpcbData != NULL) * lpcbData = dwcbData;
  836. if (lpcbLen != NULL) * lpcbLen = dwcbLen;
  837. status = PerfGetNames (
  838. dwQueryType,
  839. &usLocalValue,
  840. lpData,
  841. lpcbData,
  842. lpcbLen,
  843. lpLangId);
  844. }
  845. if (!NT_SUCCESS(status)) {
  846. TRACE((WINPERF_DBG_TRACE_FATAL),
  847. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, status, NULL));
  848. // convert error to win32 for return
  849. }
  850. lFnStatus = PerfpDosError(status);
  851. if (ARGUMENT_PRESENT (lpType)) {
  852. // test for optional value
  853. *lpType = REG_MULTI_SZ;
  854. }
  855. } except (EXCEPTION_EXECUTE_HANDLER) {
  856. lFnStatus = Win32Error = GetExceptionCode();
  857. }
  858. ReleaseMutex (hGlobalDataMutex);
  859. }
  860. } else {
  861. // define info block for data collection
  862. COLLECT_THREAD_DATA CollectThreadData = {0, NULL, NULL, NULL, NULL, NULL, 0, 0};
  863. liQueryWaitTime.QuadPart = MakeTimeOutValue(QUERY_WAIT_TIME);
  864. status = NtWaitForSingleObject (
  865. hGlobalDataMutex, // semaphore
  866. FALSE, // not alertable
  867. &liQueryWaitTime); // wait 'til timeout
  868. if (status != STATUS_SUCCESS) {
  869. lFnStatus = ERROR_BUSY;
  870. Win32Error = ERROR_BUSY;
  871. TotalLen = dwcbData;
  872. TRACE((WINPERF_DBG_TRACE_FATAL),
  873. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, status, NULL));
  874. } else {
  875. TRACE((WINPERF_DBG_TRACE_INFO),
  876. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, status, NULL));
  877. //
  878. // Format Return Buffer: start with basic data block
  879. //
  880. TotalLen = sizeof(PERF_DATA_BLOCK) +
  881. ((CNLEN+sizeof(UNICODE_NULL))*sizeof(WCHAR));
  882. if ( dwcbData < TotalLen ) {
  883. Win32Error = ERROR_MORE_DATA;
  884. TRACE((WINPERF_DBG_TRACE_ERROR),
  885. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, TotalLen,
  886. dwcbData, sizeof(DWORD), NULL));
  887. } else {
  888. // foreign data provider will return the perf data header
  889. Win32Error = ERROR_SUCCESS;
  890. try {
  891. if (dwQueryType == QUERY_FOREIGN) {
  892. // reset the values to avoid confusion
  893. // *lpcbData = 0; // 0 bytes (removed to enable foreign computers)
  894. if (lpData == NULL) {
  895. Win32Error = ERROR_MORE_DATA;
  896. }
  897. else {
  898. pDataDefinition = (LPVOID) lpData;
  899. memset(lpData, 0, sizeof(PERF_DATA_BLOCK)); // clear out header
  900. }
  901. } else {
  902. if (pPerfDataBlock == NULL) { // this is actually lpData
  903. Win32Error = ERROR_MORE_DATA;
  904. }
  905. else {
  906. MonBuildPerfDataBlock(pPerfDataBlock,
  907. (PVOID *) &pDataDefinition,
  908. 0,
  909. PROCESSOR_OBJECT_TITLE_INDEX);
  910. }
  911. }
  912. } except (EXCEPTION_EXECUTE_HANDLER) {
  913. Win32Error = GetExceptionCode();
  914. }
  915. if (Win32Error == ERROR_SUCCESS) {
  916. CollectThreadData.dwQueryType = dwQueryType;
  917. CollectThreadData.lpValueName = usLocalValue.Buffer,
  918. CollectThreadData.lpData = lpData;
  919. CollectThreadData.lpcbData = lpcbData;
  920. CollectThreadData.lppDataDefinition = &pDataDefinition;
  921. CollectThreadData.pCurrentExtObject = NULL;
  922. CollectThreadData.lReturnValue = ERROR_SUCCESS;
  923. CollectThreadData.dwActionFlags = CTD_AF_NO_ACTION;
  924. if (hCollectThread == NULL) {
  925. // then call the function directly and hope for the best
  926. Win32Error = QueryExtensibleData (
  927. &CollectThreadData);
  928. } else {
  929. // collect the data in a separate thread
  930. // load the args
  931. // set event to get things going
  932. SetEvent (hCollectEvents[COLLECT_THREAD_PROCESS_EVENT]);
  933. // now wait for the thread to return
  934. Win32Error = WaitForSingleObject (
  935. hCollectEvents[COLLECT_THREAD_DONE_EVENT],
  936. COLLECTION_WAIT_TIME);
  937. if (Win32Error == WAIT_TIMEOUT) {
  938. bThreadHung = TRUE;
  939. // log error
  940. TRACE((WINPERF_DBG_TRACE_FATAL),
  941. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, Win32Error, NULL));
  942. if (THROTTLE_PERFLIB (PERFLIB_COLLECTION_HUNG)) {
  943. LPSTR szMessageArray[2];
  944. WORD wStringIndex;
  945. // load data for eventlog message
  946. wStringIndex = 0;
  947. if (CollectThreadData.pCurrentExtObject != NULL) {
  948. szMessageArray[wStringIndex++] =
  949. CollectThreadData.pCurrentExtObject->szCollectProcName;
  950. } else {
  951. szMessageArray[wStringIndex++] = "Unknown";
  952. }
  953. ReportEventA (hEventLog,
  954. EVENTLOG_ERROR_TYPE, // error type
  955. 0, // category (not used)
  956. (DWORD)PERFLIB_COLLECTION_HUNG, // event,
  957. NULL, // SID (not used),
  958. wStringIndex, // number of strings
  959. 0, // sizeof raw data
  960. szMessageArray, // message text array
  961. NULL); // raw data
  962. }
  963. DisablePerfLibrary(CollectThreadData.pCurrentExtObject, PERFLIB_DISABLE_ALL);
  964. // DebugPrint((0, "Collection thread is hung in %s\n",
  965. // CollectThreadData.pCurrentExtObject->szCollectProcName != NULL ?
  966. // CollectThreadData.pCurrentExtObject->szCollectProcName : "Unknown"));
  967. // and then wait forever for the thread to return
  968. // this is done to prevent the function from returning
  969. // while the collection thread is using the buffer
  970. // passed in by the calling function and causing
  971. // all kind of havoc should the buffer be changed and/or
  972. // deleted and then have the thread continue for some reason
  973. Win32Error = WaitForSingleObject (
  974. hCollectEvents[COLLECT_THREAD_DONE_EVENT],
  975. INFINITE);
  976. }
  977. bThreadHung = FALSE; // in case it was true, but came out
  978. // here the thread has returned so continue on
  979. Win32Error = CollectThreadData.lReturnValue;
  980. }
  981. #if 0
  982. if (CollectThreadData.dwActionFlags != CTD_AF_NO_ACTION) {
  983. if (CollectThreadData.dwActionFlags == CTD_AF_OPEN_THREAD) {
  984. OpenCollectionThread();
  985. } else if (CollectThreadData.dwActionFlags == CTD_AF_CLOSE_THREAD) {
  986. CloseCollectionThread();
  987. } else {
  988. assert (CollectThreadData.dwActionFlags != 0);
  989. }
  990. }
  991. #endif
  992. }
  993. } // if (Win32Error == ERROR_SUCCESS)
  994. ReleaseMutex (hGlobalDataMutex);
  995. }
  996. // if an error was encountered, return it
  997. if (Win32Error != ERROR_SUCCESS) {
  998. lFnStatus = Win32Error;
  999. } else {
  1000. //
  1001. // Final housekeeping for data return: note data size
  1002. //
  1003. TotalLen = (DWORD) ((PCHAR) pDataDefinition - (PCHAR) lpData);
  1004. lFnStatus = ERROR_SUCCESS;
  1005. try {
  1006. if (lpcbData != NULL) {
  1007. *lpcbData = TotalLen;
  1008. }
  1009. } except (EXCEPTION_EXECUTE_HANDLER) {
  1010. lFnStatus = GetExceptionCode();
  1011. }
  1012. pPerfDataBlock->TotalByteLength = TotalLen;
  1013. }
  1014. try {
  1015. if (ARGUMENT_PRESENT (lpcbLen)) { // test for optional parameter
  1016. *lpcbLen = TotalLen;
  1017. }
  1018. if (ARGUMENT_PRESENT (lpType)) { // test for optional value
  1019. *lpType = REG_BINARY;
  1020. }
  1021. } except (EXCEPTION_EXECUTE_HANDLER) {
  1022. lFnStatus = GetExceptionCode();
  1023. }
  1024. }
  1025. PRQV_ErrorExit1:
  1026. if (dwBoostPriority != 0) {
  1027. // reset thread to original priority
  1028. if ((lOldPriority > 0) && (lOldPriority != lNewPriority)) {
  1029. NtSetInformationThread(
  1030. NtCurrentThread(),
  1031. ThreadPriority,
  1032. &lOldPriority,
  1033. sizeof(lOldPriority)
  1034. );
  1035. }
  1036. }
  1037. if (usLocalValue.Buffer != NULL) {
  1038. // restore the value string if it was from the local static buffer
  1039. // then free the local buffer
  1040. if (lpValueName == &NtCurrentTeb( )->StaticUnicodeString) {
  1041. USHORT Length = lpValueName->MaximumLength;
  1042. if (Length > usLocalValue.MaximumLength) {
  1043. Length = usLocalValue.MaximumLength;
  1044. }
  1045. memcpy (lpValueName->Buffer, usLocalValue.Buffer, Length);
  1046. lpValueName->Buffer[(Length/sizeof(WCHAR))-1] = UNICODE_NULL;
  1047. RtlFreeUnicodeString (&usLocalValue);
  1048. }
  1049. }
  1050. HEAP_PROBE();
  1051. TRACE((WINPERF_DBG_TRACE_INFO),
  1052. (&PerflibGuid, __LINE__, PERF_REG_QUERY_VALUE, 0, lFnStatus, NULL));
  1053. return (LONG) lFnStatus;
  1054. }
  1055. LONG
  1056. PerfRegCloseKey
  1057. (
  1058. IN OUT PHKEY phKey
  1059. )
  1060. /*++
  1061. Routine Description:
  1062. Closes all performance handles when the usage count drops to 0.
  1063. Arguments:
  1064. phKey - Supplies a handle to an open key to be closed.
  1065. Return Value:
  1066. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  1067. --*/
  1068. {
  1069. NTSTATUS status;
  1070. LARGE_INTEGER liQueryWaitTime ;
  1071. HANDLE hObjMutex;
  1072. LONG lReturn = ERROR_SUCCESS;
  1073. HKEY hKey;
  1074. PEXT_OBJECT pThisExtObj, pNextExtObj;
  1075. //
  1076. // Set the handle to NULL so that RPC knows that it has been closed.
  1077. //
  1078. hKey = *phKey;
  1079. *phKey = NULL;
  1080. if (hKey != HKEY_PERFORMANCE_DATA) {
  1081. // no need to check HKEY_PERFORMANCE_TEXT and HKEY_PERFORMANCE_NLSTEXT.
  1082. // Only HKEY_PERFORMANCE_DATA affects NumberOfOpens value.
  1083. //
  1084. return ERROR_SUCCESS;
  1085. }
  1086. if (NumberOfOpens <= 0) {
  1087. // KdPrint(("PERFLIB: [Close] Pid: %d, Number Of PerflibHandles: %d\n",
  1088. // GetCurrentProcessId(), NumberOfOpens));
  1089. return ERROR_SUCCESS;
  1090. }
  1091. // wait for ext obj list to be "un"-busy
  1092. liQueryWaitTime.QuadPart = MakeTimeOutValue (CLOSE_WAIT_TIME);
  1093. status = NtWaitForSingleObject (
  1094. hExtObjListIsNotInUse,
  1095. FALSE,
  1096. &liQueryWaitTime);
  1097. if (status == STATUS_SUCCESS) {
  1098. TRACE((WINPERF_DBG_TRACE_INFO),
  1099. (&PerflibGuid, __LINE__, PERF_REG_CLOSE_KEY, 0, status, NULL));
  1100. // then the list is inactive so continue
  1101. if (hGlobalDataMutex != NULL) { // if a mutex was allocated, then use it
  1102. // if here, then assume a mutex is ready
  1103. liQueryWaitTime.QuadPart = MakeTimeOutValue(CLOSE_WAIT_TIME);
  1104. status = NtWaitForSingleObject (
  1105. hGlobalDataMutex, // semaphore
  1106. FALSE, // not alertable
  1107. &liQueryWaitTime); // wait forever
  1108. if (status == STATUS_SUCCESS) {
  1109. TRACE((WINPERF_DBG_TRACE_INFO),
  1110. (&PerflibGuid, __LINE__, PERF_REG_CLOSE_KEY, 0, status,
  1111. &NumberOfOpens, sizeof(NumberOfOpens),
  1112. &hKey, sizeof(hKey), NULL));
  1113. // now we have a lock on the global data, so continue
  1114. if (hKey == HKEY_PERFORMANCE_DATA) {
  1115. if (InterlockedDecrement(&NumberOfOpens) == 0) {
  1116. // walk down list of known objects and close and delete each one
  1117. pNextExtObj = ExtensibleObjects;
  1118. while (pNextExtObj != NULL) {
  1119. // close and destroy each entry in the list
  1120. pThisExtObj = pNextExtObj;
  1121. hObjMutex = pThisExtObj->hMutex;
  1122. status = NtWaitForSingleObject (
  1123. hObjMutex,
  1124. FALSE,
  1125. &liQueryWaitTime);
  1126. if (status == STATUS_SUCCESS) {
  1127. TRACE((WINPERF_DBG_TRACE_INFO),
  1128. (&PerflibGuid, __LINE__, PERF_REG_CLOSE_KEY, 0, status,
  1129. pThisExtObj->szServiceName,
  1130. WSTRSIZE(pThisExtObj->szServiceName),
  1131. NULL));
  1132. InterlockedIncrement((LONG *)&pThisExtObj->dwLockoutCount);
  1133. status = CloseExtObjectLibrary(pThisExtObj, TRUE);
  1134. // close the handle to the perf subkey
  1135. NtClose (pThisExtObj->hPerfKey);
  1136. ReleaseMutex (hObjMutex); // release
  1137. CloseHandle (hObjMutex); // and free
  1138. pNextExtObj = pThisExtObj->pNext;
  1139. // toss the memory for this object
  1140. FREEMEM (pThisExtObj);
  1141. } else {
  1142. TRACE((WINPERF_DBG_TRACE_INFO),
  1143. (&PerflibGuid, __LINE__, PERF_REG_CLOSE_KEY, 0, status,
  1144. pThisExtObj->szServiceName,
  1145. WSTRSIZE(pThisExtObj->szServiceName),
  1146. NULL));
  1147. // this shouldn't happen since we've locked the
  1148. // list of objects
  1149. pNextExtObj = pThisExtObj->pNext;
  1150. }
  1151. } // while
  1152. // close the global objects
  1153. FREEMEM(pComputerName);
  1154. ComputerNameLength = 0;
  1155. pComputerName = NULL;
  1156. ExtensibleObjects = NULL;
  1157. NumExtensibleObjects = 0;
  1158. // close the timer thread
  1159. DestroyPerflibFunctionTimer ();
  1160. if (hEventLog != NULL) {
  1161. DeregisterEventSource (hEventLog);
  1162. hEventLog = NULL;
  1163. } // else the event log has already been closed
  1164. // release event handle
  1165. CloseHandle (hExtObjListIsNotInUse);
  1166. hExtObjListIsNotInUse = NULL;
  1167. // CloseCollectionThread();
  1168. if (ghKeyPerflib != NULL) {
  1169. RegCloseKey(ghKeyPerflib);
  1170. ghKeyPerflib = NULL;
  1171. }
  1172. if (lpPerflibSectionAddr != NULL) {
  1173. UnmapViewOfFile (lpPerflibSectionAddr);
  1174. lpPerflibSectionAddr = NULL;
  1175. CloseHandle (hPerflibSectionMap);
  1176. hPerflibSectionMap = NULL;
  1177. CloseHandle (hPerflibSectionFile);
  1178. hPerflibSectionFile = NULL;
  1179. }
  1180. ReleaseMutex(hGlobalDataMutex);
  1181. } else { // this isn't the last open call so return success
  1182. assert(NumberOfOpens != 0);
  1183. ReleaseMutex (hGlobalDataMutex);
  1184. }
  1185. } // if (hKey == HKEY_PERFORMANCE_DATA)
  1186. } else {
  1187. TRACE((WINPERF_DBG_TRACE_FATAL),
  1188. (&PerflibGuid, __LINE__, PERF_REG_CLOSE_KEY, 0, status, NULL));
  1189. // unable to lock the global data mutex in a timely fashion
  1190. // so return
  1191. lReturn = ERROR_BUSY;
  1192. }
  1193. } else {
  1194. // if there's no mutex then something's fishy. It probably hasn't
  1195. // been opened, yet.
  1196. lReturn = ERROR_NOT_READY;
  1197. }
  1198. } else {
  1199. TRACE((WINPERF_DBG_TRACE_FATAL),
  1200. (&PerflibGuid, __LINE__, PERF_REG_CLOSE_KEY, 0, status, NULL));
  1201. // the object list is still in use so return and let the
  1202. // caller try again later
  1203. lReturn = WAIT_TIMEOUT;
  1204. }
  1205. // KdPrint(("PERFLIB: [Close] Pid: %d, Number Of PerflibHandles: %d\n",
  1206. // GetCurrentProcessId(), NumberOfOpens));
  1207. TRACE((WINPERF_DBG_TRACE_INFO),
  1208. (&PerflibGuid, __LINE__, PERF_REG_CLOSE_KEY, 0, lReturn,
  1209. &NumberOfOpens, sizeof(NumberOfOpens), NULL));
  1210. return lReturn;
  1211. }
  1212. LONG
  1213. PerfRegSetValue (
  1214. IN HKEY hKey,
  1215. IN LPWSTR lpValueName,
  1216. IN DWORD Reserved,
  1217. IN DWORD dwType,
  1218. IN LPBYTE lpData,
  1219. IN DWORD cbData
  1220. )
  1221. /*++
  1222. PerfRegSetValue - Set data
  1223. Inputs:
  1224. hKey - Predefined handle to open remote
  1225. machine
  1226. lpValueName - Name of the value to be returned;
  1227. could be "ForeignComputer:<computername>
  1228. or perhaps some other objects, separated
  1229. by ~; must be Unicode string
  1230. lpReserved - should be omitted (NULL)
  1231. lpType - should be REG_MULTI_SZ
  1232. lpData - pointer to a buffer containing the
  1233. performance name
  1234. lpcbData - pointer to a variable containing the
  1235. size in bytes of the input buffer;
  1236. Return Value:
  1237. DOS error code indicating status of call or
  1238. ERROR_SUCCESS if all ok
  1239. --*/
  1240. {
  1241. DWORD dwQueryType; // type of request
  1242. LPWSTR lpLangId = NULL;
  1243. NTSTATUS status;
  1244. UNICODE_STRING String;
  1245. LONG lReturn = ERROR_SUCCESS;
  1246. DWORD cbTmpData = cbData;
  1247. UNREFERENCED_PARAMETER(dwType);
  1248. UNREFERENCED_PARAMETER(Reserved);
  1249. try {
  1250. dwQueryType = GetQueryType (lpValueName);
  1251. } except (EXCEPTION_EXECUTE_HANDLER) {
  1252. lReturn = GetExceptionCode();
  1253. goto Error_exit;
  1254. }
  1255. TRACE((WINPERF_DBG_TRACE_INFO),
  1256. (&PerflibGuid, __LINE__, PERF_REG_SET_VALUE, 0, dwQueryType,
  1257. &hKey, sizeof(hKey), NULL));
  1258. // convert the query to set commands
  1259. if ((dwQueryType == QUERY_COUNTER) ||
  1260. (dwQueryType == QUERY_ADDCOUNTER)) {
  1261. dwQueryType = QUERY_ADDCOUNTER;
  1262. } else if ((dwQueryType == QUERY_HELP) ||
  1263. (dwQueryType == QUERY_ADDHELP)) {
  1264. dwQueryType = QUERY_ADDHELP;
  1265. } else {
  1266. lReturn = ERROR_BADKEY;
  1267. goto Error_exit;
  1268. }
  1269. if (hKey == HKEY_PERFORMANCE_TEXT) {
  1270. lpLangId = DefaultLangId;
  1271. } else if (hKey == HKEY_PERFORMANCE_NLSTEXT) {
  1272. lpLangId = &NativeLangId[0];
  1273. PerfGetLangId(NativeLangId);
  1274. } else {
  1275. lReturn = ERROR_BADKEY;
  1276. goto Error_exit;
  1277. }
  1278. try {
  1279. RtlInitUnicodeString(&String, lpValueName);
  1280. status = PerfGetNames (
  1281. dwQueryType,
  1282. &String,
  1283. lpData,
  1284. &cbData,
  1285. NULL,
  1286. lpLangId);
  1287. if (!NT_SUCCESS(status) && (hKey == HKEY_PERFORMANCE_NLSTEXT)) {
  1288. TRACE((WINPERF_DBG_TRACE_INFO),
  1289. (&PerflibGuid, __LINE__, PERF_REG_SET_VALUE, 0, status, NULL));
  1290. // Sublanguage doesn't exist, so try the real one
  1291. //
  1292. PerfGetPrimaryLangId(GetUserDefaultUILanguage(), NativeLangId);
  1293. cbData = cbTmpData;
  1294. status = PerfGetNames (
  1295. dwQueryType,
  1296. &String,
  1297. lpData,
  1298. &cbData,
  1299. NULL,
  1300. lpLangId);
  1301. }
  1302. } except (EXCEPTION_EXECUTE_HANDLER) {
  1303. lReturn = GetExceptionCode();
  1304. goto Error_exit;
  1305. }
  1306. if (!NT_SUCCESS(status)) {
  1307. TRACE((WINPERF_DBG_TRACE_FATAL),
  1308. (&PerflibGuid, __LINE__, PERF_REG_SET_VALUE, 0, status, NULL));
  1309. lReturn = (error_status_t)PerfpDosError(status);
  1310. }
  1311. Error_exit:
  1312. TRACE((WINPERF_DBG_TRACE_INFO),
  1313. (&PerflibGuid, __LINE__, PERF_REG_SET_VALUE, 0, lReturn, NULL));
  1314. return (lReturn);
  1315. }
  1316. LONG
  1317. PerfRegEnumKey (
  1318. IN HKEY hKey,
  1319. IN DWORD dwIndex,
  1320. OUT PUNICODE_STRING lpName,
  1321. OUT LPDWORD lpReserved OPTIONAL,
  1322. OUT PUNICODE_STRING lpClass OPTIONAL,
  1323. OUT PFILETIME lpftLastWriteTime OPTIONAL
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. Enumerates keys under HKEY_PERFORMANCE_DATA.
  1328. Arguments:
  1329. Same as RegEnumKeyEx. Returns that there are no such keys.
  1330. Return Value:
  1331. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  1332. --*/
  1333. {
  1334. UNREFERENCED_PARAMETER(hKey);
  1335. UNREFERENCED_PARAMETER(dwIndex);
  1336. UNREFERENCED_PARAMETER(lpReserved);
  1337. try {
  1338. lpName->Length = 0;
  1339. if (ARGUMENT_PRESENT (lpClass)) {
  1340. lpClass->Length = 0;
  1341. }
  1342. if ( ARGUMENT_PRESENT(lpftLastWriteTime) ) {
  1343. lpftLastWriteTime->dwLowDateTime = 0;
  1344. lpftLastWriteTime->dwHighDateTime = 0;
  1345. }
  1346. } except (EXCEPTION_EXECUTE_HANDLER) {
  1347. return 0;
  1348. }
  1349. return ERROR_NO_MORE_ITEMS;
  1350. }
  1351. LONG
  1352. PerfRegQueryInfoKey (
  1353. IN HKEY hKey,
  1354. OUT PUNICODE_STRING lpClass,
  1355. OUT LPDWORD lpReserved OPTIONAL,
  1356. OUT LPDWORD lpcSubKeys,
  1357. OUT LPDWORD lpcbMaxSubKeyLen,
  1358. OUT LPDWORD lpcbMaxClassLen,
  1359. OUT LPDWORD lpcValues,
  1360. OUT LPDWORD lpcbMaxValueNameLen,
  1361. OUT LPDWORD lpcbMaxValueLen,
  1362. OUT LPDWORD lpcbSecurityDescriptor,
  1363. OUT PFILETIME lpftLastWriteTime
  1364. )
  1365. /*++
  1366. Routine Description:
  1367. This returns information concerning the predefined handle
  1368. HKEY_PERFORMANCE_DATA
  1369. Arguments:
  1370. Same as RegQueryInfoKey.
  1371. Return Value:
  1372. Returns ERROR_SUCCESS (0) for success.
  1373. --*/
  1374. {
  1375. DWORD TempLength=0;
  1376. DWORD MaxValueLen=0;
  1377. UNICODE_STRING Null;
  1378. SECURITY_DESCRIPTOR SecurityDescriptor;
  1379. HKEY hPerflibKey;
  1380. OBJECT_ATTRIBUTES Obja;
  1381. NTSTATUS Status;
  1382. DWORD PerfStatus = ERROR_SUCCESS;
  1383. UNICODE_STRING PerflibSubKeyString;
  1384. BOOL bGetSACL = TRUE;
  1385. UNREFERENCED_PARAMETER(lpReserved);
  1386. try {
  1387. if (lpClass->MaximumLength >= sizeof(UNICODE_NULL)) {
  1388. lpClass->Length = 0;
  1389. *lpClass->Buffer = UNICODE_NULL;
  1390. }
  1391. *lpcSubKeys = 0;
  1392. *lpcbMaxSubKeyLen = 0;
  1393. *lpcbMaxClassLen = 0;
  1394. *lpcValues = NUM_VALUES;
  1395. *lpcbMaxValueNameLen = VALUE_NAME_LENGTH;
  1396. *lpcbMaxValueLen = 0;
  1397. if ( ARGUMENT_PRESENT(lpftLastWriteTime) ) {
  1398. lpftLastWriteTime->dwLowDateTime = 0;
  1399. lpftLastWriteTime->dwHighDateTime = 0;
  1400. }
  1401. } except (EXCEPTION_EXECUTE_HANDLER) {
  1402. PerfStatus = GetExceptionCode();
  1403. }
  1404. if (PerfStatus == ERROR_SUCCESS) {
  1405. if ((hKey == HKEY_PERFORMANCE_TEXT) ||
  1406. (hKey == HKEY_PERFORMANCE_NLSTEXT)) {
  1407. //
  1408. // We have to go enumerate the values to determine the answer for
  1409. // the MaxValueLen parameter.
  1410. //
  1411. Null.Buffer = NULL;
  1412. Null.Length = 0;
  1413. Null.MaximumLength = 0;
  1414. PerfStatus = PerfEnumTextValue(hKey,
  1415. 0,
  1416. &Null,
  1417. NULL,
  1418. NULL,
  1419. NULL,
  1420. &MaxValueLen,
  1421. NULL);
  1422. if (PerfStatus == ERROR_SUCCESS) {
  1423. PerfStatus = PerfEnumTextValue(hKey,
  1424. 1,
  1425. &Null,
  1426. NULL,
  1427. NULL,
  1428. NULL,
  1429. &TempLength,
  1430. NULL);
  1431. }
  1432. try {
  1433. if (PerfStatus == ERROR_SUCCESS) {
  1434. if (TempLength > MaxValueLen) {
  1435. MaxValueLen = TempLength;
  1436. }
  1437. *lpcbMaxValueLen = MaxValueLen;
  1438. } else {
  1439. TRACE((WINPERF_DBG_TRACE_FATAL),
  1440. (&PerflibGuid, __LINE__, PERF_REG_QUERY_INFO_KEY, 0, PerfStatus, NULL));
  1441. // unable to successfully enum text values for this
  1442. // key so return 0's and the error code
  1443. *lpcValues = 0;
  1444. *lpcbMaxValueNameLen = 0;
  1445. }
  1446. } except (EXCEPTION_EXECUTE_HANDLER) {
  1447. PerfStatus = GetExceptionCode();
  1448. }
  1449. }
  1450. }
  1451. if (PerfStatus == ERROR_SUCCESS) {
  1452. // continune if all is OK
  1453. // now get the size of SecurityDescriptor for Perflib key
  1454. RtlInitUnicodeString (
  1455. &PerflibSubKeyString,
  1456. PerflibKey);
  1457. //
  1458. // Initialize the OBJECT_ATTRIBUTES structure and open the key.
  1459. //
  1460. InitializeObjectAttributes(
  1461. &Obja,
  1462. &PerflibSubKeyString,
  1463. OBJ_CASE_INSENSITIVE,
  1464. NULL,
  1465. NULL
  1466. );
  1467. Status = NtOpenKey(
  1468. &hPerflibKey,
  1469. MAXIMUM_ALLOWED | ACCESS_SYSTEM_SECURITY,
  1470. &Obja
  1471. );
  1472. if ( ! NT_SUCCESS( Status )) {
  1473. Status = NtOpenKey(
  1474. &hPerflibKey,
  1475. MAXIMUM_ALLOWED,
  1476. &Obja
  1477. );
  1478. bGetSACL = FALSE;
  1479. }
  1480. if ( ! NT_SUCCESS( Status )) {
  1481. TRACE((WINPERF_DBG_TRACE_FATAL),
  1482. (&PerflibGuid, __LINE__, PERF_REG_QUERY_INFO_KEY, 0, Status, NULL));
  1483. } else {
  1484. try {
  1485. *lpcbSecurityDescriptor = 0;
  1486. if (bGetSACL == FALSE) {
  1487. //
  1488. // Get the size of the key's SECURITY_DESCRIPTOR for OWNER, GROUP
  1489. // and DACL. These three are always accessible (or inaccesible)
  1490. // as a set.
  1491. //
  1492. Status = NtQuerySecurityObject(
  1493. hPerflibKey,
  1494. OWNER_SECURITY_INFORMATION
  1495. | GROUP_SECURITY_INFORMATION
  1496. | DACL_SECURITY_INFORMATION,
  1497. &SecurityDescriptor,
  1498. 0,
  1499. lpcbSecurityDescriptor
  1500. );
  1501. } else {
  1502. //
  1503. // Get the size of the key's SECURITY_DESCRIPTOR for OWNER, GROUP,
  1504. // DACL, and SACL.
  1505. //
  1506. Status = NtQuerySecurityObject(
  1507. hPerflibKey,
  1508. OWNER_SECURITY_INFORMATION
  1509. | GROUP_SECURITY_INFORMATION
  1510. | DACL_SECURITY_INFORMATION
  1511. | SACL_SECURITY_INFORMATION,
  1512. &SecurityDescriptor,
  1513. 0,
  1514. lpcbSecurityDescriptor
  1515. );
  1516. }
  1517. if( Status != STATUS_BUFFER_TOO_SMALL ) {
  1518. *lpcbSecurityDescriptor = 0;
  1519. } else {
  1520. // this is expected so set status to success
  1521. Status = STATUS_SUCCESS;
  1522. }
  1523. } except (EXCEPTION_EXECUTE_HANDLER) {
  1524. PerfStatus = GetExceptionCode();
  1525. }
  1526. NtClose(hPerflibKey);
  1527. } // else return status
  1528. if (NT_SUCCESS( Status )) {
  1529. PerfStatus = ERROR_SUCCESS;
  1530. } else {
  1531. TRACE((WINPERF_DBG_TRACE_FATAL),
  1532. (&PerflibGuid, __LINE__, PERF_REG_QUERY_INFO_KEY, 0, Status, NULL));
  1533. // return error
  1534. PerfStatus = PerfpDosError(Status);
  1535. }
  1536. }
  1537. return (LONG) PerfStatus;
  1538. }
  1539. LONG
  1540. PerfRegEnumValue (
  1541. IN HKEY hKey,
  1542. IN DWORD dwIndex,
  1543. OUT PUNICODE_STRING lpValueName,
  1544. OUT LPDWORD lpReserved OPTIONAL,
  1545. OUT LPDWORD lpType OPTIONAL,
  1546. OUT LPBYTE lpData,
  1547. IN OUT LPDWORD lpcbData,
  1548. OUT LPDWORD lpcbLen OPTIONAL
  1549. )
  1550. /*++
  1551. Routine Description:
  1552. Enumerates Values under HKEY_PERFORMANCE_DATA.
  1553. Arguments:
  1554. Same as RegEnumValue. Returns the values.
  1555. Return Value:
  1556. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  1557. --*/
  1558. {
  1559. USHORT cbNameSize;
  1560. LONG ErrorCode;
  1561. // table of names used by enum values
  1562. UNICODE_STRING ValueNames[NUM_VALUES];
  1563. ValueNames [0].Length = (WORD)(lstrlenW (GLOBAL_STRING) * sizeof(WCHAR));
  1564. ValueNames [0].MaximumLength = (WORD)(ValueNames [0].Length + sizeof(UNICODE_NULL));
  1565. ValueNames [0].Buffer = (LPWSTR)GLOBAL_STRING;
  1566. ValueNames [1].Length = (WORD)(lstrlenW(COSTLY_STRING) * sizeof(WCHAR));
  1567. ValueNames [1].MaximumLength = (WORD)(ValueNames [1].Length + sizeof(UNICODE_NULL));
  1568. ValueNames [1].Buffer = (LPWSTR)COSTLY_STRING;
  1569. if (lpValueName == NULL || lpValueName->Buffer == NULL) {
  1570. return ERROR_INVALID_PARAMETER;
  1571. }
  1572. if ((hKey == HKEY_PERFORMANCE_TEXT) ||
  1573. (hKey == HKEY_PERFORMANCE_NLSTEXT)) {
  1574. //
  1575. // Assumes PerfEnumTextValue will use try block
  1576. //
  1577. return(PerfEnumTextValue(hKey,
  1578. dwIndex,
  1579. lpValueName,
  1580. lpReserved,
  1581. lpType,
  1582. lpData,
  1583. lpcbData,
  1584. lpcbLen));
  1585. }
  1586. if ( dwIndex >= NUM_VALUES ) {
  1587. //
  1588. // This is a request for data from a non-existent value name
  1589. //
  1590. try {
  1591. *lpcbData = 0;
  1592. } except (EXCEPTION_EXECUTE_HANDLER) {
  1593. return GetExceptionCode();
  1594. }
  1595. return ERROR_NO_MORE_ITEMS;
  1596. }
  1597. cbNameSize = ValueNames[dwIndex].Length;
  1598. ErrorCode = ERROR_SUCCESS;
  1599. try {
  1600. if ( lpValueName->MaximumLength < cbNameSize ) {
  1601. ErrorCode = ERROR_MORE_DATA;
  1602. } else {
  1603. lpValueName->Length = cbNameSize;
  1604. RtlCopyUnicodeString(lpValueName, &ValueNames[dwIndex]);
  1605. if (ARGUMENT_PRESENT (lpType)) {
  1606. *lpType = REG_BINARY;
  1607. }
  1608. }
  1609. } except (EXCEPTION_EXECUTE_HANDLER) {
  1610. ErrorCode = GetExceptionCode();
  1611. }
  1612. if (ErrorCode == ERROR_SUCCESS) {
  1613. ErrorCode = PerfRegQueryValue(hKey,
  1614. lpValueName,
  1615. NULL,
  1616. lpType,
  1617. lpData,
  1618. lpcbData,
  1619. lpcbLen);
  1620. }
  1621. return ErrorCode;
  1622. }
  1623. LONG
  1624. PerfEnumTextValue (
  1625. IN HKEY hKey,
  1626. IN DWORD dwIndex,
  1627. OUT PUNICODE_STRING lpValueName,
  1628. OUT LPDWORD lpReserved OPTIONAL,
  1629. OUT LPDWORD lpType OPTIONAL,
  1630. OUT LPBYTE lpData,
  1631. IN OUT LPDWORD lpcbData,
  1632. OUT LPDWORD lpcbLen OPTIONAL
  1633. )
  1634. /*++
  1635. Routine Description:
  1636. Enumerates Values under Perflib\lang
  1637. Arguments:
  1638. Same as RegEnumValue. Returns the values.
  1639. Return Value:
  1640. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  1641. --*/
  1642. {
  1643. UNICODE_STRING FullValueName;
  1644. LONG lReturn = ERROR_SUCCESS;
  1645. //
  1646. // Only two values, "Counter" and "Help"
  1647. //
  1648. try {
  1649. if (dwIndex==0) {
  1650. lpValueName->Length = 0;
  1651. RtlInitUnicodeString(&FullValueName, CounterValue);
  1652. } else if (dwIndex==1) {
  1653. lpValueName->Length = 0;
  1654. RtlInitUnicodeString(&FullValueName, HelpValue);
  1655. } else {
  1656. lReturn = ERROR_NO_MORE_ITEMS;
  1657. }
  1658. if (lReturn == ERROR_SUCCESS) {
  1659. RtlCopyUnicodeString(lpValueName, &FullValueName);
  1660. //
  1661. // We need to NULL terminate the name to make RPC happy.
  1662. //
  1663. if (lpValueName->Length+sizeof(WCHAR) <= lpValueName->MaximumLength) {
  1664. lpValueName->Buffer[lpValueName->Length / sizeof(WCHAR)] = UNICODE_NULL;
  1665. lpValueName->Length += sizeof(UNICODE_NULL);
  1666. }
  1667. }
  1668. } except (EXCEPTION_EXECUTE_HANDLER) {
  1669. lReturn = GetExceptionCode();
  1670. }
  1671. if (lReturn == ERROR_SUCCESS) {
  1672. lReturn = PerfRegQueryValue(hKey,
  1673. &FullValueName,
  1674. lpReserved,
  1675. lpType,
  1676. lpData,
  1677. lpcbData,
  1678. lpcbLen);
  1679. }
  1680. return lReturn;
  1681. }
  1682. #if 0
  1683. DWORD
  1684. CollectThreadFunction (
  1685. LPDWORD dwArg
  1686. )
  1687. {
  1688. DWORD dwWaitStatus = 0;
  1689. BOOL bExit = FALSE;
  1690. NTSTATUS status = STATUS_SUCCESS;
  1691. THREAD_BASIC_INFORMATION tbiData;
  1692. LONG lOldPriority, lNewPriority;
  1693. LONG lStatus;
  1694. UNREFERENCED_PARAMETER (dwArg);
  1695. // KdPrint(("PERFLIB: Entering Data Collection Thread: PID: %d, TID: %d\n",
  1696. // GetCurrentProcessId(), GetCurrentThreadId()));
  1697. // raise the priority of this thread
  1698. status = NtQueryInformationThread (
  1699. NtCurrentThread(),
  1700. ThreadBasicInformation,
  1701. &tbiData,
  1702. sizeof(tbiData),
  1703. NULL);
  1704. if (NT_SUCCESS(status)) {
  1705. lOldPriority = tbiData.Priority;
  1706. lNewPriority = DEFAULT_THREAD_PRIORITY; // perfmon's favorite priority
  1707. //
  1708. // Only RAISE the priority here. Don't lower it if it's high
  1709. //
  1710. if (lOldPriority < lNewPriority) {
  1711. status = NtSetInformationThread(
  1712. NtCurrentThread(),
  1713. ThreadPriority,
  1714. &lNewPriority,
  1715. sizeof(lNewPriority)
  1716. );
  1717. if (status != STATUS_SUCCESS) {
  1718. DebugPrint((0, "Set Thread Priority failed: 0x%8.8x\n", status));
  1719. }
  1720. }
  1721. }
  1722. // wait for flags
  1723. while (!bExit) {
  1724. dwWaitStatus = WaitForMultipleObjects (
  1725. COLLECT_THREAD_LOOP_EVENT_COUNT,
  1726. hCollectEvents,
  1727. FALSE, // wait for ANY event to go
  1728. INFINITE); // wait for ever
  1729. // see why the wait returned:
  1730. if (dwWaitStatus == (WAIT_OBJECT_0 + COLLECT_THREAD_PROCESS_EVENT)) {
  1731. // the event is cleared automatically
  1732. // collect data
  1733. lStatus = QueryExtensibleData (
  1734. &CollectThreadData);
  1735. CollectThreadData.lReturnValue = lStatus;
  1736. SetEvent (hCollectEvents[COLLECT_THREAD_DONE_EVENT]);
  1737. } else if (dwWaitStatus == (WAIT_OBJECT_0 + COLLECT_THREAD_EXIT_EVENT)) {
  1738. bExit = TRUE;
  1739. continue; // go up and bail out
  1740. } else {
  1741. // who knows, so output message
  1742. KdPrint(("\nPERFLILB: Collect Thread wait returned unknown value: 0x%8.8x",dwWaitStatus));
  1743. bExit = TRUE;
  1744. continue;
  1745. }
  1746. }
  1747. // KdPrint(("PERFLIB: Leaving Data Collection Thread: PID: %d, TID: %d\n",
  1748. // GetCurrentProcessId(), GetCurrentThreadId()));
  1749. return ERROR_SUCCESS;
  1750. }
  1751. #endif
  1752. BOOL
  1753. PerfRegInitialize()
  1754. {
  1755. RtlInitializeCriticalSection(&PerfpCritSect);
  1756. InitializeListHead((PLIST_ENTRY) &PerfpErrorLog);
  1757. return TRUE;
  1758. }
  1759. BOOL
  1760. PerfRegCleanup()
  1761. /*++
  1762. Routine Description:
  1763. Cleans up anything that perflib uses before it unloads. Assumes
  1764. that there are queries or perf reg opens outstanding.
  1765. Arguments:
  1766. None
  1767. Return Value:
  1768. Returns TRUE if succeed. FALSE otherwise.
  1769. --*/
  1770. {
  1771. if (hGlobalDataMutex != NULL) {
  1772. if (NumberOfOpens != 0)
  1773. return FALSE;
  1774. CloseHandle(hGlobalDataMutex);
  1775. hGlobalDataMutex = NULL;
  1776. }
  1777. PerfpDeleteErrorLogs(&PerfpErrorLog);
  1778. RtlDeleteCriticalSection(&PerfpCritSect);
  1779. return TRUE;
  1780. }