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.

564 lines
15 KiB

  1. /*++
  2. Copyright (c) 1995-6 Microsoft Corporation
  3. Module Name:
  4. perfutil.c
  5. Abstract:
  6. This file implements the utility routines used to construct the
  7. common parts of a PERF_INSTANCE_DEFINITION (see winperf.h) and
  8. perform event logging functions.
  9. Created:
  10. Bob Watson 28-Jul-1995
  11. Revision History:
  12. --*/
  13. //
  14. // include files
  15. //
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <string.h>
  21. #include <winperf.h>
  22. #include "perfutil.h"
  23. #include "perfmsg.h"
  24. //
  25. // Global data definitions.
  26. //
  27. ULONG ulInfoBufferSize = 0;
  28. extern HANDLE hEventLog; // event log handle for reporting events
  29. // initialized in Open... routines
  30. DWORD dwLogUsers = 0; // count of functions using event log
  31. DWORD MESSAGE_LEVEL = 0;
  32. const WCHAR GLOBAL_STRING[] = L"Global";
  33. const WCHAR FOREIGN_STRING[] = L"Foreign";
  34. const WCHAR COSTLY_STRING[] = L"Costly";
  35. const WCHAR NULL_STRING[] = L"\0"; // pointer to null string
  36. const WCHAR szTotalValue[] = L"TotalInstanceName";
  37. const WCHAR szDefaultTotalString[] = L"_Total";
  38. // test for delimiter, end of line and non-digit characters
  39. // used by IsNumberInUnicodeList routine
  40. //
  41. #define DIGIT 1
  42. #define DELIMITER 2
  43. #define INVALID 3
  44. #define EvalThisChar(c,d) ( \
  45. (c == d) ? DELIMITER : \
  46. (c == 0) ? DELIMITER : \
  47. (c < (WCHAR)'0') ? INVALID : \
  48. (c > (WCHAR)'9') ? INVALID : \
  49. DIGIT)
  50. LONG
  51. GetPerflibKeyValue (
  52. LPCWSTR szItem,
  53. DWORD dwRegType,
  54. DWORD dwMaxSize, // ... of pReturnBuffer in bytes
  55. LPVOID pReturnBuffer,
  56. DWORD dwDefaultSize, // ... of pDefault in bytes
  57. LPVOID pDefault
  58. )
  59. /*++
  60. read and return the current value of the specified value
  61. under the Perflib registry key. If unable to read the value
  62. return the default value from the argument list.
  63. the value is returned in the pReturnBuffer.
  64. --*/
  65. {
  66. HKEY hPerflibKey;
  67. OBJECT_ATTRIBUTES Obja;
  68. NTSTATUS Status;
  69. UNICODE_STRING PerflibSubKeyString;
  70. UNICODE_STRING ValueNameString;
  71. LONG lReturn;
  72. PKEY_VALUE_PARTIAL_INFORMATION pValueInformation;
  73. PKEY_VALUE_PARTIAL_INFORMATION pNewValueInformation;
  74. DWORD ValueBufferLength;
  75. DWORD ResultLength;
  76. BOOL bUseDefault = TRUE;
  77. // initialize UNICODE_STRING structures used in this function
  78. RtlInitUnicodeString (
  79. &PerflibSubKeyString,
  80. L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");
  81. RtlInitUnicodeString (
  82. &ValueNameString,
  83. (LPWSTR)szItem);
  84. //
  85. // Initialize the OBJECT_ATTRIBUTES structure and open the key.
  86. //
  87. InitializeObjectAttributes(
  88. &Obja,
  89. &PerflibSubKeyString,
  90. OBJ_CASE_INSENSITIVE,
  91. NULL,
  92. NULL
  93. );
  94. Status = NtOpenKey(
  95. &hPerflibKey,
  96. KEY_READ,
  97. &Obja
  98. );
  99. if (NT_SUCCESS( Status )) {
  100. // read value of desired entry
  101. ValueBufferLength = ResultLength = 1024;
  102. pValueInformation = ALLOCMEM(RtlProcessHeap(), 0, ResultLength);
  103. if (pValueInformation != NULL) {
  104. while ( (Status = NtQueryValueKey(hPerflibKey,
  105. &ValueNameString,
  106. KeyValuePartialInformation,
  107. pValueInformation,
  108. ValueBufferLength,
  109. &ResultLength))
  110. == STATUS_BUFFER_OVERFLOW ) {
  111. pNewValueInformation = REALLOCMEM(RtlProcessHeap(), 0,
  112. pValueInformation,
  113. ResultLength);
  114. if ( pNewValueInformation == NULL) {
  115. FREEMEM(RtlProcessHeap(), 0, pValueInformation);
  116. pValueInformation = NULL;
  117. Status = STATUS_NO_MEMORY;
  118. break;
  119. } else {
  120. pValueInformation = pNewValueInformation;
  121. ValueBufferLength = ResultLength;
  122. }
  123. }
  124. if (NT_SUCCESS(Status)) {
  125. // check to see if it's the desired type
  126. if (pValueInformation->Type == dwRegType) {
  127. // see if it will fit
  128. if (pValueInformation->DataLength <= dwMaxSize) {
  129. memcpy (pReturnBuffer, &pValueInformation->Data[0],
  130. pValueInformation->DataLength);
  131. bUseDefault = FALSE;
  132. lReturn = STATUS_SUCCESS;
  133. }
  134. }
  135. } else {
  136. // return the default value
  137. lReturn = Status;
  138. }
  139. // Release temp buffer. Check pValueInfo again since
  140. // the realloc may have failed above.
  141. if (pValueInformation != NULL) {
  142. FREEMEM (RtlProcessHeap(), 0, pValueInformation);
  143. }
  144. } else {
  145. // unable to allocate memory for this operation so
  146. // just return the default value
  147. }
  148. // close the registry key
  149. NtClose(hPerflibKey);
  150. } else {
  151. // return default value
  152. }
  153. if (bUseDefault) {
  154. memcpy (pReturnBuffer, pDefault, dwDefaultSize);
  155. lReturn = STATUS_SUCCESS;
  156. }
  157. return lReturn;
  158. }
  159. HANDLE
  160. MonOpenEventLog (
  161. IN LPWSTR szAppName
  162. )
  163. /*++
  164. Routine Description:
  165. Reads the level of event logging from the registry and opens the
  166. channel to the event logger for subsequent event log entries.
  167. Arguments:
  168. None
  169. Return Value:
  170. Handle to the event log for reporting events.
  171. NULL if open not successful.
  172. --*/
  173. {
  174. HKEY hAppKey;
  175. TCHAR LogLevelKeyName[] = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");
  176. TCHAR LogLevelValueName[] = TEXT("EventLogLevel");
  177. LONG lStatus;
  178. DWORD dwLogLevel;
  179. DWORD dwValueType;
  180. DWORD dwValueSize;
  181. // if global value of the logging level not initialized or is disabled,
  182. // check the registry to see if it should be updated.
  183. if (!MESSAGE_LEVEL) {
  184. lStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  185. LogLevelKeyName,
  186. 0,
  187. KEY_READ,
  188. &hAppKey);
  189. dwValueSize = sizeof (dwLogLevel);
  190. if (lStatus == ERROR_SUCCESS) {
  191. lStatus = RegQueryValueEx (hAppKey,
  192. LogLevelValueName,
  193. (LPDWORD)NULL,
  194. &dwValueType,
  195. (LPBYTE)&dwLogLevel,
  196. &dwValueSize);
  197. if (lStatus == ERROR_SUCCESS) {
  198. MESSAGE_LEVEL = dwLogLevel;
  199. } else {
  200. MESSAGE_LEVEL = MESSAGE_LEVEL_DEFAULT;
  201. }
  202. RegCloseKey (hAppKey);
  203. } else {
  204. MESSAGE_LEVEL = MESSAGE_LEVEL_DEFAULT;
  205. }
  206. }
  207. if (hEventLog == NULL){
  208. hEventLog = RegisterEventSourceW (
  209. (LPWSTR)NULL, // Use Local Machine
  210. szAppName); // event log app name to find in registry
  211. }
  212. if (hEventLog != NULL) {
  213. dwLogUsers++; // increment count of perfctr log users
  214. }
  215. return (hEventLog);
  216. }
  217. VOID
  218. MonCloseEventLog (
  219. )
  220. /*++
  221. Routine Description:
  222. Closes the handle to the event logger if this is the last caller
  223. Arguments:
  224. None
  225. Return Value:
  226. None
  227. --*/
  228. {
  229. if (hEventLog != NULL) {
  230. dwLogUsers--; // decrement usage
  231. if (dwLogUsers <= 0) { // and if we're the last, then close up log
  232. DeregisterEventSource (hEventLog);
  233. }
  234. }
  235. }
  236. DWORD
  237. GetQueryType (
  238. IN LPWSTR lpValue
  239. )
  240. /*++
  241. GetQueryType
  242. returns the type of query described in the lpValue string so that
  243. the appropriate processing method may be used
  244. Arguments
  245. IN lpValue
  246. string passed to PerfRegQuery Value for processing
  247. Return Value
  248. QUERY_GLOBAL
  249. if lpValue == 0 (null pointer)
  250. lpValue == pointer to Null string
  251. lpValue == pointer to "Global" string
  252. QUERY_FOREIGN
  253. if lpValue == pointer to "Foriegn" string
  254. QUERY_COSTLY
  255. if lpValue == pointer to "Costly" string
  256. otherwise:
  257. QUERY_ITEMS
  258. --*/
  259. {
  260. WCHAR *pwcArgChar, *pwcTypeChar;
  261. BOOL bFound;
  262. if (lpValue == 0) {
  263. return QUERY_GLOBAL;
  264. } else if (*lpValue == 0) {
  265. return QUERY_GLOBAL;
  266. }
  267. // check for "Global" request
  268. pwcArgChar = lpValue;
  269. pwcTypeChar = (LPWSTR)GLOBAL_STRING;
  270. bFound = TRUE; // assume found until contradicted
  271. // check to the length of the shortest string
  272. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  273. if (*pwcArgChar++ != *pwcTypeChar++) {
  274. bFound = FALSE; // no match
  275. break; // bail out now
  276. }
  277. }
  278. if (bFound) return QUERY_GLOBAL;
  279. // check for "Foreign" request
  280. pwcArgChar = lpValue;
  281. pwcTypeChar = (LPWSTR)FOREIGN_STRING;
  282. bFound = TRUE; // assume found until contradicted
  283. // check to the length of the shortest string
  284. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  285. if (*pwcArgChar++ != *pwcTypeChar++) {
  286. bFound = FALSE; // no match
  287. break; // bail out now
  288. }
  289. }
  290. if (bFound) return QUERY_FOREIGN;
  291. // check for "Costly" request
  292. pwcArgChar = lpValue;
  293. pwcTypeChar = (LPWSTR)COSTLY_STRING;
  294. bFound = TRUE; // assume found until contradicted
  295. // check to the length of the shortest string
  296. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  297. if (*pwcArgChar++ != *pwcTypeChar++) {
  298. bFound = FALSE; // no match
  299. break; // bail out now
  300. }
  301. }
  302. if (bFound) return QUERY_COSTLY;
  303. // if not Global and not Foreign and not Costly,
  304. // then it must be an item list
  305. return QUERY_ITEMS;
  306. }
  307. BOOL
  308. IsNumberInUnicodeList (
  309. IN DWORD dwNumber,
  310. IN LPWSTR lpwszUnicodeList
  311. )
  312. /*++
  313. IsNumberInUnicodeList
  314. Arguments:
  315. IN dwNumber
  316. DWORD number to find in list
  317. IN lpwszUnicodeList
  318. Null terminated, Space delimited list of decimal numbers
  319. Return Value:
  320. TRUE:
  321. dwNumber was found in the list of unicode number strings
  322. FALSE:
  323. dwNumber was not found in the list.
  324. --*/
  325. {
  326. DWORD dwThisNumber;
  327. WCHAR *pwcThisChar;
  328. BOOL bValidNumber;
  329. BOOL bNewItem;
  330. WCHAR wcDelimiter; // could be an argument to be more flexible
  331. if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not founde
  332. pwcThisChar = lpwszUnicodeList;
  333. dwThisNumber = 0;
  334. wcDelimiter = (WCHAR)' ';
  335. bValidNumber = FALSE;
  336. bNewItem = TRUE;
  337. while (TRUE) {
  338. switch (EvalThisChar (*pwcThisChar, wcDelimiter)) {
  339. case DIGIT:
  340. // if this is the first digit after a delimiter, then
  341. // set flags to start computing the new number
  342. if (bNewItem) {
  343. bNewItem = FALSE;
  344. bValidNumber = TRUE;
  345. }
  346. if (bValidNumber) {
  347. dwThisNumber *= 10;
  348. dwThisNumber += (*pwcThisChar - (WCHAR)'0');
  349. }
  350. break;
  351. case DELIMITER:
  352. // a delimter is either the delimiter character or the
  353. // end of the string ('\0') if when the delimiter has been
  354. // reached a valid number was found, then compare it to the
  355. // number from the argument list. if this is the end of the
  356. // string and no match was found, then return.
  357. //
  358. if (bValidNumber) {
  359. if (dwThisNumber == dwNumber) return TRUE;
  360. bValidNumber = FALSE;
  361. }
  362. if (*pwcThisChar == 0) {
  363. return FALSE;
  364. } else {
  365. bNewItem = TRUE;
  366. dwThisNumber = 0;
  367. }
  368. break;
  369. case INVALID:
  370. // if an invalid character was encountered, ignore all
  371. // characters up to the next delimiter and then start fresh.
  372. // the invalid number is not compared.
  373. bValidNumber = FALSE;
  374. break;
  375. default:
  376. break;
  377. }
  378. pwcThisChar++;
  379. }
  380. return FALSE;
  381. } // IsNumberInUnicodeList
  382. BOOL
  383. MonBuildInstanceDefinition(
  384. PERF_INSTANCE_DEFINITION *pBuffer,
  385. PVOID *pBufferNext,
  386. DWORD ParentObjectTitleIndex,
  387. DWORD ParentObjectInstance,
  388. DWORD UniqueID,
  389. LPWSTR Name
  390. )
  391. /*++
  392. MonBuildInstanceDefinition - Build an instance of an object
  393. Inputs:
  394. pBuffer - pointer to buffer where instance is to
  395. be constructed
  396. pBufferNext - pointer to a pointer which will contain
  397. next available location, DWORD aligned
  398. ParentObjectTitleIndex
  399. - Title Index of parent object type; 0 if
  400. no parent object
  401. ParentObjectInstance
  402. - Index into instances of parent object
  403. type, starting at 0, for this instances
  404. parent object instance
  405. UniqueID - a unique identifier which should be used
  406. instead of the Name for identifying
  407. this instance
  408. Name - Name of this instance
  409. --*/
  410. {
  411. DWORD NameLength;
  412. LPWSTR pName;
  413. //
  414. // Include trailing null in name size
  415. //
  416. NameLength = (lstrlenW(Name) + 1) * sizeof(WCHAR);
  417. pBuffer->ByteLength = sizeof(PERF_INSTANCE_DEFINITION) +
  418. NameLength;
  419. pBuffer->ParentObjectTitleIndex = ParentObjectTitleIndex;
  420. pBuffer->ParentObjectInstance = ParentObjectInstance;
  421. pBuffer->UniqueID = UniqueID;
  422. pBuffer->NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
  423. pBuffer->NameLength = NameLength;
  424. // copy name to name buffer
  425. pName = (LPWSTR)&pBuffer[1];
  426. memcpy(pName,Name,NameLength);
  427. // update "next byte" pointer
  428. *pBufferNext = (PVOID) ((PCHAR) pBuffer + pBuffer->ByteLength);
  429. // round up to put next buffer on a QUADWORD boundry
  430. *pBufferNext = ALIGN_ON_QWORD (*pBufferNext);
  431. // adjust length value to match new length
  432. pBuffer->ByteLength = (ULONG)((ULONG_PTR)*pBufferNext - (ULONG_PTR)pBuffer);
  433. return 0;
  434. }