Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

441 lines
11 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 1992 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. Russ Blake 07/30/92
  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 "p5ctrmsg.h" // error message definition
  23. #include "p5msg.h"
  24. #include "perfutil.h"
  25. #define INITIAL_SIZE 1024L
  26. #define EXTEND_SIZE 1024L
  27. //
  28. // Global data definitions.
  29. //
  30. ULONG ulInfoBufferSize = 0;
  31. HANDLE hEventLog = NULL; // event log handle for reporting events
  32. // initialized in Open... routines
  33. DWORD dwLogUsers = 0; // count of functions using event log
  34. DWORD MESSAGE_LEVEL = 0;
  35. WCHAR GLOBAL_STRING[] = L"Global";
  36. WCHAR FOREIGN_STRING[] = L"Foreign";
  37. WCHAR COSTLY_STRING[] = L"Costly";
  38. WCHAR NULL_STRING[] = L"\0"; // pointer to null string
  39. // test for delimiter, end of line and non-digit characters
  40. // used by IsNumberInUnicodeList routine
  41. //
  42. #define DIGIT 1
  43. #define DELIMITER 2
  44. #define INVALID 3
  45. #define EvalThisChar(c,d) ( \
  46. (c == d) ? DELIMITER : \
  47. (c == 0) ? DELIMITER : \
  48. (c < (WCHAR)'0') ? INVALID : \
  49. (c > (WCHAR)'9') ? INVALID : \
  50. DIGIT)
  51. HANDLE
  52. MonOpenEventLog (
  53. )
  54. /*++
  55. Routine Description:
  56. Reads the level of event logging from the registry and opens the
  57. channel to the event logger for subsequent event log entries.
  58. Arguments:
  59. None
  60. Return Value:
  61. Handle to the event log for reporting events.
  62. NULL if open not successful.
  63. --*/
  64. {
  65. HKEY hAppKey;
  66. TCHAR LogLevelKeyName[] = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
  67. TCHAR LogLevelValueName[] = "EventLogLevel";
  68. LONG lStatus;
  69. DWORD dwLogLevel;
  70. DWORD dwValueType;
  71. DWORD dwValueSize;
  72. // if global value of the logging level not initialized or is disabled,
  73. // check the registry to see if it should be updated.
  74. if (!MESSAGE_LEVEL) {
  75. lStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  76. LogLevelKeyName,
  77. 0,
  78. KEY_READ,
  79. &hAppKey);
  80. dwValueSize = sizeof (dwLogLevel);
  81. if (lStatus == ERROR_SUCCESS) {
  82. lStatus = RegQueryValueEx (hAppKey,
  83. LogLevelValueName,
  84. (LPDWORD)NULL,
  85. &dwValueType,
  86. (LPBYTE)&dwLogLevel,
  87. &dwValueSize);
  88. if (lStatus == ERROR_SUCCESS) {
  89. MESSAGE_LEVEL = dwLogLevel;
  90. } else {
  91. MESSAGE_LEVEL = MESSAGE_LEVEL_DEFAULT;
  92. }
  93. RegCloseKey (hAppKey);
  94. } else {
  95. MESSAGE_LEVEL = MESSAGE_LEVEL_DEFAULT;
  96. }
  97. }
  98. if (hEventLog == NULL){
  99. hEventLog = RegisterEventSource (
  100. (LPTSTR)NULL, // Use Local Machine
  101. APP_NAME); // event log app name to find in registry
  102. if (hEventLog != NULL) {
  103. REPORT_INFORMATION (UTIL_LOG_OPEN, LOG_DEBUG);
  104. }
  105. }
  106. if (hEventLog != NULL) {
  107. dwLogUsers++; // increment count of perfctr log users
  108. }
  109. return (hEventLog);
  110. }
  111. VOID
  112. MonCloseEventLog (
  113. )
  114. /*++
  115. Routine Description:
  116. Closes the handle to the event logger if this is the last caller
  117. Arguments:
  118. None
  119. Return Value:
  120. None
  121. --*/
  122. {
  123. if (hEventLog != NULL) {
  124. dwLogUsers--; // decrement usage
  125. if (dwLogUsers <= 0) { // and if we're the last, then close up log
  126. REPORT_INFORMATION (UTIL_CLOSING_LOG, LOG_DEBUG);
  127. DeregisterEventSource (hEventLog);
  128. }
  129. }
  130. }
  131. DWORD
  132. GetQueryType (
  133. IN LPWSTR lpValue
  134. )
  135. /*++
  136. GetQueryType
  137. returns the type of query described in the lpValue string so that
  138. the appropriate processing method may be used
  139. Arguments
  140. IN lpValue
  141. string passed to PerfRegQuery Value for processing
  142. Return Value
  143. QUERY_GLOBAL
  144. if lpValue == 0 (null pointer)
  145. lpValue == pointer to Null string
  146. lpValue == pointer to "Global" string
  147. QUERY_FOREIGN
  148. if lpValue == pointer to "Foriegn" string
  149. QUERY_COSTLY
  150. if lpValue == pointer to "Costly" string
  151. otherwise:
  152. QUERY_ITEMS
  153. --*/
  154. {
  155. WCHAR *pwcArgChar, *pwcTypeChar;
  156. BOOL bFound;
  157. if (lpValue == 0) {
  158. return QUERY_GLOBAL;
  159. } else if (*lpValue == 0) {
  160. return QUERY_GLOBAL;
  161. }
  162. // check for "Global" request
  163. pwcArgChar = lpValue;
  164. pwcTypeChar = GLOBAL_STRING;
  165. bFound = TRUE; // assume found until contradicted
  166. // check to the length of the shortest string
  167. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  168. if (*pwcArgChar++ != *pwcTypeChar++) {
  169. bFound = FALSE; // no match
  170. break; // bail out now
  171. }
  172. }
  173. if (bFound) return QUERY_GLOBAL;
  174. // check for "Foreign" request
  175. pwcArgChar = lpValue;
  176. pwcTypeChar = FOREIGN_STRING;
  177. bFound = TRUE; // assume found until contradicted
  178. // check to the length of the shortest string
  179. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  180. if (*pwcArgChar++ != *pwcTypeChar++) {
  181. bFound = FALSE; // no match
  182. break; // bail out now
  183. }
  184. }
  185. if (bFound) return QUERY_FOREIGN;
  186. // check for "Costly" request
  187. pwcArgChar = lpValue;
  188. pwcTypeChar = COSTLY_STRING;
  189. bFound = TRUE; // assume found until contradicted
  190. // check to the length of the shortest string
  191. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  192. if (*pwcArgChar++ != *pwcTypeChar++) {
  193. bFound = FALSE; // no match
  194. break; // bail out now
  195. }
  196. }
  197. if (bFound) return QUERY_COSTLY;
  198. // if not Global and not Foreign and not Costly,
  199. // then it must be an item list
  200. return QUERY_ITEMS;
  201. }
  202. BOOL
  203. IsNumberInUnicodeList (
  204. IN DWORD dwNumber,
  205. IN LPWSTR lpwszUnicodeList
  206. )
  207. /*++
  208. IsNumberInUnicodeList
  209. Arguments:
  210. IN dwNumber
  211. DWORD number to find in list
  212. IN lpwszUnicodeList
  213. Null terminated, Space delimited list of decimal numbers
  214. Return Value:
  215. TRUE:
  216. dwNumber was found in the list of unicode number strings
  217. FALSE:
  218. dwNumber was not found in the list.
  219. --*/
  220. {
  221. DWORD dwThisNumber;
  222. WCHAR *pwcThisChar;
  223. BOOL bValidNumber;
  224. BOOL bNewItem;
  225. BOOL bReturnValue;
  226. WCHAR wcDelimiter; // could be an argument to be more flexible
  227. if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not founde
  228. pwcThisChar = lpwszUnicodeList;
  229. dwThisNumber = 0;
  230. wcDelimiter = (WCHAR)' ';
  231. bValidNumber = FALSE;
  232. bNewItem = TRUE;
  233. while (TRUE) {
  234. switch (EvalThisChar (*pwcThisChar, wcDelimiter)) {
  235. case DIGIT:
  236. // if this is the first digit after a delimiter, then
  237. // set flags to start computing the new number
  238. if (bNewItem) {
  239. bNewItem = FALSE;
  240. bValidNumber = TRUE;
  241. }
  242. if (bValidNumber) {
  243. dwThisNumber *= 10;
  244. dwThisNumber += (*pwcThisChar - (WCHAR)'0');
  245. }
  246. break;
  247. case DELIMITER:
  248. // a delimter is either the delimiter character or the
  249. // end of the string ('\0') if when the delimiter has been
  250. // reached a valid number was found, then compare it to the
  251. // number from the argument list. if this is the end of the
  252. // string and no match was found, then return.
  253. //
  254. if (bValidNumber) {
  255. if (dwThisNumber == dwNumber) return TRUE;
  256. bValidNumber = FALSE;
  257. }
  258. if (*pwcThisChar == 0) {
  259. return FALSE;
  260. } else {
  261. bNewItem = TRUE;
  262. dwThisNumber = 0;
  263. }
  264. break;
  265. case INVALID:
  266. // if an invalid character was encountered, ignore all
  267. // characters up to the next delimiter and then start fresh.
  268. // the invalid number is not compared.
  269. bValidNumber = FALSE;
  270. break;
  271. default:
  272. break;
  273. }
  274. pwcThisChar++;
  275. }
  276. } // IsNumberInUnicodeList
  277. BOOL
  278. MonBuildInstanceDefinition(
  279. PERF_INSTANCE_DEFINITION *pBuffer,
  280. PVOID *pBufferNext,
  281. DWORD ParentObjectTitleIndex,
  282. DWORD ParentObjectInstance,
  283. DWORD UniqueID,
  284. PUNICODE_STRING Name
  285. )
  286. /*++
  287. MonBuildInstanceDefinition - Build an instance of an object
  288. Inputs:
  289. pBuffer - pointer to buffer where instance is to
  290. be constructed
  291. pBufferNext - pointer to a pointer which will contain
  292. next available location, DWORD aligned
  293. ParentObjectTitleIndex
  294. - Title Index of parent object type; 0 if
  295. no parent object
  296. ParentObjectInstance
  297. - Index into instances of parent object
  298. type, starting at 0, for this instances
  299. parent object instance
  300. UniqueID - a unique identifier which should be used
  301. instead of the Name for identifying
  302. this instance
  303. Name - Name of this instance
  304. --*/
  305. {
  306. DWORD NameLength;
  307. WCHAR *pName;
  308. //
  309. // Include trailing null in name size
  310. //
  311. NameLength = Name->Length;
  312. if ( !NameLength ||
  313. Name->Buffer[(NameLength/sizeof(WCHAR))-1] != UNICODE_NULL ) {
  314. NameLength += sizeof(WCHAR);
  315. }
  316. pBuffer->ByteLength = sizeof(PERF_INSTANCE_DEFINITION) +
  317. DWORD_MULTIPLE(NameLength);
  318. pBuffer->ParentObjectTitleIndex = ParentObjectTitleIndex;
  319. pBuffer->ParentObjectInstance = ParentObjectInstance;
  320. pBuffer->UniqueID = UniqueID;
  321. pBuffer->NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
  322. pBuffer->NameLength = NameLength;
  323. pName = (PWCHAR)&pBuffer[1];
  324. RtlMoveMemory(pName,Name->Buffer,Name->Length);
  325. // Always null terminated. Space for this reserved above.
  326. pName[(NameLength/sizeof(WCHAR))-1] = UNICODE_NULL;
  327. *pBufferNext = (PVOID) ((PCHAR) pBuffer + pBuffer->ByteLength);
  328. return 0;
  329. }
  330.