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.

441 lines
11 KiB

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