2555 lines
66 KiB
C
2555 lines
66 KiB
C
/*++
|
|
|
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
process.c
|
|
|
|
Abstract:
|
|
|
|
Manipulation routines for cpdata structures.
|
|
|
|
Author:
|
|
|
|
Melur Raghuraman (mraghu) 03-Oct-1997
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "cpdata.h"
|
|
#include "tracectr.h"
|
|
#include "item.h"
|
|
|
|
extern PTRACE_CONTEXT_BLOCK TraceContext;
|
|
extern PWCHAR CpdiGuidToString(PWCHAR s, ULONG len, LPGUID piid);
|
|
extern LIST_ENTRY g_ValueMapTable;
|
|
|
|
VOID
|
|
Aggregate(
|
|
IN PTHREAD_RECORD pThread
|
|
);
|
|
|
|
ULONG
|
|
CPDAPI
|
|
GetTempName( LPTSTR strFile, size_t cchSize )
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwStatus;
|
|
GUID guid;
|
|
WCHAR strGUID[128];
|
|
DWORD nChar = 0;
|
|
|
|
dwStatus = UuidCreate( &guid );
|
|
if( dwStatus == RPC_S_OK || dwStatus == RPC_S_UUID_LOCAL_ONLY ){
|
|
nChar = StringFromGUID2( (const GUID*)&guid, strGUID, 128 );
|
|
dwStatus = ERROR_SUCCESS;
|
|
}
|
|
|
|
if( 0 == nChar ){
|
|
hr = StringCchPrintf( strGUID, 128, L"{d41c99ea-c303-4d06-b779-f9e8e20acb8f}.%08d", rand() );
|
|
}
|
|
|
|
nChar = GetTempPath( cchSize, strFile );
|
|
if( 0 == nChar ){
|
|
dwStatus = GetLastError();
|
|
}
|
|
|
|
if( ERROR_SUCCESS == dwStatus ){
|
|
hr = StringCchCat( strFile, cchSize, strGUID );
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
__inline
|
|
USHORT
|
|
UrlHashKey(
|
|
PUCHAR UrlStr,
|
|
ULONG StrSize
|
|
)
|
|
{
|
|
USHORT i, l, key = 0;
|
|
i = (USHORT)(StrSize - 1);
|
|
// Use only the last 25 chars
|
|
l = (StrSize > 25) ? (USHORT)(StrSize - 25) : 0;
|
|
|
|
// UrlStr cannot be NULL when this function is called.
|
|
for ( ; i >= l; i--) {
|
|
key = 37 * key + (USHORT)(*(UrlStr + i));
|
|
if (i == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
key = key % (URL_HASH_TABLESIZE);
|
|
|
|
return key;
|
|
}
|
|
|
|
VOID
|
|
InitDiskRecord(
|
|
PTDISK_RECORD pDisk,
|
|
ULONG DiskNumber
|
|
)
|
|
{
|
|
PWCHAR name;
|
|
if (pDisk == NULL){
|
|
return;
|
|
}
|
|
memset(pDisk, 0, sizeof(TDISK_RECORD));
|
|
InitializeListHead(&pDisk->ProcessListHead);
|
|
InitializeListHead(&pDisk->FileListHead);
|
|
pDisk->DiskNumber = DiskNumber;
|
|
|
|
name = (PWCHAR)malloc(16 * sizeof(WCHAR));
|
|
if (name != NULL) {
|
|
StringCbPrintfW(name, 16 * sizeof(WCHAR), L"Disk%d", DiskNumber);
|
|
}
|
|
pDisk->DiskName = name;
|
|
}
|
|
|
|
VOID
|
|
InitFileRecord(
|
|
PFILE_RECORD pFile
|
|
)
|
|
{
|
|
if (pFile == NULL){
|
|
return;
|
|
}
|
|
memset(pFile, 0, sizeof(FILE_RECORD));
|
|
InitializeListHead(&pFile->ProtoProcessListHead);
|
|
}
|
|
|
|
VOID
|
|
InitThreadRecord(
|
|
PTHREAD_RECORD pThread
|
|
)
|
|
{
|
|
if (pThread == NULL)
|
|
return;
|
|
memset(pThread, 0, sizeof(THREAD_RECORD));
|
|
InitializeListHead( &pThread->DiskListHead );
|
|
InitializeListHead( &pThread->TransListHead );
|
|
InitializeListHead( &pThread->HPFReadListHead );
|
|
InitializeListHead( &pThread->HPFWriteListHead );
|
|
}
|
|
|
|
PTRANS_RECORD
|
|
CreateTransRecord()
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PTRANS_RECORD pTrans = NULL;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.FreeTransListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
if (Next != Head) {
|
|
pTrans = CONTAINING_RECORD ( Next, TRANS_RECORD, Entry );
|
|
RemoveEntryList( &pTrans->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
if (pTrans == NULL) {
|
|
pTrans = malloc(sizeof(TRANS_RECORD));
|
|
if (pTrans == NULL) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return NULL;
|
|
}
|
|
}
|
|
memset(pTrans, 0, sizeof(TRANS_RECORD));
|
|
InitializeListHead(&pTrans->SubTransListHead);
|
|
return pTrans;
|
|
}
|
|
|
|
VOID
|
|
InitMofData(
|
|
PMOF_DATA pMofData
|
|
)
|
|
{
|
|
if (pMofData == NULL)
|
|
return;
|
|
memset(pMofData, 0, sizeof(MOF_DATA));
|
|
pMofData->MaxKCpu = -1;
|
|
pMofData->MinKCpu = -1;
|
|
pMofData->MaxUCpu = -1;
|
|
pMofData->MinUCpu = -1;
|
|
}
|
|
|
|
VOID
|
|
InitProcessRecord(
|
|
PPROCESS_RECORD pProcess
|
|
)
|
|
{
|
|
if (pProcess == NULL)
|
|
return;
|
|
memset(pProcess, 0, sizeof(PROCESS_RECORD));
|
|
InitializeListHead( &pProcess->ThreadListHead );
|
|
InitializeListHead( &pProcess->DiskListHead );
|
|
InitializeListHead( &pProcess->FileListHead );
|
|
InitializeListHead( &pProcess->ModuleListHead );
|
|
InitializeListHead( &pProcess->HPFListHead );
|
|
}
|
|
|
|
BOOLEAN AddModuleRecord(PMODULE_RECORD * ppModule,
|
|
ULONG lBaseAddress,
|
|
ULONG lModuleSize,
|
|
WCHAR * strModuleName)
|
|
{
|
|
PMODULE_RECORD pModule;
|
|
|
|
if ( (ppModule == NULL) || (strModuleName == NULL) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
pModule = (PMODULE_RECORD)malloc(sizeof(MODULE_RECORD));
|
|
|
|
if(NULL != pModule){
|
|
memset(pModule, 0, sizeof(MODULE_RECORD));
|
|
|
|
pModule->strModuleName =
|
|
malloc(sizeof(WCHAR) * (lstrlenW(strModuleName) + 1));
|
|
|
|
if (pModule->strModuleName == NULL)
|
|
{
|
|
free(pModule);
|
|
pModule = NULL;
|
|
}
|
|
else
|
|
{
|
|
StringCchCopyW(pModule->strModuleName, (lstrlenW(strModuleName) + 1), strModuleName);
|
|
|
|
pModule->lBaseAddress = lBaseAddress;
|
|
pModule->lModuleSize = lModuleSize;
|
|
}
|
|
}
|
|
|
|
* ppModule = pModule;
|
|
|
|
return (BOOLEAN) (* ppModule != NULL);
|
|
}
|
|
|
|
BOOLEAN AddHPFFileRecord(
|
|
PHPF_FILE_RECORD * ppHPFFileRecord,
|
|
ULONG RecordID,
|
|
ULONG IrpFlags,
|
|
ULONG DiskNumber,
|
|
ULONGLONG ByteOffset,
|
|
ULONG BytesCount,
|
|
PVOID fDO
|
|
)
|
|
{
|
|
PHPF_FILE_RECORD pHPFFileRecord = malloc(sizeof(HPF_FILE_RECORD));
|
|
|
|
if (pHPFFileRecord)
|
|
{
|
|
pHPFFileRecord->RecordID = RecordID;
|
|
pHPFFileRecord->IrpFlags = IrpFlags;
|
|
pHPFFileRecord->DiskNumber = DiskNumber;
|
|
pHPFFileRecord->ByteOffset = ByteOffset;
|
|
pHPFFileRecord->BytesCount = BytesCount;
|
|
pHPFFileRecord->fDO = fDO;
|
|
}
|
|
|
|
* ppHPFFileRecord = pHPFFileRecord;
|
|
return (BOOLEAN) (* ppHPFFileRecord != NULL);
|
|
}
|
|
|
|
BOOLEAN AddHPFRecord(
|
|
PHPF_RECORD * ppHPFRecord,
|
|
ULONG lFaultAddress,
|
|
PVOID fDO,
|
|
LONG ByteCount,
|
|
LONGLONG ByteOffset
|
|
)
|
|
{
|
|
PHPF_RECORD pHPFRecord = malloc(sizeof(HPF_RECORD));
|
|
|
|
if (pHPFRecord)
|
|
{
|
|
pHPFRecord->fDO = fDO;
|
|
pHPFRecord->lFaultAddress = lFaultAddress;
|
|
pHPFRecord->lByteCount = ByteCount;
|
|
pHPFRecord->lByteOffset = ByteOffset;
|
|
InitializeListHead(& pHPFRecord->HPFReadListHead);
|
|
}
|
|
|
|
* ppHPFRecord = pHPFRecord;
|
|
return (BOOLEAN) (* ppHPFRecord != NULL);
|
|
}
|
|
|
|
void DeleteHPFRecord(
|
|
PHPF_RECORD pHPFRecord
|
|
)
|
|
{
|
|
PLIST_ENTRY pHead;
|
|
PLIST_ENTRY pNext;
|
|
PHPF_FILE_RECORD pHPFFileRecord;
|
|
|
|
if (!pHPFRecord)
|
|
return;
|
|
|
|
RemoveEntryList(& pHPFRecord->Entry);
|
|
pHead = & pHPFRecord->HPFReadListHead;
|
|
pNext = pHead->Flink;
|
|
while (pNext != pHead)
|
|
{
|
|
pHPFFileRecord = CONTAINING_RECORD(pNext, HPF_FILE_RECORD, Entry);
|
|
pNext = pNext->Flink;
|
|
RemoveEntryList(& pHPFFileRecord->Entry);
|
|
free(pHPFFileRecord);
|
|
}
|
|
free(pHPFRecord);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
InitWorkloadRecord(
|
|
PWORKLOAD_RECORD pWorkload
|
|
)
|
|
{
|
|
if (pWorkload == NULL)
|
|
return;
|
|
memset(pWorkload, 0, sizeof(WORKLOAD_RECORD));
|
|
InitializeListHead( &pWorkload->DiskListHead );
|
|
}
|
|
|
|
VOID
|
|
DeleteWorkloadRecord(
|
|
PWORKLOAD_RECORD pWorkload
|
|
)
|
|
{
|
|
if (pWorkload == NULL)
|
|
return;
|
|
|
|
}
|
|
|
|
PPROTO_PROCESS_RECORD
|
|
AddProtoProcess(
|
|
PFILE_RECORD pFile,
|
|
PPROCESS_RECORD pProcess
|
|
)
|
|
{
|
|
PPROTO_PROCESS_RECORD pProto;
|
|
|
|
if (pFile == NULL || pProcess == NULL)
|
|
return NULL;
|
|
|
|
pProto = malloc(sizeof(PROTO_PROCESS_RECORD));
|
|
if (pProto == NULL) {
|
|
return NULL;
|
|
}
|
|
memset(pProto, 0, sizeof(PROTO_PROCESS_RECORD));
|
|
|
|
pProto->ProcessRecord = pProcess;
|
|
InsertHeadList( &pFile->ProtoProcessListHead, &pProto->Entry );
|
|
return pProto;
|
|
}
|
|
|
|
PPROTO_PROCESS_RECORD
|
|
FindProtoProcessRecord(
|
|
PFILE_RECORD pFile,
|
|
PPROCESS_RECORD pProcess
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PPROTO_PROCESS_RECORD pProto;
|
|
if (pFile == NULL || pProcess == NULL)
|
|
return NULL;
|
|
|
|
Head = &pFile->ProtoProcessListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pProto = CONTAINING_RECORD(Next, PROTO_PROCESS_RECORD, Entry);
|
|
if (pProcess == pProto->ProcessRecord)
|
|
return pProto;
|
|
Next = Next->Flink;
|
|
}
|
|
return (AddProtoProcess(pFile, pProcess));
|
|
}
|
|
|
|
BOOLEAN
|
|
AddProcess(
|
|
ULONG ProcessId,
|
|
PPROCESS_RECORD *ReturnedProcess
|
|
)
|
|
{
|
|
PPROCESS_RECORD Process;
|
|
PMODULE_RECORD pModule = NULL;
|
|
|
|
Process = malloc(sizeof(PROCESS_RECORD));
|
|
if (Process == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
InitProcessRecord( Process );
|
|
Process->PID = ProcessId;
|
|
if (!AddModuleRecord(& pModule, 0, 0, L"other")) {
|
|
free(Process);
|
|
return FALSE;
|
|
}
|
|
|
|
pModule->pProcess = Process;
|
|
|
|
EnterTracelibCritSection();
|
|
InsertHeadList( &CurrentSystem.ProcessListHead, &Process->Entry );
|
|
InsertHeadList(& Process->ModuleListHead, & pModule->Entry);
|
|
LeaveTracelibCritSection();
|
|
*ReturnedProcess = Process;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
DeleteProcess(
|
|
PPROCESS_RECORD Process
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PTHREAD_RECORD Thread;
|
|
PTDISK_RECORD Disk;
|
|
PFILE_RECORD pFile;
|
|
PMODULE_RECORD pModule;
|
|
PHPF_RECORD pHPFRecord;
|
|
|
|
if (Process == NULL)
|
|
return FALSE;
|
|
|
|
EnterTracelibCritSection();
|
|
RemoveEntryList( &Process->Entry );
|
|
LeaveTracelibCritSection();
|
|
|
|
Head = &Process->ThreadListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Thread = CONTAINING_RECORD( Next, THREAD_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteThread( Thread );
|
|
}
|
|
|
|
Head = &Process->DiskListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteDisk( Disk );
|
|
}
|
|
|
|
Head = &Process->HPFListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pHPFRecord = CONTAINING_RECORD(Next, HPF_RECORD, Entry);
|
|
Next = Next->Flink;
|
|
DeleteHPFRecord(pHPFRecord);
|
|
}
|
|
|
|
Head = &Process->FileListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pFile = CONTAINING_RECORD( Next, FILE_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList( &pFile->Entry );
|
|
if (pFile->FileName != NULL)
|
|
free(pFile->FileName);
|
|
free(pFile);
|
|
}
|
|
|
|
Head = &Process->ModuleListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head)
|
|
{
|
|
pModule = CONTAINING_RECORD(Next, MODULE_RECORD, Entry);
|
|
Next = Next->Flink;
|
|
RemoveEntryList(& pModule->Entry);
|
|
if(pModule->strModuleName)
|
|
{
|
|
free(pModule->strModuleName);
|
|
}
|
|
free(pModule);
|
|
}
|
|
|
|
if (Process->ImageName != NULL)
|
|
free(Process->ImageName);
|
|
if (Process->UserName != NULL)
|
|
free(Process->UserName);
|
|
|
|
free( Process );
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
AddThread(
|
|
ULONG ThreadId,
|
|
PEVENT_TRACE pEvent,
|
|
PTHREAD_RECORD * ResultThread
|
|
)
|
|
{
|
|
PTHREAD_RECORD Thread = NULL;
|
|
PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) & pEvent->Header;
|
|
int i;
|
|
|
|
Thread = malloc(sizeof(THREAD_RECORD));
|
|
if (Thread == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
InitThreadRecord(Thread);
|
|
|
|
Thread->TimeStart = Thread->TimeEnd
|
|
= (ULONGLONG) pHeader->TimeStamp.QuadPart;
|
|
Thread->TID = ThreadId;
|
|
Thread->ProcessorID = pEvent->ClientContext & 0x000000FF;
|
|
i = (int)Thread->TID;
|
|
i = i % THREAD_HASH_TABLESIZE;
|
|
InsertHeadList(&CurrentSystem.ThreadHashList[i], &Thread->Entry);
|
|
*ResultThread = Thread;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
DeleteThread(
|
|
PTHREAD_RECORD Thread
|
|
)
|
|
{
|
|
PLIST_ENTRY pHead;
|
|
PLIST_ENTRY pNext;
|
|
PHPF_FILE_RECORD pHPFFileRecord;
|
|
|
|
if (Thread == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
RemoveEntryList( &Thread->Entry );
|
|
DeleteTransList( &Thread->TransListHead, 0 );
|
|
|
|
pHead = & Thread->HPFReadListHead;
|
|
pNext = pHead->Flink;
|
|
while (pNext != pHead)
|
|
{
|
|
pHPFFileRecord = CONTAINING_RECORD(pNext, HPF_FILE_RECORD, Entry);
|
|
pNext = pNext->Flink;
|
|
RemoveEntryList(& pHPFFileRecord->Entry);
|
|
free(pHPFFileRecord);
|
|
}
|
|
pHead = & Thread->HPFWriteListHead;
|
|
pNext = pHead->Flink;
|
|
while (pNext != pHead)
|
|
{
|
|
pHPFFileRecord = CONTAINING_RECORD(pNext, HPF_FILE_RECORD, Entry);
|
|
pNext = pNext->Flink;
|
|
RemoveEntryList(& pHPFFileRecord->Entry);
|
|
free(pHPFFileRecord);
|
|
}
|
|
|
|
free( Thread );
|
|
return TRUE;
|
|
}
|
|
|
|
PTRANS_RECORD
|
|
FindTransByList(
|
|
PLIST_ENTRY Head,
|
|
LPGUID pGuid,
|
|
ULONG level
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PTRANS_RECORD pTrans = NULL;
|
|
|
|
// Recursively look for the list that does
|
|
// not contain a running guid
|
|
//
|
|
if (level <= MAX_TRANS_LEVEL && Head != NULL)
|
|
{
|
|
Next = Head->Flink;
|
|
while (Next != Head)
|
|
{
|
|
pTrans = CONTAINING_RECORD(Next, TRANS_RECORD, Entry);
|
|
if (pTrans->bStarted)
|
|
{
|
|
if ( (level == 0 || level == 1)
|
|
&& IsEqualGUID(pTrans->pGuid, pGuid))
|
|
{
|
|
return pTrans;
|
|
}
|
|
else if (level > 0)
|
|
{
|
|
return FindTransByList(& pTrans->SubTransListHead,
|
|
pGuid,
|
|
level - 1);
|
|
}
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
}
|
|
|
|
// Found the correct list; now find
|
|
// the matching transaction
|
|
//
|
|
if (level == 0 && Head != NULL)
|
|
{
|
|
Next = Head->Flink;
|
|
while (Next != Head)
|
|
{
|
|
pTrans = CONTAINING_RECORD(Next, TRANS_RECORD, Entry);
|
|
if (IsEqualGUID( pTrans->pGuid, pGuid))
|
|
{
|
|
return pTrans;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
//
|
|
// If not Found, go ahead and add it.
|
|
//
|
|
pTrans = CreateTransRecord();
|
|
if (pTrans != NULL) {
|
|
pTrans->pGuid = pGuid;
|
|
InsertHeadList( Head, &pTrans->Entry );
|
|
}
|
|
}
|
|
return pTrans;
|
|
}
|
|
|
|
PMOF_DATA
|
|
FindMofData(
|
|
PMOF_INFO pMofInfo,
|
|
PWCHAR strSortKey
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PLIST_ENTRY Head;
|
|
PMOF_DATA pMofData = NULL;
|
|
|
|
if (pMofInfo == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Head = &pMofInfo->DataListHead;
|
|
|
|
if (Head != NULL)
|
|
{
|
|
Next = Head->Flink;
|
|
while (Next != Head)
|
|
{
|
|
pMofData = CONTAINING_RECORD(Next, MOF_DATA, Entry);
|
|
if (strSortKey == NULL && pMofData->strSortKey == NULL)
|
|
{
|
|
return pMofData;
|
|
}
|
|
else if ( strSortKey != NULL
|
|
&& pMofData->strSortKey != NULL
|
|
&& !wcscmp(pMofData->strSortKey, strSortKey))
|
|
{
|
|
return pMofData;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
// If not Found, go ahead and add it.
|
|
//
|
|
pMofData = (PMOF_DATA)malloc(sizeof(MOF_DATA));
|
|
if (pMofData == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
InitMofData(pMofData);
|
|
if (strSortKey != NULL)
|
|
{
|
|
pMofData->strSortKey =
|
|
(PWCHAR) malloc((lstrlenW(strSortKey) + 1) * sizeof(WCHAR));
|
|
if (pMofData->strSortKey != NULL) {
|
|
StringCchCopyW(pMofData->strSortKey, (lstrlenW(strSortKey) + 1), strSortKey);
|
|
}
|
|
}
|
|
InsertHeadList(Head, &pMofData->Entry);
|
|
}
|
|
return pMofData;
|
|
}
|
|
|
|
BOOLEAN
|
|
DeleteTrans(
|
|
PTRANS_RECORD Trans
|
|
)
|
|
{
|
|
if (Trans == NULL)
|
|
return FALSE;
|
|
EnterTracelibCritSection();
|
|
RemoveEntryList( &Trans->Entry );
|
|
InsertHeadList( &CurrentSystem.FreeTransListHead, &Trans->Entry );
|
|
LeaveTracelibCritSection();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
DeleteTransList(
|
|
PLIST_ENTRY Head,
|
|
ULONG level
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PTRANS_RECORD pTrans;
|
|
|
|
if( Head == NULL || level > MAX_TRANS_LEVEL )
|
|
return FALSE;
|
|
|
|
Next = Head->Flink;
|
|
|
|
while(Next != Head){
|
|
pTrans = CONTAINING_RECORD( Next, TRANS_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteTransList( &pTrans->SubTransListHead, level+1);
|
|
DeleteTrans( pTrans );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PPROCESS_RECORD
|
|
FindProcessById(
|
|
ULONG Id,
|
|
BOOLEAN CheckAlive
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PPROCESS_RECORD Process=NULL;
|
|
|
|
EnterTracelibCritSection();
|
|
|
|
Head = &CurrentSystem.ProcessListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Process = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry );
|
|
if (Process->PID == Id) {
|
|
LeaveTracelibCritSection();
|
|
if ((Process->DeadFlag) && (CheckAlive))
|
|
return NULL;
|
|
else
|
|
return Process;
|
|
}
|
|
|
|
Next = Next->Flink;
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return NULL;
|
|
}
|
|
|
|
PTHREAD_RECORD
|
|
FindGlobalThreadById(
|
|
ULONG ThreadId,
|
|
PEVENT_TRACE pEvent
|
|
)
|
|
{
|
|
PLIST_ENTRY Next,
|
|
Head;
|
|
PTHREAD_RECORD Thread;
|
|
PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) & pEvent->Header;
|
|
ULONG i = ThreadId;
|
|
ULONG Depth = 0;
|
|
|
|
i = i % THREAD_HASH_TABLESIZE;
|
|
|
|
Head = &CurrentSystem.ThreadHashList[i];
|
|
Next = Head->Flink;
|
|
while (Next != Head)
|
|
{
|
|
Thread = CONTAINING_RECORD(Next, THREAD_RECORD, Entry);
|
|
Next = Next->Flink;
|
|
Depth++;
|
|
|
|
if (Thread->TID == ThreadId)
|
|
{
|
|
if (ThreadId == 0)
|
|
{
|
|
ULONG ProcessorId = pEvent->ClientContext & 0x000000FF;
|
|
if (ProcessorId != Thread->ProcessorID)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
if (!Thread->DeadFlag)
|
|
{
|
|
if (Depth > 40) {
|
|
RemoveEntryList( &Thread->Entry );
|
|
InsertHeadList( Head, &Thread->Entry );
|
|
}
|
|
return Thread;
|
|
}
|
|
else if ( Thread->TimeEnd
|
|
== (ULONGLONG) pHeader->TimeStamp.QuadPart)
|
|
{
|
|
if (Depth > 40) {
|
|
RemoveEntryList( &Thread->Entry );
|
|
InsertHeadList( Head, &Thread->Entry );
|
|
}
|
|
return Thread;
|
|
}
|
|
else
|
|
{
|
|
// The alive thead must be at the head of the list
|
|
// otherwise bail
|
|
//
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PWORKLOAD_RECORD
|
|
FindWorkloadById(
|
|
ULONG Id
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PWORKLOAD_RECORD Workload = NULL;
|
|
|
|
Head = &CurrentSystem.WorkloadListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Workload = CONTAINING_RECORD( Next, WORKLOAD_RECORD, Entry );
|
|
if (Workload->ClassNumber == Id) {
|
|
return Workload;
|
|
}
|
|
|
|
Next = Next->Flink;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOLEAN
|
|
AddDisk(
|
|
ULONG DiskNumber,
|
|
PTDISK_RECORD *ReturnedDisk
|
|
)
|
|
{
|
|
PTDISK_RECORD Disk;
|
|
|
|
Disk = malloc(sizeof(TDISK_RECORD));
|
|
if (Disk == NULL) {
|
|
return FALSE;
|
|
}
|
|
InitDiskRecord(Disk, DiskNumber);
|
|
Disk->DiskNumber = DiskNumber;
|
|
|
|
InsertHeadList( &CurrentSystem.GlobalDiskListHead, &Disk->Entry );
|
|
*ReturnedDisk = Disk;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
DeleteDisk(
|
|
PTDISK_RECORD Disk
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PPROCESS_RECORD Process;
|
|
PFILE_RECORD File;
|
|
if (Disk == NULL)
|
|
return FALSE;
|
|
RemoveEntryList( &Disk->Entry );
|
|
|
|
if (Disk->DiskName != NULL)
|
|
free(Disk->DiskName);
|
|
|
|
Head = &Disk->ProcessListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Process = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteProcess( Process );
|
|
}
|
|
Head = &Disk->FileListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
File = CONTAINING_RECORD( Next, FILE_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteFileRecord( File );
|
|
}
|
|
|
|
free( Disk );
|
|
return TRUE;
|
|
}
|
|
|
|
PTDISK_RECORD
|
|
FindLocalDiskById(
|
|
PLIST_ENTRY Head,
|
|
ULONG Id
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PTDISK_RECORD Disk = NULL;
|
|
|
|
if (Head == NULL)
|
|
return NULL;
|
|
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry );
|
|
if (Disk->DiskNumber == Id) {
|
|
return Disk;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
// If not Found, go ahead and add it.
|
|
//
|
|
Disk = malloc(sizeof(TDISK_RECORD));
|
|
if (Disk == NULL) {
|
|
return FALSE;
|
|
}
|
|
InitDiskRecord(Disk, Id);
|
|
|
|
Disk->DiskNumber = Id;
|
|
InsertHeadList( Head, &Disk->Entry );
|
|
return Disk;
|
|
}
|
|
|
|
PTDISK_RECORD
|
|
FindProcessDiskById(
|
|
PPROCESS_RECORD pProcess,
|
|
ULONG Id
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PTDISK_RECORD Disk = NULL;
|
|
|
|
if (pProcess == NULL)
|
|
return NULL;
|
|
|
|
Head = &pProcess->DiskListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry );
|
|
if (Disk->DiskNumber == Id) {
|
|
return Disk;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
// If not Found, go ahead and add it.
|
|
//
|
|
Disk = malloc(sizeof(TDISK_RECORD));
|
|
if (Disk == NULL) {
|
|
return NULL;
|
|
}
|
|
InitDiskRecord(Disk, Id);
|
|
|
|
Disk->DiskNumber = Id;
|
|
InsertHeadList( &pProcess->DiskListHead, &Disk->Entry );
|
|
return Disk;
|
|
}
|
|
|
|
PPROCESS_RECORD
|
|
FindDiskProcessById(
|
|
PTDISK_RECORD pDisk,
|
|
ULONG Id
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PPROCESS_RECORD Process = NULL;
|
|
PPROCESS_RECORD gProcess = NULL;
|
|
|
|
if (pDisk == NULL)
|
|
return NULL;
|
|
|
|
Head = &pDisk->ProcessListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Process = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry );
|
|
if (Process->PID == Id) {
|
|
return Process;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
// If not Found, go ahead and add it.
|
|
//
|
|
Process = malloc(sizeof(PROCESS_RECORD));
|
|
if (Process == NULL) {
|
|
return FALSE;
|
|
}
|
|
InitProcessRecord(Process);
|
|
|
|
Process->PID = Id;
|
|
|
|
// Find the global Process Record and copy the UserName and Image.
|
|
//
|
|
gProcess = FindProcessById(Id, FALSE);
|
|
if (gProcess != NULL) {
|
|
if ( IsNotEmpty( gProcess->UserName ) ) {
|
|
Process->UserName = (LPWSTR)malloc( (wcslen(gProcess->UserName) + 1) * sizeof(WCHAR) );
|
|
if (NULL != Process->UserName) {
|
|
StringCchCopyW(Process->UserName, (wcslen(gProcess->UserName) + 1), gProcess->UserName);
|
|
}
|
|
}
|
|
if ( IsNotEmpty( gProcess->ImageName ) ) {
|
|
Process->ImageName = (LPWSTR)malloc( (wcslen(gProcess->ImageName) + 1) * sizeof(WCHAR) );
|
|
if (NULL != Process->ImageName) {
|
|
StringCchCopyW(Process->ImageName, (wcslen(gProcess->ImageName) + 1), gProcess->ImageName);
|
|
}
|
|
}
|
|
}
|
|
InsertHeadList( &pDisk->ProcessListHead, &Process->Entry );
|
|
return Process;
|
|
}
|
|
|
|
PTDISK_RECORD
|
|
FindGlobalDiskById(
|
|
ULONG Id
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PTDISK_RECORD Disk = NULL;
|
|
|
|
Head = &CurrentSystem.GlobalDiskListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry );
|
|
if (Disk->DiskNumber == Id) {
|
|
return Disk;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
DeleteMofVersion(
|
|
PMOF_VERSION pMofVersion,
|
|
FILE* file
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PITEM_DESC pMofItem;
|
|
|
|
|
|
//
|
|
// Traverse through the MOF_VERSION list and
|
|
// delete each one
|
|
//
|
|
if (pMofVersion == NULL)
|
|
return;
|
|
if( NULL != file ){
|
|
fwprintf( file, L" %s (Type:%d Level:%d Version:%d)\n",
|
|
pMofVersion->strType ? pMofVersion->strType : L"Default",
|
|
pMofVersion->TypeIndex,
|
|
pMofVersion->Level,
|
|
pMofVersion->Version
|
|
);
|
|
}
|
|
Head = &pMofVersion->ItemHeader;
|
|
Next = Head->Flink;
|
|
while (Head != Next) {
|
|
pMofItem = CONTAINING_RECORD(Next, ITEM_DESC, Entry);
|
|
Next = Next->Flink;
|
|
RemoveEntryList( &pMofItem->Entry );
|
|
if (pMofItem->strDescription != NULL){
|
|
if( NULL != file ){
|
|
fwprintf( file, L" %s\n",
|
|
pMofItem->strDescription
|
|
);
|
|
}
|
|
free (pMofItem->strDescription);
|
|
}
|
|
|
|
free (pMofItem);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DeleteMofInfo(
|
|
PMOF_INFO pMofInfo,
|
|
FILE* f
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PMOF_VERSION pMofVersion;
|
|
|
|
//
|
|
// Traverse through the MOF_VERSION list and
|
|
// delete each one
|
|
//
|
|
|
|
if (pMofInfo == NULL){
|
|
return;
|
|
}
|
|
|
|
if( NULL != f ){
|
|
WCHAR buffer[MAXSTR];
|
|
fwprintf( f, L"%s\n",
|
|
pMofInfo->strDescription ? pMofInfo->strDescription : CpdiGuidToString( buffer, MAXSTR, &pMofInfo->Guid ) );
|
|
}
|
|
|
|
Head = &pMofInfo->VersionHeader;
|
|
Next = Head->Flink;
|
|
while (Head != Next) {
|
|
pMofVersion = CONTAINING_RECORD(Next, MOF_VERSION, Entry);
|
|
Next = Next->Flink;
|
|
RemoveEntryList( &pMofVersion->Entry );
|
|
|
|
DeleteMofVersion( pMofVersion, f );
|
|
}
|
|
|
|
//
|
|
// Delete any strings allocated for this structure
|
|
//
|
|
if (pMofInfo->strDescription){
|
|
free(pMofInfo->strDescription);
|
|
}
|
|
|
|
//
|
|
// Finally delete the object
|
|
//
|
|
free(pMofInfo);
|
|
}
|
|
|
|
VOID
|
|
Cleanup()
|
|
{
|
|
PTDISK_RECORD Disk;
|
|
PTHREAD_RECORD Thread;
|
|
PPROCESS_RECORD Process;
|
|
PFILE_RECORD FileRec;
|
|
PWORKLOAD_RECORD pWorkload;
|
|
PMODULE_RECORD pModule;
|
|
PTRANS_RECORD pTrans;
|
|
PMOF_INFO pMofInfo;
|
|
PPRINT_JOB_RECORD pJob;
|
|
PHTTP_REQUEST_RECORD pReq;
|
|
PURL_RECORD pUrl;
|
|
PCLIENT_RECORD pClient;
|
|
PSITE_RECORD pSite;
|
|
PLOGICAL_DRIVE_RECORD pLogDrive;
|
|
PVALUEMAP pValueMap;
|
|
|
|
PLIST_ENTRY Next, Head;
|
|
PLIST_ENTRY EventListHead;
|
|
FILE* f = NULL;
|
|
|
|
ULONG i;
|
|
|
|
// Clean up the Global Disk List for now.
|
|
//
|
|
EventListHead = &CurrentSystem.EventListHead;
|
|
Head = EventListHead;
|
|
Next = Head->Flink;
|
|
|
|
if( (TraceContext->Flags & TRACE_INTERPRET) && NULL != TraceContext->CompFileName ){
|
|
f = _wfopen( TraceContext->CompFileName, L"w" );
|
|
}
|
|
|
|
while (Head != Next) {
|
|
pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry);
|
|
Next = Next->Flink;
|
|
RemoveEntryList( &pMofInfo->Entry );
|
|
DeleteMofInfo(pMofInfo, f);
|
|
}
|
|
|
|
if( NULL != f ){
|
|
fclose( f );
|
|
f = NULL;
|
|
}
|
|
|
|
Head = &CurrentSystem.GlobalDiskListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Disk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteDisk( Disk );
|
|
}
|
|
|
|
// Clean up the Global Thread List for now.
|
|
//
|
|
Head = &CurrentSystem.GlobalThreadListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Thread = CONTAINING_RECORD( Next, THREAD_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteThread( Thread );
|
|
}
|
|
Head = &CurrentSystem.ProcessListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
Process = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteProcess( Process );
|
|
}
|
|
Head = &CurrentSystem.GlobalModuleListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head)
|
|
{
|
|
pModule = CONTAINING_RECORD(Next, MODULE_RECORD, Entry);
|
|
Next = Next->Flink;
|
|
RemoveEntryList(& pModule->Entry);
|
|
if(pModule->strModuleName)
|
|
{
|
|
free(pModule->strModuleName);
|
|
}
|
|
free(pModule);
|
|
}
|
|
|
|
Head = &CurrentSystem.HotFileListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
FileRec = CONTAINING_RECORD( Next, FILE_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteFileRecord( FileRec );
|
|
}
|
|
// Cleanup workload structures
|
|
//
|
|
Head = &CurrentSystem.WorkloadListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pWorkload = CONTAINING_RECORD( Next, WORKLOAD_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
DeleteWorkloadRecord( pWorkload );
|
|
}
|
|
//
|
|
// Cleanup the Print Job List structures
|
|
//
|
|
Head = &CurrentSystem.PrintJobListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pJob = CONTAINING_RECORD( Next, PRINT_JOB_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pJob->Entry);
|
|
free(pJob);
|
|
}
|
|
//
|
|
// Cleanup the Http Request List structures
|
|
//
|
|
Head = &CurrentSystem.HttpReqListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pReq = CONTAINING_RECORD( Next, HTTP_REQUEST_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pReq->Entry);
|
|
if (pReq->URL != NULL) {
|
|
free(pReq->URL);
|
|
}
|
|
free(pReq);
|
|
}
|
|
//
|
|
// Cleanup the Pending Http Request List structures
|
|
//
|
|
Head = &CurrentSystem.PendingHttpReqListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pReq = CONTAINING_RECORD( Next, HTTP_REQUEST_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pReq->Entry);
|
|
if (pReq->URL != NULL) {
|
|
free(pReq->URL);
|
|
}
|
|
free(pReq);
|
|
}
|
|
//
|
|
// Cleanup the URL List structures
|
|
//
|
|
for (i = 0; i < URL_HASH_TABLESIZE; i++) {
|
|
Head = &CurrentSystem.URLHashList[i];
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pUrl = CONTAINING_RECORD( Next, URL_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pUrl->Entry);
|
|
free(pUrl);
|
|
}
|
|
}
|
|
//
|
|
// Cleanup the Client List structures
|
|
//
|
|
Head = &CurrentSystem.ClientListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pClient = CONTAINING_RECORD( Next, CLIENT_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pClient->Entry);
|
|
free(pClient);
|
|
}
|
|
//
|
|
// Cleanup the Site List structures
|
|
//
|
|
Head = &CurrentSystem.SiteListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pSite = CONTAINING_RECORD( Next, SITE_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pSite->Entry);
|
|
free(pSite);
|
|
}
|
|
//
|
|
// Cleanup the Logical Drive structures
|
|
//
|
|
Head = &CurrentSystem.LogicalDriveHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pLogDrive = CONTAINING_RECORD( Next, LOGICAL_DRIVE_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pLogDrive->Entry);
|
|
if (NULL != pLogDrive->DriveLetterString) {
|
|
free(pLogDrive->DriveLetterString);
|
|
}
|
|
free(pLogDrive);
|
|
}
|
|
|
|
//
|
|
// Clean up recyled memory structures
|
|
//
|
|
Head = &CurrentSystem.FreePrintJobListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pJob = CONTAINING_RECORD( Next, PRINT_JOB_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pJob->Entry);
|
|
free(pJob);
|
|
}
|
|
Head = &CurrentSystem.FreeTransListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pTrans = CONTAINING_RECORD( Next, TRANS_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pTrans->Entry);
|
|
free(pTrans);
|
|
}
|
|
Head = &CurrentSystem.FreeHttpReqListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pReq = CONTAINING_RECORD( Next, HTTP_REQUEST_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pReq->Entry);
|
|
free(pReq);
|
|
}
|
|
Head = &CurrentSystem.FreeURLListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pUrl = CONTAINING_RECORD( Next, URL_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pUrl->Entry);
|
|
free(pUrl);
|
|
}
|
|
|
|
Head = &g_ValueMapTable;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pValueMap = CONTAINING_RECORD( Next, VALUEMAP, Entry );
|
|
Next = Next->Flink;
|
|
RemoveEntryList(&pValueMap->Entry);
|
|
if( NULL != pValueMap->saValueMap ){
|
|
SafeArrayDestroy( pValueMap->saValueMap );
|
|
}
|
|
if( NULL != pValueMap->saValues ){
|
|
SafeArrayDestroy( pValueMap->saValues );
|
|
}
|
|
|
|
free( pValueMap );
|
|
}
|
|
}
|
|
|
|
PLOGICAL_DRIVE_RECORD
|
|
FindLogicalDrive(
|
|
ULONGLONG AccessedOffset,
|
|
ULONG DiskNumber
|
|
)
|
|
{
|
|
PLOGICAL_DRIVE_RECORD pLogDrive = NULL;
|
|
PLIST_ENTRY Next, Head;
|
|
|
|
EnterTracelibCritSection();
|
|
// Find drive letter when logical drive info is available.
|
|
Head = &CurrentSystem.LogicalDriveHead;
|
|
Next = Head->Flink;
|
|
if (Next != Head) {
|
|
while (Next != Head) {
|
|
pLogDrive = CONTAINING_RECORD( Next, LOGICAL_DRIVE_RECORD, Entry );
|
|
if (DiskNumber == pLogDrive->DiskNumber &&
|
|
AccessedOffset < pLogDrive->StartOffset &&
|
|
Next->Blink != Head) {
|
|
pLogDrive = CONTAINING_RECORD( Next->Blink, LOGICAL_DRIVE_RECORD, Entry );
|
|
break;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
}
|
|
LeaveTracelibCritSection();
|
|
if (NULL != pLogDrive && DiskNumber == pLogDrive->DiskNumber) {
|
|
return pLogDrive;
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
AddFile(
|
|
WCHAR* fileName,
|
|
PFILE_RECORD *ReturnedFile,
|
|
PLOGICAL_DRIVE_RECORD pLogDrive
|
|
)
|
|
{
|
|
PFILE_RECORD fileRec;
|
|
PLIST_ENTRY Next, Head;
|
|
|
|
if (fileName == NULL)
|
|
return FALSE;
|
|
|
|
fileRec = malloc(sizeof(FILE_RECORD));
|
|
if (fileRec == NULL) {
|
|
return FALSE;
|
|
}
|
|
InitFileRecord( fileRec );
|
|
fileRec->FileName = malloc( (lstrlenW(fileName)+ 1) * sizeof(WCHAR));
|
|
if (fileRec->FileName != NULL) {
|
|
StringCchCopyW(fileRec->FileName, (lstrlenW(fileName)+ 1), fileName);
|
|
}
|
|
if (NULL != pLogDrive) {
|
|
fileRec->DiskNumber = pLogDrive->DiskNumber;
|
|
if (NULL != pLogDrive->DriveLetterString) {
|
|
fileRec->Drive = malloc( (lstrlenW(pLogDrive->DriveLetterString)+ 1) * sizeof(WCHAR));
|
|
if (fileRec->Drive != NULL) {
|
|
StringCchCopyW(fileRec->Drive, lstrlenW(pLogDrive->DriveLetterString)+ 1, pLogDrive->DriveLetterString);
|
|
}
|
|
}
|
|
}
|
|
EnterTracelibCritSection();
|
|
InsertHeadList( &CurrentSystem.HotFileListHead, &fileRec->Entry );
|
|
LeaveTracelibCritSection();
|
|
*ReturnedFile = fileRec;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
DeleteFileRecord(
|
|
PFILE_RECORD fileRec
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PPROTO_PROCESS_RECORD pProto;
|
|
|
|
if (fileRec == NULL)
|
|
return FALSE;
|
|
|
|
EnterTracelibCritSection();
|
|
RemoveEntryList( &fileRec->Entry );
|
|
LeaveTracelibCritSection();
|
|
|
|
if (fileRec->FileName != NULL)
|
|
free(fileRec->FileName);
|
|
if (fileRec->Drive != NULL)
|
|
free(fileRec->Drive);
|
|
|
|
Head = &fileRec->ProtoProcessListHead;
|
|
Next = Head->Flink;
|
|
while (Head != Next) {
|
|
pProto = CONTAINING_RECORD( Next, PROTO_PROCESS_RECORD, Entry);
|
|
Next = Next->Flink;
|
|
RemoveEntryList( &pProto->Entry );
|
|
free(pProto);
|
|
}
|
|
free( fileRec );
|
|
return TRUE;
|
|
}
|
|
|
|
PFILE_RECORD
|
|
FindFileRecordByName(
|
|
WCHAR* fileName,
|
|
PLOGICAL_DRIVE_RECORD pLogDrive
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PFILE_RECORD fileRec = NULL;
|
|
|
|
if (fileName == NULL)
|
|
return NULL;
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.HotFileListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
fileRec = CONTAINING_RECORD( Next, FILE_RECORD, Entry );
|
|
if (!wcscmp(fileName, fileRec->FileName)) {
|
|
if (NULL != pLogDrive && pLogDrive->DiskNumber == fileRec->DiskNumber) {
|
|
if (NULL != pLogDrive->DriveLetterString &&
|
|
NULL != fileRec->Drive &&
|
|
!wcscmp(pLogDrive->DriveLetterString, fileRec->Drive)) {
|
|
LeaveTracelibCritSection();
|
|
return fileRec;
|
|
}
|
|
else if (NULL == pLogDrive->DriveLetterString &&
|
|
NULL == fileRec->Drive) {
|
|
LeaveTracelibCritSection();
|
|
return fileRec;
|
|
}
|
|
}
|
|
else if (NULL == pLogDrive) {
|
|
LeaveTracelibCritSection();
|
|
return fileRec;
|
|
}
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return NULL;
|
|
}
|
|
|
|
PFILE_RECORD
|
|
FindFileInProcess(
|
|
PPROCESS_RECORD pProcess,
|
|
WCHAR* fileName
|
|
)
|
|
{
|
|
PLIST_ENTRY Next, Head;
|
|
PFILE_RECORD fileRec = NULL;
|
|
if (pProcess == NULL || fileName == NULL)
|
|
return NULL;
|
|
EnterTracelibCritSection();
|
|
Head = &pProcess->FileListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
fileRec = CONTAINING_RECORD( Next, FILE_RECORD, Entry );
|
|
if (!wcscmp(fileName, fileRec->FileName)) {
|
|
//ReleaseMutex(CurrentSystem.HotFileListMutex);
|
|
LeaveTracelibCritSection();
|
|
return fileRec;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
AddLogicalDrive(
|
|
ULONGLONG StartOffset,
|
|
ULONGLONG PartitionSize,
|
|
ULONG DiskNumber,
|
|
ULONG Size,
|
|
ULONG DriveType,
|
|
PWCHAR DriveLetterString
|
|
)
|
|
{
|
|
PLOGICAL_DRIVE_RECORD pLogDrive = NULL, pTempLogDrive = NULL;
|
|
PLIST_ENTRY Next, Head;
|
|
|
|
pLogDrive = malloc(sizeof(LOGICAL_DRIVE_RECORD));
|
|
if (pLogDrive == NULL) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return;
|
|
}
|
|
|
|
RtlZeroMemory(pLogDrive, sizeof(LOGICAL_DRIVE_RECORD));
|
|
pLogDrive->StartOffset = StartOffset;
|
|
pLogDrive->PartitionSize = PartitionSize;
|
|
pLogDrive->DiskNumber = DiskNumber;
|
|
pLogDrive->Size = Size;
|
|
pLogDrive->DriveType = DriveType;
|
|
if (DriveLetterString != NULL) {
|
|
pLogDrive->DriveLetterString = malloc( (lstrlenW(DriveLetterString)+ 1) * sizeof(WCHAR));
|
|
if (pLogDrive->DriveLetterString != NULL) {
|
|
StringCchCopyW(pLogDrive->DriveLetterString, lstrlenW(DriveLetterString)+ 1, DriveLetterString);
|
|
}
|
|
}
|
|
EnterTracelibCritSection();
|
|
// When inserting logical drives, do it in StartOffset order.
|
|
Head = &CurrentSystem.LogicalDriveHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pTempLogDrive = CONTAINING_RECORD( Next, LOGICAL_DRIVE_RECORD, Entry );
|
|
if (pLogDrive->StartOffset < pTempLogDrive->StartOffset) {
|
|
break;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
InsertTailList( Next, &pLogDrive->Entry );
|
|
LeaveTracelibCritSection();
|
|
|
|
}
|
|
|
|
VOID
|
|
AssignClass(
|
|
PPROCESS_RECORD pProcess,
|
|
PTHREAD_RECORD pThread
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(pProcess);
|
|
|
|
pThread->ClassNumber = 1; // For the Time being make it single class.
|
|
}
|
|
|
|
VOID
|
|
Classify()
|
|
{
|
|
// Assign Class to each Thread or Process.
|
|
//
|
|
PLIST_ENTRY Head, Next;
|
|
PTHREAD_RECORD pThread;
|
|
|
|
Head = &CurrentSystem.GlobalThreadListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pThread = CONTAINING_RECORD( Next, THREAD_RECORD, Entry );
|
|
|
|
AssignClass(NULL, pThread);
|
|
|
|
Aggregate(pThread);
|
|
|
|
Next = Next->Flink;
|
|
}
|
|
}
|
|
|
|
// Given the number of classes this routine
|
|
// creates and initializes the workload object
|
|
//
|
|
VOID
|
|
InitClass()
|
|
{
|
|
PWORKLOAD_RECORD pWorkload;
|
|
ULONG nclass;
|
|
ULONG i;
|
|
|
|
// Create the Class records here.
|
|
//
|
|
nclass = 1;
|
|
CurrentSystem.NumberOfWorkloads = 1;
|
|
for (i = 1; i <= nclass; i++) {
|
|
|
|
pWorkload = malloc(sizeof(WORKLOAD_RECORD));
|
|
if (pWorkload == NULL) {
|
|
return;
|
|
}
|
|
InitWorkloadRecord( pWorkload );
|
|
pWorkload->ClassNumber = i;
|
|
InsertHeadList( &CurrentSystem.WorkloadListHead, &pWorkload->Entry );
|
|
}
|
|
}
|
|
|
|
PTDISK_RECORD
|
|
FindDiskInList(
|
|
IN PLIST_ENTRY Head,
|
|
IN ULONG Id
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PTDISK_RECORD pDisk = NULL;
|
|
|
|
if (Head != NULL) {
|
|
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
pDisk = CONTAINING_RECORD ( Next, TDISK_RECORD, Entry );
|
|
if (pDisk->DiskNumber == Id) {
|
|
return pDisk;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
pDisk = malloc(sizeof(TDISK_RECORD));
|
|
if (pDisk == NULL) {
|
|
return NULL;
|
|
}
|
|
InitDiskRecord( pDisk, Id );
|
|
|
|
InsertHeadList( Head, &pDisk->Entry );
|
|
}
|
|
return pDisk;
|
|
}
|
|
|
|
VOID
|
|
Aggregate(
|
|
IN PTHREAD_RECORD pThread
|
|
)
|
|
{
|
|
PWORKLOAD_RECORD pWorkload;
|
|
PTDISK_RECORD pDisk, pClassDisk;
|
|
PLIST_ENTRY Next, Head;
|
|
|
|
// Aggregate the metrics over each class.
|
|
//
|
|
if ((pWorkload = FindWorkloadById(pThread->ClassNumber)) != NULL) {
|
|
pWorkload->UserCPU += (pThread->UCPUEnd - pThread->UCPUStart)
|
|
* CurrentSystem.TimerResolution;
|
|
pWorkload->KernelCPU += (pThread->KCPUEnd - pThread->KCPUStart)
|
|
* CurrentSystem.TimerResolution;
|
|
//
|
|
// Walk through the Thread Disk records and aggregate them
|
|
// to the class
|
|
|
|
Head = &pThread->DiskListHead;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
pDisk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry );
|
|
Next = Next->Flink;
|
|
|
|
pClassDisk = FindDiskInList(&pWorkload->DiskListHead,
|
|
pDisk->DiskNumber) ;
|
|
if (pClassDisk != NULL) {
|
|
pClassDisk->ReadCount += pDisk->ReadCount;
|
|
pClassDisk->WriteCount += pDisk->WriteCount;
|
|
pClassDisk->ReadSize += (pDisk->ReadCount * pDisk->ReadSize);
|
|
pClassDisk->WriteSize += (pDisk->WriteCount * pDisk->WriteSize);
|
|
|
|
pWorkload->ReadCount += pDisk->ReadCount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ULONGLONG
|
|
CalculateProcessLifeTime(
|
|
PPROCESS_RECORD pProcess
|
|
)
|
|
{
|
|
BOOLEAN fFirst = TRUE;
|
|
ULONGLONG TimeStart = 0;
|
|
ULONGLONG TimeEnd = 0;
|
|
PLIST_ENTRY pHead = &pProcess->ThreadListHead;
|
|
PLIST_ENTRY pNext = pHead->Flink;
|
|
PTHREAD_RECORD pThread;
|
|
|
|
while (pNext != pHead)
|
|
{
|
|
pThread = CONTAINING_RECORD(pNext, THREAD_RECORD, Entry);
|
|
pNext = pNext->Flink;
|
|
|
|
if (fFirst)
|
|
{
|
|
TimeStart = pThread->TimeStart;
|
|
TimeEnd = pThread->TimeEnd;
|
|
fFirst = FALSE;
|
|
}
|
|
else if (pThread->TimeStart < TimeStart)
|
|
{
|
|
TimeStart = pThread->TimeStart;
|
|
}
|
|
else if (pThread->TimeEnd > TimeEnd)
|
|
{
|
|
TimeEnd = pThread->TimeEnd;
|
|
}
|
|
}
|
|
return (TimeEnd - TimeStart);
|
|
}
|
|
|
|
ULONG
|
|
CalculateProcessKCPU(
|
|
PPROCESS_RECORD pProcess
|
|
)
|
|
{
|
|
ULONG KCPUTotal = 0;
|
|
ULONG KCPUMissing = 0;
|
|
PLIST_ENTRY pHead = &pProcess->ThreadListHead;
|
|
PLIST_ENTRY pNext = pHead->Flink;
|
|
PTHREAD_RECORD pThread;
|
|
|
|
while (pNext != pHead)
|
|
{
|
|
pThread = CONTAINING_RECORD(pNext, THREAD_RECORD, Entry);
|
|
pNext = pNext->Flink;
|
|
|
|
if (pThread->KCPUEnd > pThread->KCPUStart)
|
|
{
|
|
|
|
if ((pProcess->PID != 0) ||
|
|
((pProcess->PID == 0) && (pThread->TID == 0)) ){
|
|
|
|
KCPUTotal += pThread->KCPUEnd - pThread->KCPUStart;
|
|
}
|
|
else {
|
|
KCPUMissing += pThread->KCPUEnd - pThread->KCPUStart;
|
|
}
|
|
}
|
|
}
|
|
return (ULONG) (KCPUTotal * CurrentSystem.TimerResolution);
|
|
}
|
|
|
|
ULONG
|
|
CalculateProcessUCPU(
|
|
PPROCESS_RECORD pProcess
|
|
)
|
|
{
|
|
ULONG UCPUTotal = 0;
|
|
ULONG UCPUMissing = 0;
|
|
PLIST_ENTRY pHead = &pProcess->ThreadListHead;
|
|
PLIST_ENTRY pNext = pHead->Flink;
|
|
PTHREAD_RECORD pThread;
|
|
|
|
|
|
while (pNext != pHead)
|
|
{
|
|
pThread = CONTAINING_RECORD(pNext, THREAD_RECORD, Entry);
|
|
pNext = pNext->Flink;
|
|
|
|
if (pThread->UCPUEnd > pThread->UCPUStart)
|
|
{
|
|
if ((pProcess->PID != 0) ||
|
|
((pProcess->PID == 0) && (pThread->TID == 0)) ) {
|
|
UCPUTotal += pThread->UCPUEnd - pThread->UCPUStart;
|
|
}
|
|
else {
|
|
UCPUMissing += pThread->UCPUEnd - pThread->UCPUStart;
|
|
}
|
|
}
|
|
}
|
|
return (ULONG) (UCPUTotal * CurrentSystem.TimerResolution);
|
|
}
|
|
|
|
PPRINT_JOB_RECORD
|
|
FindPrintJobRecord(
|
|
ULONG JobId
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PPRINT_JOB_RECORD pJob;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.PrintJobListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
pJob = CONTAINING_RECORD ( Next, PRINT_JOB_RECORD, Entry );
|
|
if (pJob->JobId == JobId) {
|
|
LeaveTracelibCritSection();
|
|
return pJob;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PHTTP_REQUEST_RECORD
|
|
FindHttpReqRecord(
|
|
ULONGLONG RequestId
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PHTTP_REQUEST_RECORD pReq;
|
|
ULONG Depth = 0;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.HttpReqListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
pReq = CONTAINING_RECORD ( Next, HTTP_REQUEST_RECORD, Entry );
|
|
if (pReq->RequestId == RequestId) {
|
|
if (Depth > 40) {
|
|
RemoveEntryList( &pReq->Entry );
|
|
InsertHeadList( Head, &pReq->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return pReq;
|
|
}
|
|
Next = Next->Flink;
|
|
Depth++;
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PHTTP_REQUEST_RECORD
|
|
FindHttpReqRecordByConId(
|
|
ULONGLONG ConId,
|
|
PHTTP_REQUEST_RECORD pPrevReq
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PHTTP_REQUEST_RECORD pReq;
|
|
ULONG Depth = 0;
|
|
|
|
EnterTracelibCritSection();
|
|
|
|
Head = &CurrentSystem.HttpReqListHead;
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
pReq = CONTAINING_RECORD ( Next, HTTP_REQUEST_RECORD, Entry );
|
|
if (pReq->ConId == ConId) {
|
|
if (pPrevReq == NULL || pPrevReq != pReq) {
|
|
if (Depth > 40) {
|
|
RemoveEntryList( &pReq->Entry );
|
|
InsertHeadList( Head, &pReq->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return pReq;
|
|
}
|
|
}
|
|
Next = Next->Flink;
|
|
Depth++;
|
|
}
|
|
|
|
Depth = 0;
|
|
Head = &CurrentSystem.PendingHttpReqListHead;
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
pReq = CONTAINING_RECORD ( Next, HTTP_REQUEST_RECORD, Entry );
|
|
if (pReq->ConId == ConId) {
|
|
if (pPrevReq == NULL || pPrevReq != pReq) {
|
|
if (Depth > 40) {
|
|
RemoveEntryList( &pReq->Entry );
|
|
InsertHeadList( Head, &pReq->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return pReq;
|
|
}
|
|
}
|
|
Next = Next->Flink;
|
|
Depth++;
|
|
}
|
|
|
|
LeaveTracelibCritSection();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PHTTP_REQUEST_RECORD
|
|
FindPendingHttpReqRecord(
|
|
ULONGLONG RequestId
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PHTTP_REQUEST_RECORD pReq;
|
|
ULONG Depth = 0;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.PendingHttpReqListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
pReq = CONTAINING_RECORD ( Next, HTTP_REQUEST_RECORD, Entry );
|
|
if (pReq->RequestId == RequestId) {
|
|
if (Depth > 40) {
|
|
RemoveEntryList( &pReq->Entry );
|
|
InsertHeadList( Head, &pReq->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return pReq;
|
|
}
|
|
Next = Next->Flink;
|
|
Depth++;
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PURL_RECORD
|
|
FindUrlRecord(
|
|
PUCHAR Url
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PURL_RECORD pUrl;
|
|
ULONG Depth = 0;
|
|
ULONG UrlStrSize;
|
|
PUCHAR UrlChar;
|
|
BOOL bMatch;
|
|
UCHAR TempEndChar;
|
|
USHORT HashKey;
|
|
|
|
if (Url == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
UrlStrSize = 0;
|
|
UrlChar = Url;
|
|
while (*UrlChar != '\0' && *UrlChar != '?') {
|
|
UrlStrSize++;
|
|
UrlChar++;
|
|
}
|
|
|
|
// No URL will end with '/'
|
|
if (*(UrlChar - 1) == '/') {
|
|
UrlStrSize--;
|
|
}
|
|
TempEndChar = *(Url + UrlStrSize);
|
|
*(Url + UrlStrSize) = '\0';
|
|
HashKey = UrlHashKey(Url, UrlStrSize);
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.URLHashList[HashKey];
|
|
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
|
|
pUrl = CONTAINING_RECORD ( Next, URL_RECORD, Entry );
|
|
// pUrl->URL cannot be NULL. If it is, it shouldn't even be created.
|
|
|
|
if ( _stricmp( Url, pUrl->URL ) == 0 ) {
|
|
if (Depth > 20) {
|
|
RemoveEntryList( &pUrl->Entry );
|
|
InsertHeadList( Head, &pUrl->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return pUrl;
|
|
}
|
|
Next = Next->Flink;
|
|
Depth++;
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
*(Url + UrlStrSize) = TempEndChar;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PCLIENT_RECORD
|
|
FindClientRecord(
|
|
USHORT IpAddrType,
|
|
ULONG IpAddrV4,
|
|
USHORT *IpAddrV6
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PCLIENT_RECORD pClient;
|
|
|
|
if (IpAddrV6 == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.ClientListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
pClient = CONTAINING_RECORD ( Next, CLIENT_RECORD, Entry );
|
|
if (pClient->IpAddrType == IpAddrType &&
|
|
pClient->IpAddrV4 == IpAddrV4 &&
|
|
RtlCompareMemory(IpAddrV6, pClient->IpAddrV6, sizeof(USHORT) * 8) == sizeof(USHORT) * 8) {
|
|
LeaveTracelibCritSection();
|
|
return pClient;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PSITE_RECORD
|
|
FindSiteRecord(
|
|
ULONG SiteId
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PSITE_RECORD pSite;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.SiteListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
pSite = CONTAINING_RECORD ( Next, SITE_RECORD, Entry );
|
|
if (pSite->SiteId == SiteId) {
|
|
LeaveTracelibCritSection();
|
|
return pSite;
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// A New Job with a JobId has been found. This routine will create a
|
|
// new job record to track it through various threads in the system
|
|
//
|
|
|
|
PPRINT_JOB_RECORD
|
|
AddPrintJobRecord(
|
|
ULONG JobId
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PPRINT_JOB_RECORD pJob = NULL;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.FreePrintJobListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
if (Next != Head) {
|
|
pJob = CONTAINING_RECORD ( Next, PRINT_JOB_RECORD, Entry );
|
|
RemoveEntryList( &pJob->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
if (pJob == NULL) {
|
|
pJob = malloc(sizeof(PRINT_JOB_RECORD));
|
|
if (pJob == NULL) {
|
|
SetLastError( ERROR_OUTOFMEMORY);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
RtlZeroMemory(pJob, sizeof(PRINT_JOB_RECORD));
|
|
pJob->JobId = JobId;
|
|
|
|
EnterTracelibCritSection();
|
|
InsertHeadList( &CurrentSystem.PrintJobListHead, &pJob->Entry );
|
|
LeaveTracelibCritSection();
|
|
|
|
return pJob;
|
|
}
|
|
|
|
PHTTP_REQUEST_RECORD
|
|
AddHttpReqRecord(
|
|
ULONGLONG RequestId,
|
|
USHORT IpAddrType,
|
|
ULONG IpAddrV4,
|
|
USHORT *IpAddrV6
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PHTTP_REQUEST_RECORD pReq = NULL;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.FreeHttpReqListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
if (Next != Head) {
|
|
pReq = CONTAINING_RECORD ( Next, HTTP_REQUEST_RECORD, Entry );
|
|
RemoveEntryList( &pReq->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
if (pReq == NULL) {
|
|
pReq = malloc(sizeof(HTTP_REQUEST_RECORD));
|
|
if (pReq == NULL) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
RtlZeroMemory(pReq, sizeof(HTTP_REQUEST_RECORD));
|
|
pReq->RequestId = RequestId;
|
|
pReq->IpAddrType = IpAddrType;
|
|
pReq->IpAddrV4 = IpAddrV4;
|
|
if (IpAddrV6 != NULL && IpAddrType == TDI_ADDRESS_TYPE_IP6) {
|
|
RtlCopyMemory(&pReq->IpAddrV6, IpAddrV6, sizeof(USHORT) * 8);
|
|
}
|
|
|
|
EnterTracelibCritSection();
|
|
InsertHeadList( &CurrentSystem.HttpReqListHead, &pReq->Entry );
|
|
LeaveTracelibCritSection();
|
|
|
|
return pReq;
|
|
}
|
|
|
|
PURL_RECORD
|
|
AddUrlRecord(
|
|
PUCHAR Url
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PUCHAR UrlStr = NULL, UrlChar;
|
|
PURL_RECORD pUrl = NULL;
|
|
ULONG UrlStrSize;
|
|
USHORT HashKey;
|
|
|
|
if (Url == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.FreeURLListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
if (Next != Head) {
|
|
pUrl = CONTAINING_RECORD ( Next, URL_RECORD, Entry );
|
|
RemoveEntryList( &pUrl->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
|
|
if (pUrl == NULL) {
|
|
pUrl = malloc(sizeof(URL_RECORD));
|
|
if (pUrl == NULL) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
UrlStrSize = 0;
|
|
UrlChar = Url;
|
|
while (*UrlChar != '\0' && *UrlChar != '?') {
|
|
UrlStrSize++;
|
|
UrlChar++;
|
|
}
|
|
|
|
// No URL will end with '/'
|
|
if (*(UrlChar - 1) == '/') {
|
|
*(UrlChar - 1) = '\0';
|
|
UrlStrSize--;
|
|
}
|
|
|
|
RtlZeroMemory(pUrl, sizeof(URL_RECORD));
|
|
pUrl->URL = (PUCHAR)malloc(UrlStrSize + 1);
|
|
if (pUrl->URL == NULL) {
|
|
EnterTracelibCritSection();
|
|
InsertHeadList( &CurrentSystem.FreeURLListHead, &pUrl->Entry );
|
|
LeaveTracelibCritSection();
|
|
return NULL;
|
|
}
|
|
strncpy(pUrl->URL, Url, UrlStrSize);
|
|
*(pUrl->URL + UrlStrSize) = '\0';
|
|
HashKey = UrlHashKey(pUrl->URL, UrlStrSize);
|
|
EnterTracelibCritSection();
|
|
InsertHeadList( &CurrentSystem.URLHashList[HashKey], &pUrl->Entry );
|
|
LeaveTracelibCritSection();
|
|
|
|
return pUrl;
|
|
}
|
|
|
|
PURL_RECORD
|
|
FindOrAddUrlRecord(
|
|
PUCHAR Url
|
|
)
|
|
{
|
|
PURL_RECORD pUrl = NULL;
|
|
|
|
pUrl = FindUrlRecord(Url);
|
|
if (pUrl == NULL) {
|
|
pUrl = AddUrlRecord(Url);
|
|
}
|
|
return pUrl;
|
|
}
|
|
|
|
PCLIENT_RECORD
|
|
AddClientRecord(
|
|
USHORT IpAddrType,
|
|
ULONG IpAddrV4,
|
|
USHORT *IpAddrV6
|
|
)
|
|
{
|
|
PCLIENT_RECORD pClient = NULL;
|
|
|
|
pClient = malloc(sizeof(CLIENT_RECORD));
|
|
if (pClient == NULL) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
RtlZeroMemory(pClient, sizeof(CLIENT_RECORD));
|
|
pClient->IpAddrType = IpAddrType;
|
|
pClient->IpAddrV4 = IpAddrV4;
|
|
if (IpAddrV6 != NULL && IpAddrType == TDI_ADDRESS_TYPE_IP6) {
|
|
RtlCopyMemory(pClient->IpAddrV6, IpAddrV6, sizeof(USHORT) * 8);
|
|
}
|
|
|
|
EnterTracelibCritSection();
|
|
InsertHeadList( &CurrentSystem.ClientListHead, &pClient->Entry );
|
|
LeaveTracelibCritSection();
|
|
|
|
return pClient;
|
|
}
|
|
|
|
PCLIENT_RECORD
|
|
FindOrAddClientRecord(
|
|
USHORT IpAddrType,
|
|
ULONG IpAddrV4,
|
|
USHORT *IpAddrV6
|
|
)
|
|
{
|
|
PCLIENT_RECORD pClient = NULL;
|
|
|
|
pClient = FindClientRecord(IpAddrType, IpAddrV4, IpAddrV6);
|
|
if (pClient == NULL) {
|
|
pClient = AddClientRecord(IpAddrType, IpAddrV4, IpAddrV6);
|
|
}
|
|
return pClient;
|
|
}
|
|
|
|
PSITE_RECORD
|
|
AddSiteRecord(
|
|
ULONG SiteId
|
|
)
|
|
{
|
|
PSITE_RECORD pSite = NULL;
|
|
|
|
pSite = malloc(sizeof(SITE_RECORD));
|
|
if (pSite == NULL) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
RtlZeroMemory(pSite, sizeof(SITE_RECORD));
|
|
pSite->SiteId = SiteId;
|
|
|
|
EnterTracelibCritSection();
|
|
InsertHeadList( &CurrentSystem.SiteListHead, &pSite->Entry );
|
|
LeaveTracelibCritSection();
|
|
|
|
return pSite;
|
|
}
|
|
|
|
PSITE_RECORD
|
|
FindOrAddSiteRecord(
|
|
ULONG SiteId
|
|
)
|
|
{
|
|
PSITE_RECORD pSite = NULL;
|
|
|
|
pSite = FindSiteRecord(SiteId);
|
|
if (pSite == NULL) {
|
|
pSite = AddSiteRecord(SiteId);
|
|
}
|
|
return pSite;
|
|
}
|
|
|
|
PURL_RECORD
|
|
GetHeadUrlRecord(
|
|
ULONG index
|
|
)
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PURL_RECORD pUrl = NULL;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.URLHashList[index];
|
|
Next = Head->Flink;
|
|
|
|
if (Next != Head) {
|
|
pUrl = CONTAINING_RECORD ( Next, URL_RECORD, Entry );
|
|
RemoveEntryList( &pUrl->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return pUrl;
|
|
}
|
|
|
|
PCLIENT_RECORD
|
|
GetHeadClientRecord()
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PCLIENT_RECORD pClient = NULL;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.ClientListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
if (Next != Head) {
|
|
pClient = CONTAINING_RECORD ( Next, CLIENT_RECORD, Entry );
|
|
RemoveEntryList( &pClient->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return pClient;
|
|
}
|
|
|
|
PSITE_RECORD
|
|
GetHeadSiteRecord()
|
|
{
|
|
PLIST_ENTRY Head, Next;
|
|
PSITE_RECORD pSite = NULL;
|
|
|
|
EnterTracelibCritSection();
|
|
Head = &CurrentSystem.SiteListHead;
|
|
|
|
Next = Head->Flink;
|
|
|
|
if (Next != Head) {
|
|
pSite = CONTAINING_RECORD ( Next, SITE_RECORD, Entry );
|
|
RemoveEntryList( &pSite->Entry );
|
|
}
|
|
LeaveTracelibCritSection();
|
|
return pSite;
|
|
}
|
|
|
|
//
|
|
// Deletes a Job record with the JobId. Before deleting the contents
|
|
// of the job record is dumped to a temp file for later reporting.
|
|
//
|
|
ULONG
|
|
DeletePrintJobRecord(
|
|
PPRINT_JOB_RECORD pJob,
|
|
ULONG bSave
|
|
)
|
|
{
|
|
if (pJob == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
//
|
|
// Print the Contents of pJob to file.
|
|
//
|
|
|
|
// If the -spooler option isn't given to the reducer this fprintf causes the
|
|
// program to crash. Maybe TRACE_SPOOLER should alway be set.
|
|
|
|
if (CurrentSystem.TempPrintFile != NULL && bSave) {
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->JobId);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->KCPUTime);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->UCPUTime);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->ReadIO);
|
|
fprintf(CurrentSystem.TempPrintFile, "%I64u, ", pJob->StartTime);
|
|
fprintf(CurrentSystem.TempPrintFile, "%I64u, ", pJob->EndTime);
|
|
fprintf(CurrentSystem.TempPrintFile, "%I64u, ", (pJob->ResponseTime - pJob->PauseTime));
|
|
fprintf(CurrentSystem.TempPrintFile, "%I64u, ", pJob->PrintJobTime);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->WriteIO);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->DataType);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->JobSize);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->Pages);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->PagesPerSide);
|
|
fprintf(CurrentSystem.TempPrintFile, "%hd, ", pJob->FilesOpened);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d, ", pJob->GdiJobSize);
|
|
fprintf(CurrentSystem.TempPrintFile, "%hd, ", pJob->Color);
|
|
fprintf(CurrentSystem.TempPrintFile, "%hd, ", pJob->XRes);
|
|
fprintf(CurrentSystem.TempPrintFile, "%hd, ", pJob->YRes);
|
|
fprintf(CurrentSystem.TempPrintFile, "%hd, ", pJob->Quality);
|
|
fprintf(CurrentSystem.TempPrintFile, "%hd, ", pJob->Copies);
|
|
fprintf(CurrentSystem.TempPrintFile, "%hd, ", pJob->TTOption);
|
|
fprintf(CurrentSystem.TempPrintFile, "%d\n", pJob->NumberOfThreads);
|
|
}
|
|
|
|
EnterTracelibCritSection();
|
|
RemoveEntryList( &pJob->Entry );
|
|
InsertHeadList( &CurrentSystem.FreePrintJobListHead, &pJob->Entry );
|
|
LeaveTracelibCritSection();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
DeleteHttpReqRecord(
|
|
PHTTP_REQUEST_RECORD pReq,
|
|
ULONG bSave
|
|
)
|
|
{
|
|
if (pReq == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
//
|
|
// Print the Contents of pReq to file.
|
|
//
|
|
|
|
if (CurrentSystem.TempIisFile != NULL && bSave) {
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->RequestId);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->SiteId);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->KCPUTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->UCPUTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->ReadIO);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->WriteIO);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ULStartTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ULEndTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ULResponseTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ULParseTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ULDeliverTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ULReceiveTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->ULReceiveType);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->ULEndType);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->W3StartTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->W3EndTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->W3FilterResponseTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->W3ProcessType);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->W3EndType);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->FileReqTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->CGIStartTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->CGIEndTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ISAPIStartTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ISAPIEndTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ASPStartTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->ASPEndTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->SSLResponseTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%I64u, ", pReq->StrmFltrResponseTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->HttpStatus);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IsapiExt);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IpAddrType);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->IpAddrV4);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IpAddrV6[0]);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IpAddrV6[1]);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IpAddrV6[2]);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IpAddrV6[3]);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IpAddrV6[4]);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IpAddrV6[5]);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IpAddrV6[6]);
|
|
fprintf(CurrentSystem.TempIisFile, "%hd, ", pReq->IpAddrV6[7]);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->NumberOfThreads);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->BytesSent);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->ULCPUTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->W3CPUTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->W3FltrCPUTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->ISAPICPUTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%d, ", pReq->ASPCPUTime);
|
|
fprintf(CurrentSystem.TempIisFile, "%d,", pReq->CGICPUTime);
|
|
if (pReq->URL != NULL) {
|
|
fprintf(CurrentSystem.TempIisFile, "%s\n", pReq->URL);
|
|
free(pReq->URL);
|
|
}
|
|
else {
|
|
fprintf(CurrentSystem.TempIisFile, "Unknown\n");
|
|
}
|
|
}
|
|
|
|
EnterTracelibCritSection();
|
|
RemoveEntryList( &pReq->Entry );
|
|
InsertHeadList( &CurrentSystem.FreeHttpReqListHead, &pReq->Entry );
|
|
LeaveTracelibCritSection();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
DeleteUrlRecord(
|
|
PURL_RECORD pUrl
|
|
)
|
|
{
|
|
if (pUrl == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
if (pUrl->URL != NULL) {
|
|
free(pUrl->URL);
|
|
}
|
|
EnterTracelibCritSection();
|
|
RemoveEntryList( &pUrl->Entry );
|
|
InsertHeadList( &CurrentSystem.FreeURLListHead, &pUrl->Entry );
|
|
LeaveTracelibCritSection();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
DeleteClientRecord(
|
|
PCLIENT_RECORD pClient
|
|
)
|
|
{
|
|
if (pClient == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
EnterTracelibCritSection();
|
|
RemoveEntryList( &pClient->Entry );
|
|
LeaveTracelibCritSection();
|
|
free(pClient);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
DeleteSiteRecord(
|
|
PSITE_RECORD pSite
|
|
)
|
|
{
|
|
if (pSite == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
EnterTracelibCritSection();
|
|
RemoveEntryList( &pSite->Entry );
|
|
LeaveTracelibCritSection();
|
|
free(pSite);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|