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.

1240 lines
44 KiB

  1. /*++ BUILD Version: 0002 // Increment this if a change has global effects
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. PschdPrf.c
  5. Abstract:
  6. This file implements the Extensible Objects for the PSched Flow and
  7. Pipe object types. In particular, it implements the three Open,
  8. Collect, and Close functions called by PerfMon/SysMon.
  9. Author:
  10. Eliot Gillum (t-eliotg) June 14, 1998
  11. Revision History
  12. Rajesh Sundaram : Reworked the code to work with flows/instances coming up and down.
  13. --*/
  14. // Useful macro
  15. #define WRITEBUF(_addr, _len) memcpy(pdwBuf,(_addr),(_len)); pdwBuf = (PULONG)((PUCHAR)pdwBuf + (_len));
  16. #define MULTIPLE_OF_EIGHT(_x) (((_x)+7) & ~7)
  17. #include <windows.h>
  18. #include <winerror.h>
  19. #include <string.h>
  20. #include <wtypes.h>
  21. #include <ntprfctr.h>
  22. #include <malloc.h>
  23. #include <ntddndis.h>
  24. #include <qos.h>
  25. #include <ntddpsch.h>
  26. #include <objbase.h>
  27. #include "PschdPrf.h"
  28. #include "PerfUtil.h"
  29. #include "PschdCnt.h"
  30. #include <rtutils.h>
  31. // Psched Performance Key
  32. #define PSCHED_PERF_KEY TEXT("SYSTEM\\CurrentControlSet\\Services\\PSched\\Performance")
  33. HINSTANCE ghInst; // module instance handle
  34. DWORD dwOpenCount = 0; // count of "Open" threads
  35. BOOL bInitOK = FALSE; // true = DLL initialized OK
  36. HANDLE ghTciClient; // TCI client handle
  37. HANDLE ghClRegCtx; // TCI Client Registration Context
  38. PPIPE_INFO gpPI; // Pipe and flow information array
  39. ULONG gTotalIfcNameSize; // Number of bytes of all the interface names (incl. NULL term. char)
  40. ULONG gTotalFlowNameSize; // Number of bytes of all the flow names (incl. NULL term. char)
  41. ULONG giIfcBufSize = 1024; // set the initial buffer size to 1kb
  42. DWORD gPipeStatLen; // Length of the buffer used to define all the
  43. // Pipe statistics that will be reported by the
  44. // underlying components
  45. DWORD gFlowStatLen; // Length of the buffer used to define all the
  46. // Flow statistics that will be reported by the
  47. // underlying components
  48. CRITICAL_SECTION ghPipeFlowCriticalSection;
  49. #if DBG
  50. //
  51. // For tracing support.
  52. //
  53. #define DBG_INFO (0x00010000 | TRACE_USE_MASK)
  54. #define DBG_ERROR (0x00020000 | TRACE_USE_MASK)
  55. DWORD gTraceID = INVALID_TRACEID;
  56. #define Trace0(_mask, _str) TracePrintfEx(gTraceID, _mask, _str)
  57. #define Trace1(_mask, _str, _a) TracePrintfEx(gTraceID, _mask, _str, _a)
  58. #else
  59. #define Trace0(_mask, _str)
  60. #define Trace1(_mask, _str, _a)
  61. #endif
  62. // Function Prototypes
  63. //
  64. // these are used to ensure that the data collection functions
  65. // accessed by Perflib will have the correct calling format.
  66. PM_OPEN_PROC OpenPschedPerformanceData;
  67. PM_COLLECT_PROC CollectPschedPerformanceData;
  68. PM_CLOSE_PROC ClosePschedPerformanceData;
  69. // Declared in PschdDat.c
  70. extern PERF_OBJECT_TYPE PsPipeObjType;
  71. extern PS_PIPE_PIPE_STAT_DEF PsPipePipeStatDef;
  72. extern PS_PIPE_CONFORMER_STAT_DEF PsPipeConformerStatDef;
  73. extern PS_PIPE_SHAPER_STAT_DEF PsPipeShaperStatDef;
  74. extern PS_PIPE_SEQUENCER_STAT_DEF PsPipeSequencerStatDef;
  75. extern PERF_OBJECT_TYPE PsFlowObjType;
  76. extern PS_FLOW_FLOW_STAT_DEF PsFlowFlowStatDef;
  77. extern PS_FLOW_CONFORMER_STAT_DEF PsFlowConformerStatDef;
  78. extern PS_FLOW_SHAPER_STAT_DEF PsFlowShaperStatDef;
  79. extern PS_FLOW_SEQUENCER_STAT_DEF PsFlowSequencerStatDef;
  80. void closePipeFlowInfo(PPIPE_INFO *ppPI);
  81. BOOL
  82. getFlowInfo(IN PPIPE_INFO pPI, IN ULONG flowCount)
  83. {
  84. HANDLE hEnum;
  85. ULONG size;
  86. PVOID pFlowBuf;
  87. static ULONG FlowBufSize=1024;
  88. ULONG j;
  89. ULONG BytesWritten;
  90. ULONG status;
  91. ULONG nameSize;
  92. // initialize the enumeration handle
  93. hEnum = NULL;
  94. for(j=0; j<pPI->numFlows; j++)
  95. {
  96. size = ((wcslen(pPI->pFlowInfo[j].FriendlyName) + 1) * sizeof(WCHAR));
  97. gTotalFlowNameSize -= MULTIPLE_OF_EIGHT(size);
  98. }
  99. PsFlowObjType.NumInstances -= pPI->numFlows;
  100. PsFlowObjType.NumInstances += flowCount;
  101. pPI->numFlows = flowCount;
  102. if(pPI->pFlowInfo)
  103. free(pPI->pFlowInfo);
  104. if(flowCount)
  105. {
  106. pPI->pFlowInfo = (PFLOW_INFO) malloc(flowCount * sizeof(FLOW_INFO));
  107. //
  108. // We cannot allocate memory for the flow names. There is nothing much we can do here.
  109. // let's pretend as though there are no flows.
  110. //
  111. if(!pPI->pFlowInfo)
  112. {
  113. Trace0(DBG_ERROR, L"[getFlowInfo]: malloc failed \n");
  114. PsFlowObjType.NumInstances -= flowCount;
  115. pPI->numFlows = 0;
  116. return FALSE;
  117. }
  118. else
  119. {
  120. memset(pPI->pFlowInfo, 0, sizeof(FLOW_INFO) * flowCount);
  121. }
  122. // allocate the flow enumeration buffer
  123. pFlowBuf = malloc(FlowBufSize);
  124. if(!pFlowBuf)
  125. {
  126. Trace0(DBG_ERROR, L"[getFlowInfo]: malloc failed \n");
  127. free(pPI->pFlowInfo);
  128. pPI->pFlowInfo = NULL;
  129. PsFlowObjType.NumInstances -= flowCount;
  130. pPI->numFlows = 0;
  131. return FALSE;
  132. }
  133. // initialize the enumeration handle
  134. hEnum = NULL;
  135. // enumerate each flow and remember its name
  136. for (j=0; j<pPI->numFlows; j++)
  137. {
  138. PENUMERATION_BUFFER pEnum;
  139. LPQOS_FRIENDLY_NAME pFriendly;
  140. ULONG TcObjectLength, FriendlyNameFound;
  141. // If this is not the first time but the enumeration handle is NULL, bail with whatever we have so far
  142. if( (j > 0) && (!hEnum))
  143. {
  144. free(pFlowBuf);
  145. PsFlowObjType.NumInstances -= flowCount;
  146. pPI->numFlows = j;
  147. return TRUE;
  148. }
  149. // get the next flow
  150. BytesWritten = FlowBufSize;
  151. flowCount = 1;
  152. status = TcEnumerateFlows(pPI->hIfc, &hEnum, &flowCount, &BytesWritten, pFlowBuf);
  153. while (ERROR_INSUFFICIENT_BUFFER == status)
  154. {
  155. free(pFlowBuf);
  156. FlowBufSize *= 2;
  157. BytesWritten = FlowBufSize;
  158. pFlowBuf = malloc(BytesWritten);
  159. if(!pFlowBuf)
  160. {
  161. Trace0(DBG_ERROR, L"[getFlowInfo]: malloc failed \n");
  162. free(pPI->pFlowInfo);
  163. pPI->pFlowInfo = NULL;
  164. PsFlowObjType.NumInstances -= flowCount;
  165. pPI->numFlows = 0;
  166. return FALSE;
  167. }
  168. status = TcEnumerateFlows(pPI->hIfc, &hEnum, &flowCount, &BytesWritten, pFlowBuf);
  169. }
  170. if ( (NO_ERROR != status)
  171. || (BytesWritten == 0) )
  172. {
  173. if ( status )
  174. Trace1(DBG_ERROR, L"[getFlowInfo]: TcEnumerateFlows failed with 0x%x \n", status);
  175. else if ( BytesWritten == 0 )
  176. Trace0(DBG_ERROR, L"[getFlowInfo]: TcEnumerateFlows returned 0 bytes \n");
  177. free(pFlowBuf);
  178. free(pPI->pFlowInfo);
  179. pPI->pFlowInfo = NULL;
  180. PsFlowObjType.NumInstances -= flowCount;
  181. pPI->numFlows = 0;
  182. return FALSE;
  183. }
  184. // save the flow's name
  185. pEnum = (PENUMERATION_BUFFER)pFlowBuf;
  186. FriendlyNameFound = 0;
  187. pFriendly = (LPQOS_FRIENDLY_NAME)pEnum->pFlow->TcObjects;
  188. TcObjectLength = pEnum->pFlow->TcObjectsLength;
  189. while(0)
  190. {
  191. if(pFriendly->ObjectHdr.ObjectType == QOS_OBJECT_FRIENDLY_NAME)
  192. {
  193. // We found a friendly name. Lets use it.
  194. memcpy(
  195. pPI->pFlowInfo[j].FriendlyName,
  196. pFriendly->FriendlyName,
  197. PS_FRIENDLY_NAME_LENGTH *sizeof(WCHAR) );
  198. pPI->pFlowInfo[j].FriendlyName[PS_FRIENDLY_NAME_LENGTH] = L'\0';
  199. nameSize = (wcslen(pPI->pFlowInfo[j].FriendlyName) + 1) * sizeof(WCHAR);
  200. gTotalFlowNameSize += MULTIPLE_OF_EIGHT(nameSize);
  201. FriendlyNameFound = 1;
  202. break;
  203. }
  204. else {
  205. // Move on to the next QoS object.
  206. TcObjectLength -= pFriendly->ObjectHdr.ObjectLength;
  207. pFriendly = (LPQOS_FRIENDLY_NAME)((PCHAR) pFriendly + pFriendly->ObjectHdr.ObjectLength);
  208. }
  209. }
  210. if(!FriendlyNameFound)
  211. {
  212. //
  213. // If there is no friendly name, the Instance name becomes the friendly name.
  214. //
  215. memcpy(pPI->pFlowInfo[j].FriendlyName,
  216. ((PENUMERATION_BUFFER)pFlowBuf)->FlowName,
  217. PS_FRIENDLY_NAME_LENGTH * sizeof(WCHAR) );
  218. pPI->pFlowInfo[j].FriendlyName[PS_FRIENDLY_NAME_LENGTH] = L'\0';
  219. nameSize = (wcslen(pPI->pFlowInfo[j].FriendlyName) + 1) * sizeof(WCHAR);
  220. gTotalFlowNameSize += MULTIPLE_OF_EIGHT(nameSize);
  221. }
  222. //
  223. // We have to always store the instance name since we call TcQueryFlow with this name.
  224. //
  225. nameSize = (wcslen(((PENUMERATION_BUFFER)pFlowBuf)->FlowName) + 1) * sizeof(WCHAR);
  226. memcpy(pPI->pFlowInfo[j].InstanceName, ((PENUMERATION_BUFFER)pFlowBuf)->FlowName, nameSize);
  227. }
  228. free(pFlowBuf);
  229. }
  230. else
  231. {
  232. pPI->pFlowInfo = NULL;
  233. Trace0(DBG_INFO, L"[getFlowInfo]: No flows to enumerate \n");
  234. }
  235. return TRUE;
  236. }
  237. // getPipeFlowInfo() initializes an array of PIPE_INFO structs to contain
  238. // up-to-date information about the pipes available and the flows installed on them
  239. //
  240. // Parameters: ppPI - pointer to a pointer to an array of PIPE_INFO structs
  241. // Return value: TRUE if all info in *ppPI is valid, FALSE otherwise
  242. BOOL getPipeFlowInfo(OUT PPIPE_INFO *ppPI)
  243. {
  244. ULONG status;
  245. ULONG BytesWritten;
  246. ULONG i,j,k;
  247. PVOID pIfcDescBuf = NULL;
  248. PTC_IFC_DESCRIPTOR currentIfc;
  249. PPIPE_INFO pPI = NULL;
  250. HANDLE hEnum;
  251. PVOID pFlowBuf;
  252. static ULONG FlowBufSize=1024;
  253. ULONG flowCount;
  254. ULONG nameSize;
  255. ULONG size;
  256. PPERF_COUNTER_DEFINITION pCntDef;
  257. PsPipeObjType.NumInstances=0;
  258. PsFlowObjType.NumInstances = 0;
  259. pIfcDescBuf = (PVOID)malloc(giIfcBufSize);
  260. if (NULL == pIfcDescBuf)
  261. {
  262. Trace0(DBG_ERROR, L"[getPipeFlowInfo]: Malloc failed \n");
  263. return FALSE;
  264. }
  265. BytesWritten = giIfcBufSize;
  266. status = TcEnumerateInterfaces(ghTciClient, &BytesWritten, pIfcDescBuf);
  267. while (ERROR_INSUFFICIENT_BUFFER==status)
  268. {
  269. free(pIfcDescBuf);
  270. giIfcBufSize *= 2;
  271. pIfcDescBuf = (PTC_IFC_DESCRIPTOR)malloc(giIfcBufSize);
  272. if (NULL == pIfcDescBuf)
  273. {
  274. Trace0(DBG_ERROR, L"[getPipeFlowInfo]: Malloc failed \n");
  275. return FALSE;
  276. }
  277. BytesWritten = giIfcBufSize;
  278. status = TcEnumerateInterfaces(ghTciClient, &BytesWritten, pIfcDescBuf);
  279. }
  280. if (NO_ERROR!=status)
  281. {
  282. // If we're not going to be able to enumerate the interfaces, we have no alternatives
  283. Trace1(DBG_ERROR, L"[getPipeFlowInfo]: TcEnumerateInterfaces failed with 0x%x\n", status);
  284. free(pIfcDescBuf);
  285. return FALSE;
  286. }
  287. // Figure out the number of interfaces
  288. for (i=0; i<BytesWritten; i+=((PTC_IFC_DESCRIPTOR)((BYTE *)pIfcDescBuf+i))->Length)
  289. {
  290. PsPipeObjType.NumInstances++;
  291. }
  292. // Open each interface and remember the handle to it
  293. if (0 != PsPipeObjType.NumInstances) {
  294. // Allocate space for our structs
  295. *ppPI=(PPIPE_INFO)malloc(PsPipeObjType.NumInstances * sizeof(PIPE_INFO) );
  296. if (NULL == *ppPI)
  297. {
  298. Trace0(DBG_ERROR, L"[getPipeFlowInfo]: Malloc failed \n");
  299. free(pIfcDescBuf);
  300. return FALSE;
  301. }
  302. else
  303. {
  304. memset(*ppPI, 0, sizeof(PIPE_INFO) * PsPipeObjType.NumInstances);
  305. }
  306. pPI = *ppPI; // less typing, cleaner source code
  307. gTotalIfcNameSize = 0;
  308. gTotalFlowNameSize = 0;
  309. currentIfc = pIfcDescBuf;
  310. // Initialize struct information for each interface
  311. for (i=0; i<(unsigned)PsPipeObjType.NumInstances; i++)
  312. {
  313. // remember the inteface's name
  314. nameSize = (wcslen(currentIfc->pInterfaceName) + 1) * sizeof(WCHAR);
  315. pPI[i].IfcName = malloc(nameSize);
  316. if (NULL == pPI[i].IfcName)
  317. {
  318. Trace0(DBG_ERROR, L"[getPipeFlowInfo]: Malloc failed \n");
  319. goto Error;
  320. }
  321. wcscpy(pPI[i].IfcName, currentIfc->pInterfaceName);
  322. //
  323. // add this name size to gTotalIfcNameSize.
  324. //
  325. gTotalIfcNameSize += MULTIPLE_OF_EIGHT(nameSize);
  326. //
  327. // open the interface
  328. //
  329. status = TcOpenInterface(
  330. pPI[i].IfcName,
  331. ghTciClient,
  332. &pPI[i],
  333. &pPI[i].hIfc);
  334. if (status != NO_ERROR)
  335. {
  336. Trace1(DBG_ERROR, L"[getPipeFlowInfo]: TcOpenInterface failed with 0x%x\n", status);
  337. goto Error;
  338. }
  339. //
  340. // Enumerate the flows on the interface
  341. // find out how many flows to expect
  342. //
  343. pPI[i].numFlows = 0;
  344. pPI[i].pFlowInfo = 0;
  345. status = TcQueryInterface(pPI[i].hIfc,
  346. (LPGUID)&GUID_QOS_FLOW_COUNT,
  347. TRUE,
  348. &BytesWritten,
  349. &flowCount);
  350. if (NO_ERROR != status)
  351. {
  352. Trace1( DBG_ERROR,
  353. L"[getPipeFlowInfo]: TcQueryInterface failed with 0x%x, ignoring this error\n",
  354. status);
  355. }
  356. else
  357. {
  358. getFlowInfo(&pPI[i], flowCount);
  359. }
  360. // move to the next interface
  361. currentIfc = (PTC_IFC_DESCRIPTOR)((PBYTE)currentIfc + currentIfc->Length);
  362. }
  363. }
  364. // determine what components will be contributing stats, if there any stats to get
  365. if (PsPipeObjType.NumInstances > 0) {
  366. //
  367. // compute the counter definition lengths. Each set of counters is preceeded by a PERF_OBJECT_TYPE, followed
  368. // by 'n' PERF_COUNTER_DEFINITIONS. All these are aligned on 8 byte boundaries, so we don't have to do any
  369. // fancy aligining.
  370. //
  371. PsPipeObjType.DefinitionLength = sizeof(PERF_OBJECT_TYPE) +
  372. sizeof(PsPipePipeStatDef) +
  373. sizeof(PsPipeConformerStatDef) +
  374. sizeof(PsPipeShaperStatDef) +
  375. sizeof(PsPipeSequencerStatDef);
  376. PsFlowObjType.DefinitionLength = sizeof(PERF_OBJECT_TYPE) +
  377. sizeof(PsFlowFlowStatDef) +
  378. sizeof(PsFlowConformerStatDef) +
  379. sizeof(PsFlowShaperStatDef) +
  380. sizeof(PsFlowSequencerStatDef);
  381. // compute the sizes of the stats buffers.
  382. gPipeStatLen = FIELD_OFFSET(PS_COMPONENT_STATS, Stats) + // initial offset
  383. sizeof(PS_ADAPTER_STATS) + // every interface has adapter stats
  384. FIELD_OFFSET(PS_COMPONENT_STATS, Stats) +
  385. sizeof(PS_CONFORMER_STATS) +
  386. FIELD_OFFSET(PS_COMPONENT_STATS, Stats) +
  387. sizeof(PS_SHAPER_STATS) +
  388. FIELD_OFFSET(PS_COMPONENT_STATS, Stats) +
  389. sizeof(PS_DRRSEQ_STATS);
  390. gFlowStatLen = FIELD_OFFSET(PS_COMPONENT_STATS, Stats) + // initial offset
  391. sizeof(PS_FLOW_STATS) + // the flow's stats
  392. FIELD_OFFSET(PS_COMPONENT_STATS, Stats) +
  393. sizeof(PS_CONFORMER_STATS) +
  394. FIELD_OFFSET(PS_COMPONENT_STATS, Stats) +
  395. sizeof(PS_SHAPER_STATS) +
  396. FIELD_OFFSET(PS_COMPONENT_STATS, Stats) +
  397. sizeof(PS_DRRSEQ_STATS);
  398. // Align these to 8 byte boundaries.
  399. gPipeStatLen = MULTIPLE_OF_EIGHT(gPipeStatLen);
  400. gFlowStatLen = MULTIPLE_OF_EIGHT(gFlowStatLen);
  401. // update the number of counters to be reported for each object type
  402. PsPipeObjType.NumCounters = PIPE_PIPE_NUM_STATS + PIPE_CONFORMER_NUM_STATS +
  403. PIPE_SHAPER_NUM_STATS + PIPE_SEQUENCER_NUM_STATS;
  404. PsFlowObjType.NumCounters = FLOW_FLOW_NUM_STATS + FLOW_CONFORMER_NUM_STATS +
  405. FLOW_SHAPER_NUM_STATS + FLOW_SEQUENCER_NUM_STATS;
  406. }
  407. // free up resources
  408. free(pIfcDescBuf);
  409. // Everything worked so return that we're happy
  410. return TRUE;
  411. Error:
  412. closePipeFlowInfo(ppPI);
  413. return FALSE;
  414. }
  415. // closePipeFlowInfo() is the counterpart to getPipeFlowInfo()
  416. // It closes all open interfaces and flows, as well as freeing memory
  417. //
  418. // Parameters: ppPI - pointer to a pointer to an array of valid PIPE_INFO structs
  419. // Return value: None
  420. void closePipeFlowInfo(PPIPE_INFO *ppPI)
  421. {
  422. ULONG i;
  423. PPIPE_INFO pPI=*ppPI; // makes for less typing and cleaner code
  424. ULONG BytesWritten, flowCount;
  425. // If the PipeInfo is null, don't free it.
  426. if( !pPI )
  427. return;
  428. BytesWritten = sizeof(flowCount);
  429. // free up resources associated with each interface, then close the interface
  430. for (i=0; i<(unsigned)PsPipeObjType.NumInstances; i++)
  431. {
  432. if(pPI[i].IfcName)
  433. {
  434. free(pPI[i].IfcName);
  435. }
  436. if(pPI[i].pFlowInfo)
  437. {
  438. free(pPI[i].pFlowInfo);
  439. }
  440. // Deregister for flow count notifications.
  441. TcQueryInterface(pPI[i].hIfc,
  442. (LPGUID)&GUID_QOS_FLOW_COUNT,
  443. FALSE,
  444. &BytesWritten,
  445. &flowCount);
  446. TcCloseInterface(pPI[i].hIfc);
  447. }
  448. // now free up the whole buffer
  449. free(*ppPI);
  450. // If it is freed, set it to null
  451. *ppPI = NULL;
  452. }
  453. // This func recieves notifcations from traffic.dll and makes the appropriate
  454. // updates to internal structures
  455. void tciNotifyHandler(IN HANDLE ClRegCtx,
  456. IN HANDLE ClIfcCtx,
  457. IN ULONG Event,
  458. IN HANDLE SubCode,
  459. IN ULONG BufSize,
  460. IN PVOID Buffer)
  461. {
  462. switch (Event)
  463. {
  464. case TC_NOTIFY_IFC_UP:
  465. case TC_NOTIFY_IFC_CLOSE:
  466. case TC_NOTIFY_IFC_CHANGE:
  467. // we'll need sync'ed access
  468. EnterCriticalSection(&ghPipeFlowCriticalSection);
  469. if (dwOpenCount) {
  470. // now reinit the data struct
  471. closePipeFlowInfo(&gpPI);
  472. getPipeFlowInfo(&gpPI);
  473. }
  474. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  475. break;
  476. case TC_NOTIFY_PARAM_CHANGED:
  477. // A flow has been closed by the TC interface
  478. // for example: after a remote call close, or the whole interface
  479. // is going down
  480. //
  481. // we'll need sync'ed access
  482. EnterCriticalSection(&ghPipeFlowCriticalSection);
  483. if (dwOpenCount) {
  484. if(!memcmp((LPGUID) SubCode, &GUID_QOS_FLOW_COUNT, sizeof(GUID))) {
  485. PULONG FlowCount = (PULONG) Buffer;
  486. getFlowInfo(ClIfcCtx, *FlowCount);
  487. }
  488. }
  489. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  490. break;
  491. default:
  492. break;
  493. }
  494. }
  495. DWORD APIENTRY OpenPschedPerformanceData(LPWSTR lpDeviceNames)
  496. /*++
  497. Routine Description:
  498. This routine will open and map the memory used by the PSched driver to
  499. pass performance data in. This routine also initializes the data
  500. structures used to pass data back to the registry
  501. Arguments:
  502. Pointer to object ID of each device to be opened (PSched)
  503. Return Value:
  504. None.
  505. --*/
  506. {
  507. LONG status;
  508. HKEY hPerfKey;
  509. DWORD size;
  510. DWORD type;
  511. DWORD dwFirstCounter;
  512. DWORD dwFirstHelp;
  513. TCI_CLIENT_FUNC_LIST tciCallbFuncList = {tciNotifyHandler, NULL, NULL, NULL};
  514. // Since SCREG is multi-threaded and will call this routine in
  515. // order to service remote performance queries, this library
  516. // must keep track of how many times it has been opened (i.e.
  517. // how many threads have accessed it). the registry routines will
  518. // limit access to the initialization routine to only one thread
  519. // at a time so synchronization (i.e. reentrancy) should not be
  520. // a problem
  521. if (InterlockedIncrement(&dwOpenCount) == 1)
  522. {
  523. #if DBG
  524. gTraceID = TraceRegister(L"PschdPrf");
  525. #endif
  526. // get counter and help index base values
  527. // update static data structures by adding base to
  528. // offset value in structure.
  529. status = RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
  530. PSCHED_PERF_KEY,
  531. 0L,
  532. KEY_READ,
  533. &hPerfKey);
  534. if (status != ERROR_SUCCESS) {
  535. // this is fatal, if we can't get the base values of the
  536. // counter or help names, then the names won't be available
  537. // to the requesting application, so there's not much
  538. // point in continuing.
  539. goto OpenExitPoint;
  540. }
  541. size = sizeof (DWORD);
  542. status = RegQueryValueEx( hPerfKey,
  543. TEXT("First Counter"),
  544. 0L,
  545. &type,
  546. (LPBYTE)&dwFirstCounter,
  547. &size);
  548. if (status != ERROR_SUCCESS) {
  549. // this is fatal, if we can't get the base values of the
  550. // counter or help names, then the names won't be available
  551. // to the requesting application, so there's not much
  552. // point in continuing.
  553. RegCloseKey(hPerfKey);
  554. goto OpenExitPoint;
  555. }
  556. size = sizeof (DWORD);
  557. status = RegQueryValueEx( hPerfKey,
  558. TEXT("First Help"),
  559. 0L,
  560. &type,
  561. (LPBYTE)&dwFirstHelp,
  562. &size);
  563. RegCloseKey(hPerfKey);
  564. if (status != ERROR_SUCCESS) {
  565. // this is fatal, if we can't get the base values of the
  566. // counter or help names, then the names won't be available
  567. // to the requesting application, so there's not much
  568. // point in continuing.
  569. goto OpenExitPoint;
  570. }
  571. // Convert Pipe object and counters from offset to absolute index
  572. PsPipeObjType.ObjectNameTitleIndex += dwFirstCounter;
  573. PsPipeObjType.ObjectHelpTitleIndex += dwFirstHelp;
  574. convertIndices((BYTE *)&PsPipePipeStatDef,
  575. sizeof PsPipePipeStatDef/sizeof(PERF_COUNTER_DEFINITION),
  576. dwFirstCounter,
  577. dwFirstHelp);
  578. convertIndices((BYTE *)&PsPipeConformerStatDef,
  579. sizeof PsPipeConformerStatDef/sizeof(PERF_COUNTER_DEFINITION),
  580. dwFirstCounter,
  581. dwFirstHelp);
  582. convertIndices((BYTE *)&PsPipeShaperStatDef,
  583. sizeof PsPipeShaperStatDef/sizeof(PERF_COUNTER_DEFINITION),
  584. dwFirstCounter,
  585. dwFirstHelp);
  586. convertIndices((BYTE *)&PsPipeSequencerStatDef,
  587. sizeof PsPipeSequencerStatDef/sizeof(PERF_COUNTER_DEFINITION),
  588. dwFirstCounter,
  589. dwFirstHelp);
  590. // Convert Flow object and counters from offset to absolute index
  591. PsFlowObjType.ObjectNameTitleIndex += dwFirstCounter;
  592. PsFlowObjType.ObjectHelpTitleIndex += dwFirstHelp;
  593. convertIndices((BYTE *)&PsFlowFlowStatDef,
  594. sizeof PsFlowFlowStatDef/sizeof(PERF_COUNTER_DEFINITION),
  595. dwFirstCounter,
  596. dwFirstHelp);
  597. convertIndices((BYTE *)&PsFlowConformerStatDef,
  598. sizeof PsFlowConformerStatDef/sizeof(PERF_COUNTER_DEFINITION),
  599. dwFirstCounter,
  600. dwFirstHelp);
  601. convertIndices((BYTE *)&PsFlowShaperStatDef,
  602. sizeof PsFlowShaperStatDef/sizeof(PERF_COUNTER_DEFINITION),
  603. dwFirstCounter,
  604. dwFirstHelp);
  605. convertIndices((BYTE *)&PsFlowSequencerStatDef,
  606. sizeof PsFlowSequencerStatDef/sizeof(PERF_COUNTER_DEFINITION),
  607. dwFirstCounter,
  608. dwFirstHelp);
  609. // initialize with traffic.dll
  610. if (TcRegisterClient(CURRENT_TCI_VERSION, ghClRegCtx, &tciCallbFuncList, &ghTciClient)!=NO_ERROR)
  611. {
  612. // if we can't connect with traffic.dll we are a non admin thread in OpenPschedPerformanceData.
  613. // We cannot fail because of this, because an admin thread might call us at our collect routine.
  614. // We'll try to register as the Traffic Control client in the Collect Thread.
  615. //
  616. ghTciClient = 0;
  617. }
  618. else
  619. {
  620. // we'll need sync'ed access
  621. EnterCriticalSection(&ghPipeFlowCriticalSection);
  622. // get all necessary info about pipes and flows currently installed
  623. if (getPipeFlowInfo(&gpPI)!=TRUE) {
  624. // we didn't get all the info we wanted, so we're
  625. // going to have to try again, including re-registering
  626. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  627. TcDeregisterClient(ghTciClient);
  628. goto OpenExitPoint;
  629. }
  630. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  631. }
  632. // if we got to here, then we're all ready
  633. bInitOK = TRUE;
  634. }
  635. Trace0(DBG_INFO, L"[OpenPschedPerformanceData]: success \n");
  636. status = ERROR_SUCCESS; // for successful exit
  637. return status;
  638. OpenExitPoint:
  639. Trace1(DBG_ERROR, L"[OpenPschedPerformanceData]: Failed with 0x%x \n", status);
  640. return status;
  641. }
  642. DWORD APIENTRY CollectPschedPerformanceData(
  643. IN LPWSTR lpValueName,
  644. IN OUT LPVOID *lppData,
  645. IN OUT LPDWORD lpcbTotalBytes,
  646. IN OUT LPDWORD lpNumObjectTypes
  647. )
  648. /*++
  649. Routine Description:
  650. This routine will return the data for the PSched counters.
  651. The data is returned in the foll. format. The steps below are carried out for Pipe/Flows.
  652. 1. First, we write the PERF_OBJECT_TYPE for the Pipe (and/or) the Flow Counters.
  653. 2. for(i=0; i<NumCounters; i++)
  654. Write PERF_COUNTER_DEFINITION for counter i;
  655. 3. for(i=0; i<NumInstances; i++)
  656. Write PERF_INSTANCE_DEFINITION for instance i;
  657. Write Instance Name
  658. Write PERF_COUNTER_BLOCK
  659. Write the Stats;
  660. Arguments:
  661. IN LPWSTR lpValueName
  662. pointer to a wide character string passed by registry.
  663. IN OUT LPVOID *lppData
  664. IN: pointer to the address of the buffer to receive the completed
  665. PerfDataBlock and subordinate structures. This routine will
  666. append its data to the buffer starting at the point referenced
  667. by *lppData.
  668. OUT: points to the first byte after the data structure added by this
  669. routine. This routine updated the value at lppdata after appending
  670. its data.
  671. IN OUT LPDWORD lpcbTotalBytes
  672. IN: the address of the DWORD that tells the size in bytes of the
  673. buffer referenced by the lppData argument
  674. OUT: the number of bytes added by this routine is written to the
  675. DWORD pointed to by this argument
  676. IN OUT LPDWORD NumObjectTypes
  677. IN: the address of the DWORD to receive the number of objects added
  678. by this routine
  679. OUT: the number of objects added by this routine is written to the
  680. DWORD pointed to by this argument
  681. Return Value:
  682. ERROR_MORE_DATA if buffer passed is too small to hold data
  683. any error conditions encountered could be reported to the event log if
  684. event logging support were added.
  685. ERROR_SUCCESS if success or any other error. Errors, however could
  686. also reported to the event log.
  687. --*/
  688. {
  689. ULONG i,j;
  690. ULONG SpaceNeeded;
  691. PDWORD pdwBuf;
  692. DWORD dwQueryType;
  693. DWORD status;
  694. DWORD bufSize;
  695. PS_PERF_COUNTER_BLOCK pcb;
  696. PERF_INSTANCE_DEFINITION pid={0, 0, 0, PERF_NO_UNIQUE_ID, sizeof(pid), 0};
  697. ULONG size;
  698. PVOID pStatsBuf;
  699. // save the size of the buffer
  700. bufSize = *lpcbTotalBytes;
  701. // default to returning nothing
  702. *lpcbTotalBytes = (DWORD) 0;
  703. *lpNumObjectTypes = (DWORD) 0;
  704. // Before doing anything else, see if Open went OK
  705. if (!bInitOK)
  706. {
  707. // unable to continue because open failed.
  708. Trace0(DBG_ERROR, L"[CollectPschedPerformanceData]: open failed \n");
  709. return ERROR_SUCCESS; // yes, this is a successful exit
  710. }
  711. // See if this is a foreign (i.e. non-NT) computer data request
  712. dwQueryType = GetQueryType (lpValueName);
  713. if (dwQueryType == QUERY_FOREIGN)
  714. {
  715. // this routine does not service requests for data from
  716. // Non-NT computers
  717. Trace0(DBG_ERROR, L"[CollectPschedPerformanceData]: received QUERY_FOREIGN \n");
  718. return ERROR_SUCCESS;
  719. }
  720. // Is PerfMon requesting PSched items?
  721. if (dwQueryType == QUERY_ITEMS)
  722. {
  723. if ( !(IsNumberInUnicodeList(PsPipeObjType.ObjectNameTitleIndex,
  724. lpValueName))
  725. && !(IsNumberInUnicodeList(PsFlowObjType.ObjectNameTitleIndex,
  726. lpValueName)) ) {
  727. // request received for data object not provided by this routine
  728. Trace0(DBG_INFO, L"[CollectPschedPerformanceData]: Not for psched \n");
  729. return ERROR_SUCCESS;
  730. }
  731. }
  732. // from this point on, we need sync'ed access
  733. EnterCriticalSection(&ghPipeFlowCriticalSection);
  734. // we might need to rereigster as a Traffic control client.
  735. if(ghTciClient == NULL)
  736. {
  737. TCI_CLIENT_FUNC_LIST tciCallbFuncList = {tciNotifyHandler, NULL, NULL, NULL};
  738. status = TcRegisterClient(CURRENT_TCI_VERSION, ghClRegCtx, &tciCallbFuncList, &ghTciClient);
  739. if(status != NO_ERROR)
  740. {
  741. Trace1(DBG_ERROR, L"[CollectPschedPerformanceData]: Could not register as Traffic Client. Error 0x%x \n",
  742. status);
  743. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  744. return ERROR_SUCCESS;
  745. }
  746. // get all necessary info about pipes and flows currently installed
  747. if (getPipeFlowInfo(&gpPI)!=TRUE) {
  748. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  749. Trace0(DBG_ERROR, L"[CollectPschedPerformanceData]: getPipeFlowInfo failed \n");
  750. return ERROR_SUCCESS;
  751. }
  752. }
  753. //
  754. // We have to write the PERF_OBJECT_TYPE unconditionally even if there are no instances. So, we proceed
  755. // to compute the space needed even when there are no flows.
  756. //
  757. // Calculate the space needed for the pipe stats.
  758. SpaceNeeded = PsPipeObjType.DefinitionLength + gTotalIfcNameSize + (PsPipeObjType.NumInstances *
  759. (sizeof pid + sizeof pcb + gPipeStatLen) );
  760. SpaceNeeded += PsFlowObjType.DefinitionLength + gTotalFlowNameSize + (PsFlowObjType.NumInstances *
  761. (sizeof pid + sizeof pcb + gFlowStatLen) );
  762. if (bufSize < SpaceNeeded)
  763. {
  764. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  765. Trace0(DBG_ERROR, L"[CollectPschedPerformanceData]: Need More data\n");
  766. return ERROR_MORE_DATA;
  767. }
  768. pdwBuf = (PDWORD)*lppData;
  769. // Record the total length of the pipe stats
  770. PsPipeObjType.TotalByteLength =
  771. PsPipeObjType.DefinitionLength + gTotalIfcNameSize + (PsPipeObjType.NumInstances *
  772. (sizeof pid + sizeof pcb + gPipeStatLen) );
  773. // copy object and counter definitions, increment count of object types
  774. WRITEBUF(&PsPipeObjType,sizeof PsPipeObjType);
  775. WRITEBUF(&PsPipePipeStatDef, sizeof PsPipePipeStatDef);
  776. WRITEBUF(&PsPipeConformerStatDef, sizeof PsPipeConformerStatDef);
  777. WRITEBUF(&PsPipeShaperStatDef, sizeof PsPipeShaperStatDef);
  778. WRITEBUF(&PsPipeSequencerStatDef, sizeof PsPipeSequencerStatDef);
  779. (*lpNumObjectTypes)++;
  780. //
  781. // for each pipe, write out its instance definition, counter block, and actual stats
  782. //
  783. if(ghTciClient)
  784. {
  785. for (i=0; i<(unsigned)PsPipeObjType.NumInstances; i++) {
  786. PWCHAR InstanceName;
  787. //
  788. // Write out the PERF_INSTANCE_DEFINITION, which identifies an interface and gives it a name.
  789. //
  790. pid.NameLength = (wcslen(gpPI[i].IfcName)+1) * sizeof(WCHAR);
  791. pid.ByteLength = sizeof pid + MULTIPLE_OF_EIGHT(pid.NameLength);
  792. WRITEBUF(&pid, sizeof pid);
  793. InstanceName = (PWCHAR) pdwBuf;
  794. memcpy(pdwBuf, gpPI[i].IfcName, pid.NameLength);
  795. pdwBuf = (PULONG)((PUCHAR)pdwBuf + MULTIPLE_OF_EIGHT(pid.NameLength));
  796. CorrectInstanceName(InstanceName);
  797. //
  798. // get pipe stats and copy them to the buffer
  799. //
  800. size = gPipeStatLen;
  801. pStatsBuf = malloc(size);
  802. if (NULL == pStatsBuf)
  803. {
  804. *lpcbTotalBytes = (DWORD) 0;
  805. *lpNumObjectTypes = (DWORD) 0;
  806. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  807. Trace0(DBG_ERROR, L"[CollectPschedPerformanceData]: Insufficient memory\n");
  808. return ERROR_SUCCESS;
  809. }
  810. status = TcQueryInterface(gpPI[i].hIfc,
  811. (LPGUID)&GUID_QOS_STATISTICS_BUFFER,
  812. FALSE,
  813. &size,
  814. pStatsBuf);
  815. if (ERROR_INSUFFICIENT_BUFFER==status)
  816. {
  817. free(pStatsBuf);
  818. size = gPipeStatLen = MULTIPLE_OF_EIGHT(size);
  819. pStatsBuf = (PPS_COMPONENT_STATS)malloc(gPipeStatLen);
  820. if (NULL == pStatsBuf)
  821. {
  822. *lpcbTotalBytes = (DWORD) 0;
  823. *lpNumObjectTypes = (DWORD) 0;
  824. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  825. Trace0(DBG_ERROR, L"[CollectPschedPerformanceData]: Insufficient memory\n");
  826. return ERROR_SUCCESS;
  827. }
  828. status = TcQueryInterface(gpPI[i].hIfc,
  829. (LPGUID)&GUID_QOS_STATISTICS_BUFFER,
  830. FALSE,
  831. &size,
  832. pStatsBuf);
  833. }
  834. if (NO_ERROR != status) {
  835. Trace1(DBG_ERROR, L"[CollectPschedPerformanceData]: TcQueryInterface failed with 0x%x \n", status);
  836. memset ( pStatsBuf, 0, gPipeStatLen );
  837. }
  838. //
  839. // Now, write the PERF_COUNTER_BLOCK
  840. //
  841. pcb.pcb.ByteLength = gPipeStatLen + sizeof(pcb);
  842. WRITEBUF(&pcb,sizeof pcb);
  843. //
  844. // Write out all the counters.
  845. //
  846. WRITEBUF(pStatsBuf,gPipeStatLen);
  847. free(pStatsBuf);
  848. }
  849. }
  850. // set the pointer to where the pipe object type said the next object would start
  851. pdwBuf = (PDWORD)( ((BYTE *)*lppData) + PsPipeObjType.TotalByteLength );
  852. // first copy flow data def (object_type struct).
  853. // Record the total length of the flow stats
  854. PsFlowObjType.TotalByteLength =
  855. PsFlowObjType.DefinitionLength + gTotalFlowNameSize + (PsFlowObjType.NumInstances *
  856. (sizeof pid + sizeof pcb + gFlowStatLen) );
  857. // copy object and counter definitions, increment count of object types
  858. WRITEBUF(&PsFlowObjType,sizeof PsFlowObjType);
  859. WRITEBUF(&PsFlowFlowStatDef, sizeof PsFlowFlowStatDef);
  860. WRITEBUF(&PsFlowConformerStatDef, sizeof PsFlowConformerStatDef);
  861. WRITEBUF(&PsFlowShaperStatDef, sizeof PsFlowShaperStatDef);
  862. WRITEBUF(&PsFlowSequencerStatDef, sizeof PsFlowSequencerStatDef);
  863. (*lpNumObjectTypes)++;
  864. // if there are any flows, process them
  865. if (PsFlowObjType.NumInstances && ghTciClient) {
  866. // initialize parent structure
  867. pid.ParentObjectTitleIndex = PsPipeObjType.ObjectNameTitleIndex;
  868. // loop over each interface checking for flow installed on them
  869. for (i=0; i<(unsigned)PsPipeObjType.NumInstances; i++) {
  870. // keep parent instance up to date
  871. pid.ParentObjectInstance = i;
  872. for (j=0; j<gpPI[i].numFlows; j++) {
  873. PWCHAR InstanceName;
  874. // copy flow instance definition and name
  875. pid.NameLength = (wcslen(gpPI[i].pFlowInfo[j].FriendlyName)+1) * sizeof(WCHAR);
  876. pid.ByteLength = sizeof(pid) + MULTIPLE_OF_EIGHT(pid.NameLength);
  877. WRITEBUF(&pid,sizeof pid);
  878. InstanceName = (PWCHAR) pdwBuf;
  879. memcpy(pdwBuf, gpPI[i].pFlowInfo[j].FriendlyName, pid.NameLength);
  880. pdwBuf = (PULONG)((PUCHAR)pdwBuf + MULTIPLE_OF_EIGHT(pid.NameLength));
  881. CorrectInstanceName(InstanceName);
  882. // get flow stats and copy them to the buffer
  883. size = gFlowStatLen;
  884. pStatsBuf = malloc(size);
  885. if (NULL == pStatsBuf) {
  886. *lpcbTotalBytes = (DWORD) 0;
  887. *lpNumObjectTypes = (DWORD) 0;
  888. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  889. Trace0(DBG_ERROR, L"[CollectPschedPerformanceData]: Insufficient memory\n");
  890. return ERROR_SUCCESS;
  891. }
  892. status = TcQueryFlow(gpPI[i].pFlowInfo[j].InstanceName, (LPGUID)&GUID_QOS_STATISTICS_BUFFER,
  893. &size, pStatsBuf);
  894. if (ERROR_INSUFFICIENT_BUFFER==status) {
  895. free(pStatsBuf);
  896. size = gFlowStatLen = MULTIPLE_OF_EIGHT(size);
  897. pStatsBuf = (PPS_COMPONENT_STATS)malloc(gFlowStatLen);
  898. if (NULL == pStatsBuf)
  899. {
  900. *lpcbTotalBytes = (DWORD) 0;
  901. *lpNumObjectTypes = (DWORD) 0;
  902. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  903. Trace0(DBG_ERROR, L"[CollectPschedPerformanceData]: Insufficient memory\n");
  904. return ERROR_SUCCESS;
  905. }
  906. status = TcQueryFlow(gpPI[i].pFlowInfo[j].InstanceName, (LPGUID)&GUID_QOS_STATISTICS_BUFFER,
  907. &size, pStatsBuf);
  908. }
  909. if (NO_ERROR != status) {
  910. free(pStatsBuf);
  911. *lpcbTotalBytes = (DWORD) 0;
  912. *lpNumObjectTypes = (DWORD) 0;
  913. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  914. Trace1(DBG_ERROR,
  915. L"[CollectPschedPerformanceData]: TcQueryFlow failed with status 0x%x \n", status);
  916. return ERROR_SUCCESS;
  917. }
  918. // copy flow instance counter_block
  919. pcb.pcb.ByteLength = gFlowStatLen + sizeof(pcb);
  920. WRITEBUF(&pcb,sizeof pcb);
  921. WRITEBUF(pStatsBuf, gFlowStatLen);
  922. free(pStatsBuf);
  923. }
  924. }
  925. }
  926. // update the data pointer
  927. *lpcbTotalBytes = PsPipeObjType.TotalByteLength + PsFlowObjType.TotalByteLength;
  928. *lppData = ((PBYTE)*lppData) + *lpcbTotalBytes;
  929. // free up the sync lock
  930. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  931. Trace0(DBG_INFO, L"[CollectPschedPerformanceData]: Succcess \n");
  932. return ERROR_SUCCESS;
  933. }
  934. /*
  935. Routine Description:
  936. This routine closes the open handles to PSched device performance counters
  937. Arguments:
  938. None.
  939. Return Value:
  940. ERROR_SUCCESS
  941. */
  942. DWORD APIENTRY ClosePschedPerformanceData()
  943. {
  944. EnterCriticalSection(&ghPipeFlowCriticalSection);
  945. if(InterlockedDecrement(&dwOpenCount) == 0)
  946. {
  947. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  948. // Clean up with traffic.dll and free up resources
  949. closePipeFlowInfo(&gpPI);
  950. // then deregister
  951. if(ghTciClient)
  952. TcDeregisterClient(ghTciClient);
  953. // get rid of the mutex
  954. #if DBG
  955. TraceDeregister(gTraceID);
  956. #endif
  957. } else {
  958. LeaveCriticalSection(&ghPipeFlowCriticalSection);
  959. }
  960. return ERROR_SUCCESS;
  961. }
  962. //////////////////////////////////////////////////////////////////////
  963. //
  964. // PERF UTILITY STUFF BELOW!
  965. //
  966. //////////////////////////////////////////////////////////////////////
  967. BOOL WINAPI DllEntryPoint(
  968. HANDLE hDLL,
  969. DWORD dwReason,
  970. LPVOID lpReserved)
  971. {
  972. switch (dwReason)
  973. {
  974. case DLL_PROCESS_ATTACH:
  975. ghInst = hDLL;
  976. // initialize the mutex
  977. __try {
  978. InitializeCriticalSection(&ghPipeFlowCriticalSection);
  979. } __except (EXCEPTION_EXECUTE_HANDLER) {
  980. return FALSE;
  981. }
  982. break;
  983. case DLL_PROCESS_DETACH:
  984. DeleteCriticalSection(&ghPipeFlowCriticalSection);
  985. break;
  986. case DLL_THREAD_ATTACH:
  987. break;
  988. case DLL_THREAD_DETACH:
  989. break;
  990. } // switch
  991. return TRUE;
  992. }