2025-05-13 19:45:22 +03:00

303 lines
9.6 KiB
C

/*
* Process Hacker Plugins -
* Hardware Devices Plugin
*
* Copyright (C) 2015-2016 dmex
* Copyright (C) 2016 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "devices.h"
VOID DiskEntryDeleteProcedure(
_In_ PVOID Object,
_In_ ULONG Flags
)
{
PDV_DISK_ENTRY entry = Object;
PhAcquireQueuedLockExclusive(&DiskDrivesListLock);
PhRemoveItemList(DiskDrivesList, PhFindItemList(DiskDrivesList, entry));
PhReleaseQueuedLockExclusive(&DiskDrivesListLock);
DeleteDiskId(&entry->Id);
PhClearReference(&entry->DiskName);
PhDeleteCircularBuffer_ULONG64(&entry->ReadBuffer);
PhDeleteCircularBuffer_ULONG64(&entry->WriteBuffer);
AddRemoveDeviceChangeCallback();
}
VOID DiskDrivesInitialize(
VOID
)
{
DiskDrivesList = PhCreateList(1);
DiskDriveEntryType = PhCreateObjectType(L"DiskDriveEntry", 0, DiskEntryDeleteProcedure);
}
VOID DiskDrivesUpdate(
VOID
)
{
static ULONG runCount = 0; // MUST keep in sync with runCount in process provider
PhAcquireQueuedLockShared(&DiskDrivesListLock);
for (ULONG i = 0; i < DiskDrivesList->Count; i++)
{
HANDLE deviceHandle;
PDV_DISK_ENTRY entry;
entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]);
if (!entry)
continue;
if (NT_SUCCESS(DiskDriveCreateHandle(&deviceHandle, entry->Id.DevicePath)))
{
DISK_PERFORMANCE diskPerformance;
if (NT_SUCCESS(DiskDriveQueryStatistics(deviceHandle, &diskPerformance)))
{
ULONG64 readTime;
ULONG64 writeTime;
ULONG64 idleTime;
ULONG readCount;
ULONG writeCount;
ULONG64 queryTime;
PhUpdateDelta(&entry->BytesReadDelta, diskPerformance.BytesRead.QuadPart);
PhUpdateDelta(&entry->BytesWrittenDelta, diskPerformance.BytesWritten.QuadPart);
PhUpdateDelta(&entry->ReadTimeDelta, diskPerformance.ReadTime.QuadPart);
PhUpdateDelta(&entry->WriteTimeDelta, diskPerformance.WriteTime.QuadPart);
PhUpdateDelta(&entry->IdleTimeDelta, diskPerformance.IdleTime.QuadPart);
PhUpdateDelta(&entry->ReadCountDelta, diskPerformance.ReadCount);
PhUpdateDelta(&entry->WriteCountDelta, diskPerformance.WriteCount);
PhUpdateDelta(&entry->QueryTimeDelta, diskPerformance.QueryTime.QuadPart);
readTime = entry->ReadTimeDelta.Delta;
writeTime = entry->WriteTimeDelta.Delta;
idleTime = entry->IdleTimeDelta.Delta;
readCount = entry->ReadCountDelta.Delta;
writeCount = entry->WriteCountDelta.Delta;
queryTime = entry->QueryTimeDelta.Delta;
if (readCount + writeCount != 0)
entry->ResponseTime = ((FLOAT)readTime + (FLOAT)writeTime) / (readCount + writeCount);
else
entry->ResponseTime = 0;
if (queryTime != 0)
entry->ActiveTime = (FLOAT)(queryTime - idleTime) / queryTime * 100;
else
entry->ActiveTime = 0.0f;
if (entry->ActiveTime > 100.f)
entry->ActiveTime = 0.f;
if (entry->ActiveTime < 0.f)
entry->ActiveTime = 0.f;
entry->QueueDepth = diskPerformance.QueueDepth;
entry->SplitCount = diskPerformance.SplitCount;
entry->DiskIndex = diskPerformance.StorageDeviceNumber;
entry->DevicePresent = TRUE;
}
else
{
// Disk has been disconnected or dismounted.
PhInitializeDelta(&entry->BytesReadDelta);
PhInitializeDelta(&entry->BytesWrittenDelta);
PhInitializeDelta(&entry->ReadTimeDelta);
PhInitializeDelta(&entry->WriteTimeDelta);
PhInitializeDelta(&entry->IdleTimeDelta);
PhInitializeDelta(&entry->ReadCountDelta);
PhInitializeDelta(&entry->WriteCountDelta);
PhInitializeDelta(&entry->QueryTimeDelta);
entry->ResponseTime = 0;
entry->ActiveTime = 0.0f;
entry->QueueDepth = 0;
entry->SplitCount = 0;
entry->DiskIndex = ULONG_MAX;
entry->DevicePresent = FALSE;
PhClearReference(&entry->DiskIndexName);
}
if (runCount > 1)
{
// Delay the first query for the disk name, index and type.
// 1) This information is not needed until the user opens the sysinfo window.
// 2) Try not to query this information while opening the sysinfo window (e.g. delay).
// 3) Try not to query this information during startup (e.g. delay).
//
// Note: If the user opens the Sysinfo window before we query the disk info,
// we have a second check in diskgraph.c that queries the information on demand.
DiskDriveUpdateDeviceInfo(deviceHandle, entry);
}
NtClose(deviceHandle);
}
else
{
// Disk has been disconnected or dismounted.
PhInitializeDelta(&entry->BytesReadDelta);
PhInitializeDelta(&entry->BytesWrittenDelta);
PhInitializeDelta(&entry->ReadTimeDelta);
PhInitializeDelta(&entry->WriteTimeDelta);
PhInitializeDelta(&entry->IdleTimeDelta);
PhInitializeDelta(&entry->ReadCountDelta);
PhInitializeDelta(&entry->WriteCountDelta);
PhInitializeDelta(&entry->QueryTimeDelta);
entry->ResponseTime = 0;
entry->ActiveTime = 0.0f;
entry->QueueDepth = 0;
entry->SplitCount = 0;
entry->DiskIndex = ULONG_MAX;
entry->DevicePresent = FALSE;
PhClearReference(&entry->DiskIndexName);
}
if (!entry->HaveFirstSample)
{
// The first sample must be zero.
entry->BytesReadDelta.Delta = 0;
entry->BytesWrittenDelta.Delta = 0;
entry->HaveFirstSample = TRUE;
}
if (runCount != 0)
{
PhAddItemCircularBuffer_ULONG64(&entry->ReadBuffer, entry->BytesReadDelta.Delta);
PhAddItemCircularBuffer_ULONG64(&entry->WriteBuffer, entry->BytesWrittenDelta.Delta);
}
PhDereferenceObjectDeferDelete(entry);
}
PhReleaseQueuedLockShared(&DiskDrivesListLock);
runCount++;
}
VOID DiskDriveUpdateDeviceInfo(
_In_opt_ HANDLE DeviceHandle,
_In_ PDV_DISK_ENTRY DiskEntry
)
{
if (!DiskEntry->DiskName || DiskEntry->DiskIndex == ULONG_MAX)
{
HANDLE deviceHandle = NULL;
if (!DeviceHandle)
{
DiskDriveCreateHandle(&deviceHandle, DiskEntry->Id.DevicePath);
}
else
{
deviceHandle = DeviceHandle;
}
if (deviceHandle)
{
if (!DiskEntry->DiskName)
{
PPH_STRING diskName = NULL;
if (NT_SUCCESS(DiskDriveQueryDeviceInformation(deviceHandle, NULL, &diskName, NULL, NULL)))
{
DiskEntry->DiskName = diskName;
}
}
if (DiskEntry->DiskIndex == ULONG_MAX)
{
ULONG diskIndex = ULONG_MAX; // Note: Do not initialize to zero.
if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber(deviceHandle, &diskIndex, NULL)))
{
DiskEntry->DiskIndex = diskIndex;
}
}
if (!DeviceHandle)
{
NtClose(deviceHandle);
}
}
}
}
VOID InitializeDiskId(
_Out_ PDV_DISK_ID Id,
_In_ PPH_STRING DevicePath
)
{
PhSetReference(&Id->DevicePath, DevicePath);
}
VOID CopyDiskId(
_Out_ PDV_DISK_ID Destination,
_In_ PDV_DISK_ID Source
)
{
InitializeDiskId(
Destination,
Source->DevicePath
);
}
VOID DeleteDiskId(
_Inout_ PDV_DISK_ID Id
)
{
PhClearReference(&Id->DevicePath);
}
BOOLEAN EquivalentDiskId(
_In_ PDV_DISK_ID Id1,
_In_ PDV_DISK_ID Id2
)
{
return PhEqualString(Id1->DevicePath, Id2->DevicePath, TRUE);
}
PDV_DISK_ENTRY CreateDiskEntry(
_In_ PDV_DISK_ID Id
)
{
PDV_DISK_ENTRY entry;
entry = PhCreateObject(sizeof(DV_DISK_ENTRY), DiskDriveEntryType);
memset(entry, 0, sizeof(DV_DISK_ENTRY));
entry->DiskIndex = ULONG_MAX;
CopyDiskId(&entry->Id, Id);
PhInitializeCircularBuffer_ULONG64(&entry->ReadBuffer, PhGetIntegerSetting(L"SampleCount"));
PhInitializeCircularBuffer_ULONG64(&entry->WriteBuffer, PhGetIntegerSetting(L"SampleCount"));
PhAcquireQueuedLockExclusive(&DiskDrivesListLock);
PhAddItemList(DiskDrivesList, entry);
PhReleaseQueuedLockExclusive(&DiskDrivesListLock);
AddRemoveDeviceChangeCallback();
return entry;
}