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.

276 lines
8.4 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. perftdet.c
  5. Abstract:
  6. This file implements an Performance Object that presents
  7. Thread details performance object data
  8. Created:
  9. Bob Watson 22-Oct-1996
  10. Revision History
  11. --*/
  12. //
  13. // Include Files
  14. //
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <winperf.h>
  20. #include <ntprfctr.h>
  21. #define PERF_HEAP hLibHeap
  22. #include <perfutil.h>
  23. #include "perfsprc.h"
  24. #include "perfmsg.h"
  25. #include "datatdet.h"
  26. DWORD APIENTRY
  27. CollectThreadDetailsObjectData (
  28. IN OUT LPVOID *lppData,
  29. IN OUT LPDWORD lpcbTotalBytes,
  30. IN OUT LPDWORD lpNumObjectTypes
  31. )
  32. /*++
  33. Routine Description:
  34. This routine will return the data for the processor object
  35. Arguments:
  36. IN OUT LPVOID *lppData
  37. IN: pointer to the address of the buffer to receive the completed
  38. PerfDataBlock and subordinate structures. This routine will
  39. append its data to the buffer starting at the point referenced
  40. by *lppData.
  41. OUT: points to the first byte after the data structure added by this
  42. routine. This routine updated the value at lppdata after appending
  43. its data.
  44. IN OUT LPDWORD lpcbTotalBytes
  45. IN: the address of the DWORD that tells the size in bytes of the
  46. buffer referenced by the lppData argument
  47. OUT: the number of bytes added by this routine is writted to the
  48. DWORD pointed to by this argument
  49. IN OUT LPDWORD NumObjectTypes
  50. IN: the address of the DWORD to receive the number of objects added
  51. by this routine
  52. OUT: the number of objects added by this routine is writted to the
  53. DWORD pointed to by this argument
  54. Returns:
  55. 0 if successful, else Win 32 error code of failure
  56. --*/
  57. {
  58. DWORD TotalLen; // Length of the total return block
  59. PTHREAD_DETAILS_DATA_DEFINITION pThreadDetailDataDefinition;
  60. PPERF_INSTANCE_DEFINITION pPerfInstanceDefinition;
  61. PTHREAD_DETAILS_COUNTER_DATA pTDCD;
  62. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  63. PSYSTEM_THREAD_INFORMATION ThreadInfo = NULL;
  64. ULONG ProcessNumber;
  65. ULONG NumThreadInstances;
  66. ULONG ThreadNumber = 0;
  67. ULONG ProcessBufferOffset;
  68. BOOLEAN NullProcess;
  69. NTSTATUS Status; // return from Nt Calls
  70. LONGLONG llPcValue; // value of current thread PC
  71. OBJECT_ATTRIBUTES Obja; // object attributes for thread context
  72. HANDLE hThread; // handle to current thread
  73. CONTEXT ThreadContext; // current thread context struct
  74. UNICODE_STRING ThreadName;
  75. WCHAR ThreadNameBuffer[MAX_THREAD_NAME_LENGTH+1];
  76. BOOL bMoreThreads;
  77. pThreadDetailDataDefinition = (THREAD_DETAILS_DATA_DEFINITION *) *lppData;
  78. //
  79. // Check for sufficient space for Thread object type definition
  80. //
  81. TotalLen = sizeof(THREAD_DETAILS_DATA_DEFINITION) +
  82. sizeof(PERF_INSTANCE_DEFINITION) +
  83. sizeof(THREAD_DETAILS_COUNTER_DATA);
  84. if ( *lpcbTotalBytes < TotalLen ) {
  85. *lpcbTotalBytes = 0;
  86. *lpNumObjectTypes = 0;
  87. return ERROR_MORE_DATA;
  88. }
  89. //
  90. // Define Thread data block
  91. //
  92. ThreadName.Length =
  93. ThreadName.MaximumLength = (MAX_THREAD_NAME_LENGTH + 1) * sizeof(WCHAR);
  94. ThreadName.Buffer = ThreadNameBuffer;
  95. memcpy (pThreadDetailDataDefinition,
  96. &ThreadDetailsDataDefinition,
  97. sizeof(THREAD_DETAILS_DATA_DEFINITION));
  98. ProcessBufferOffset = 0;
  99. // Now collect data for each Thread
  100. ProcessNumber = 0;
  101. NumThreadInstances = 0;
  102. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
  103. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  104. &pThreadDetailDataDefinition[1];
  105. TotalLen = sizeof (THREAD_DETAILS_DATA_DEFINITION);
  106. bMoreThreads = FALSE;
  107. if (ProcessInfo) {
  108. if (ProcessInfo->NextEntryOffset != 0) {
  109. bMoreThreads = TRUE;
  110. }
  111. }
  112. while ( bMoreThreads && (ProcessInfo != NULL)) {
  113. if ( ProcessInfo->ImageName.Buffer != NULL ||
  114. ProcessInfo->NumberOfThreads > 0 ) {
  115. NullProcess = FALSE;
  116. ThreadNumber = 0; // Thread number of this process
  117. ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  118. } else {
  119. NullProcess = TRUE;
  120. }
  121. while ( !NullProcess &&
  122. ThreadNumber < ProcessInfo->NumberOfThreads ) {
  123. TotalLen += sizeof(PERF_INSTANCE_DEFINITION) +
  124. (MAX_THREAD_NAME_LENGTH+1+sizeof(DWORD))*
  125. sizeof(WCHAR) +
  126. sizeof (THREAD_DETAILS_COUNTER_DATA);
  127. if ( *lpcbTotalBytes < TotalLen ) {
  128. *lpcbTotalBytes = 0;
  129. *lpNumObjectTypes = 0;
  130. return ERROR_MORE_DATA;
  131. }
  132. // Get Thread Context Information for Current PC field
  133. llPcValue = 0;
  134. InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL);
  135. Status = NtOpenThread(
  136. &hThread,
  137. THREAD_GET_CONTEXT,
  138. &Obja,
  139. &ThreadInfo->ClientId
  140. );
  141. if ( NT_SUCCESS(Status) ) {
  142. ThreadContext.ContextFlags = CONTEXT_CONTROL;
  143. Status = NtGetContextThread(hThread,&ThreadContext);
  144. NtClose(hThread);
  145. if ( NT_SUCCESS(Status) ) {
  146. llPcValue = (LONGLONG)CONTEXT_TO_PROGRAM_COUNTER(&ThreadContext);
  147. } else {
  148. llPcValue = 0; // an error occured so send back 0 PC
  149. }
  150. } else {
  151. llPcValue = 0; // an error occured so send back 0 PC
  152. }
  153. // The only name we've got is the thread number
  154. if (!NT_SUCCESS(RtlIntegerToUnicodeString(
  155. ThreadNumber,
  156. 10,
  157. &ThreadName))) {
  158. ThreadName.Length = 2 * sizeof(WCHAR);
  159. memcpy(ThreadName.Buffer, L"-1", ThreadName.Length);
  160. ThreadName.Buffer[2] = UNICODE_NULL;
  161. }
  162. MonBuildInstanceDefinition(pPerfInstanceDefinition,
  163. (PVOID *) &pTDCD,
  164. EXPROCESS_OBJECT_TITLE_INDEX,
  165. ProcessNumber,
  166. (DWORD)-1,
  167. ThreadName.Buffer);
  168. //
  169. //
  170. // Format and collect Thread data
  171. //
  172. pTDCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof (THREAD_DETAILS_COUNTER_DATA));
  173. pTDCD->UserPc = llPcValue;
  174. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pTDCD[1];
  175. NumThreadInstances++;
  176. ThreadNumber++;
  177. ThreadInfo++;
  178. }
  179. if (ProcessInfo->NextEntryOffset == 0) {
  180. // no more entries so bail out of the loop
  181. bMoreThreads = FALSE;
  182. continue;
  183. }
  184. ProcessBufferOffset += ProcessInfo->NextEntryOffset;
  185. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  186. &pProcessBuffer[ProcessBufferOffset];
  187. if ( !NullProcess ) {
  188. ProcessNumber++;
  189. }
  190. }
  191. // Note number of Thread instances
  192. pThreadDetailDataDefinition->ThreadDetailsObjectType.NumInstances =
  193. NumThreadInstances;
  194. //
  195. // Now we know how large an area we used for the
  196. // Thread definition, so we can update the offset
  197. // to the next object definition
  198. //
  199. *lpcbTotalBytes =
  200. pThreadDetailDataDefinition->ThreadDetailsObjectType.TotalByteLength =
  201. QWORD_MULTIPLE(
  202. (DWORD)((PCHAR) pPerfInstanceDefinition -
  203. (PCHAR) pThreadDetailDataDefinition));
  204. #if DBG
  205. if (*lpcbTotalBytes > TotalLen ) {
  206. DbgPrint ("\nPERFPROC: Thread Details Perf Ctr. Instance Size Underestimated:");
  207. DbgPrint ("\nPERFPROC: Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes);
  208. }
  209. #endif
  210. *lppData = (LPVOID) ((PCHAR) pThreadDetailDataDefinition + *lpcbTotalBytes);
  211. *lpNumObjectTypes = 1;
  212. return ERROR_SUCCESS;
  213. }