Source
xxxxxxxxxx
/* Check if GetActiveProcessorGroupCount() is available. See comments in get_cpu_num_win32() for details. */
/*
** Zabbix
** Copyright (C) 2001-2023 Zabbix SIA
**
** This program 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 2 of the License, or
** (at your option) any later version.
**
** This program 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 this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
/* shortcut to avoid extra verbosity */
typedef PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX PSYS_LPI_EX;
/* pointer to GetLogicalProcessorInformationEx(), it's not guaranteed to be available */
typedef BOOL (WINAPI *GETLPIEX)(LOGICAL_PROCESSOR_RELATIONSHIP, PSYS_LPI_EX, PDWORD);
static GETLPIEX get_lpiex;
/******************************************************************************
* *
* Purpose: find number of active logical CPUs *
* *
* Return value: number of CPUs or 0 on failure *
* *
******************************************************************************/
int get_cpu_num_win32(void)
{
/* pointer to GetActiveProcessorCount() */
typedef DWORD (WINAPI *GETACTIVEPC)(WORD);
ZBX_THREAD_LOCAL static GETACTIVEPC get_act;
SYSTEM_INFO sysInfo;
PSYS_LPI_EX buffer = NULL;
int cpu_count = 0;
/* The rationale for checking dynamically if specific functions are implemented */
/* in kernel32.lib is because these may not be available in certain Windows versions. */
/* E.g. GetActiveProcessorCount() is available from Windows 7 onward (and not in Windows Vista or XP) */
/* We can't resolve this using conditional compilation unless we release multiple agents */
/* targeting different sets of Windows APIs. */
/* First, let's try GetLogicalProcessorInformationEx() method. It's the most reliable way */
/* because it counts logical CPUs (aka threads) regardless of whether the application is */
/* 32 or 64-bit. GetActiveProcessorCount() may return incorrect value (e.g. 64 CPUs for systems */
/* with 128 CPUs) if executed under WoW64. */
if (NULL == get_lpiex)
{
get_lpiex = (GETLPIEX)GetProcAddress(GetModuleHandle(L"kernel32.dll"),
"GetLogicalProcessorInformationEx");
}
if (NULL != get_lpiex)
{
DWORD buffer_length = 0;
/* first run with empty arguments to figure the buffer length */
if (get_lpiex(RelationProcessorCore, NULL, &buffer_length) ||
ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
goto fallback;
}
buffer = (PSYS_LPI_EX)zbx_malloc(buffer, (size_t)buffer_length);
if (get_lpiex(RelationProcessorCore, buffer, &buffer_length))
{
unsigned int i;
PSYS_LPI_EX ptr;
for (i = 0; i < buffer_length; i += (unsigned int)ptr->Size)
{
ptr = (PSYS_LPI_EX)((PBYTE)buffer + i);
for (WORD group = 0; group < ptr->Processor.GroupCount; group++)
{
for (KAFFINITY mask = ptr->Processor.GroupMask[group].Mask; mask != 0;