1
0
Fork 0
virtualbox/include/iprt/cpuset.h
Daniel Baumann df1bda4fe9
Adding upstream version 7.0.20-dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 09:56:04 +02:00

353 lines
8 KiB
C

/** @file
* IPRT - CPU Set.
*/
/*
* Copyright (C) 2008-2023 Oracle and/or its affiliates.
*
* This file is part of VirtualBox base platform packages, as
* available from https://www.virtualbox.org.
*
* 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, in version 3 of the
* License.
*
* 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, see <https://www.gnu.org/licenses>.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
* in the VirtualBox distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*
* SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
*/
#ifndef IPRT_INCLUDED_cpuset_h
#define IPRT_INCLUDED_cpuset_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif
#include <iprt/types.h>
#include <iprt/mp.h> /* RTMpCpuIdToSetIndex */
#include <iprt/asm.h>
RT_C_DECLS_BEGIN
/** @defgroup grp_rt_cpuset RTCpuSet - CPU Set
* @ingroup grp_rt
* @{
*/
/**
* Clear all CPUs.
*
* @returns pSet.
* @param pSet Pointer to the set.
*/
DECLINLINE(PRTCPUSET) RTCpuSetEmpty(PRTCPUSET pSet)
{
size_t i;
for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++)
pSet->bmSet[i] = 0;
return pSet;
}
/**
* Set all CPUs.
*
* @returns pSet.
* @param pSet Pointer to the set.
*/
DECLINLINE(PRTCPUSET) RTCpuSetFill(PRTCPUSET pSet)
{
size_t i;
for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++)
pSet->bmSet[i] = UINT64_MAX;
return pSet;
}
/**
* Copies one set to another.
*
* @param pDst Pointer to the destination set.
* @param pSrc Pointer to the source set.
*/
DECLINLINE(void) RTCpuSetCopy(PRTCPUSET pDst, PRTCPUSET pSrc)
{
size_t i;
for (i = 0; i < RT_ELEMENTS(pDst->bmSet); i++)
pDst->bmSet[i] = pSrc->bmSet[i];
}
/**
* ANDs the given CPU set with another.
*
* @returns pSet.
* @param pSet Pointer to the set.
* @param pAndMaskSet Pointer to the AND-mask set.
*/
DECLINLINE(PRTCPUSET) RTCpuSetAnd(PRTCPUSET pSet, PRTCPUSET pAndMaskSet)
{
size_t i;
for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++)
ASMAtomicAndU64((volatile uint64_t *)&pSet->bmSet[i], pAndMaskSet->bmSet[i]);
return pSet;
}
/**
* Adds a CPU given by its identifier to the set.
*
* @returns 0 on success, -1 if idCpu isn't valid.
* @param pSet Pointer to the set.
* @param idCpu The identifier of the CPU to add.
* @remarks The modification is atomic.
*/
DECLINLINE(int) RTCpuSetAdd(PRTCPUSET pSet, RTCPUID idCpu)
{
int iCpu = RTMpCpuIdToSetIndex(idCpu);
if (RT_LIKELY(iCpu >= 0))
{
ASMAtomicBitSet(pSet, iCpu);
return 0;
}
return -1;
}
/**
* Adds a CPU given by its identifier to the set.
*
* @returns 0 on success, -1 if iCpu isn't valid.
* @param pSet Pointer to the set.
* @param iCpu The index of the CPU to add.
* @remarks The modification is atomic.
*/
DECLINLINE(int) RTCpuSetAddByIndex(PRTCPUSET pSet, int iCpu)
{
if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS))
{
ASMAtomicBitSet(pSet, iCpu);
return 0;
}
return -1;
}
/**
* Removes a CPU given by its identifier from the set.
*
* @returns 0 on success, -1 if idCpu isn't valid.
* @param pSet Pointer to the set.
* @param idCpu The identifier of the CPU to delete.
* @remarks The modification is atomic.
*/
DECLINLINE(int) RTCpuSetDel(PRTCPUSET pSet, RTCPUID idCpu)
{
int iCpu = RTMpCpuIdToSetIndex(idCpu);
if (RT_LIKELY(iCpu >= 0))
{
ASMAtomicBitClear(pSet, iCpu);
return 0;
}
return -1;
}
/**
* Removes a CPU given by its index from the set.
*
* @returns 0 on success, -1 if iCpu isn't valid.
* @param pSet Pointer to the set.
* @param iCpu The index of the CPU to delete.
* @remarks The modification is atomic.
*/
DECLINLINE(int) RTCpuSetDelByIndex(PRTCPUSET pSet, int iCpu)
{
if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS))
{
ASMAtomicBitClear(pSet, iCpu);
return 0;
}
return -1;
}
/**
* Checks if a CPU given by its identifier is a member of the set.
*
* @returns true / false accordingly.
* @param pSet Pointer to the set.
* @param idCpu The identifier of the CPU to look for.
* @remarks The test is atomic.
*/
DECLINLINE(bool) RTCpuSetIsMember(PCRTCPUSET pSet, RTCPUID idCpu)
{
int iCpu = RTMpCpuIdToSetIndex(idCpu);
if (RT_LIKELY(iCpu >= 0))
return ASMBitTest((volatile void *)pSet, iCpu);
return false;
}
/**
* Checks if a CPU given by its index is a member of the set.
*
* @returns true / false accordingly.
* @param pSet Pointer to the set.
* @param iCpu The index of the CPU in the set.
* @remarks The test is atomic.
*/
DECLINLINE(bool) RTCpuSetIsMemberByIndex(PCRTCPUSET pSet, int iCpu)
{
if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS))
return ASMBitTest((volatile void *)pSet, iCpu);
return false;
}
/**
* Checks if the two sets match or not.
*
* @returns true / false accordingly.
* @param pSet1 The first set.
* @param pSet2 The second set.
*/
DECLINLINE(bool) RTCpuSetIsEqual(PCRTCPUSET pSet1, PCRTCPUSET pSet2)
{
size_t i;
for (i = 0; i < RT_ELEMENTS(pSet1->bmSet); i++)
if (pSet1->bmSet[i] != pSet2->bmSet[i])
return false;
return true;
}
/**
* Checks if the CPU set is empty or not.
*
* @returns true / false accordingly.
* @param pSet Pointer to the set.
*/
DECLINLINE(bool) RTCpuSetIsEmpty(PRTCPUSET pSet)
{
size_t i;
for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++)
if (pSet->bmSet[i])
return false;
return true;
}
/**
* Converts the CPU set to a 64-bit mask.
*
* @returns The mask.
* @param pSet Pointer to the set.
* @remarks Use with extreme care as it may lose information!
*/
DECLINLINE(uint64_t) RTCpuSetToU64(PCRTCPUSET pSet)
{
return pSet->bmSet[0];
}
/**
* Initializes the CPU set from a 64-bit mask.
*
* @param pSet Pointer to the set.
* @param fMask The mask.
*/
DECLINLINE(PRTCPUSET) RTCpuSetFromU64(PRTCPUSET pSet, uint64_t fMask)
{
size_t i;
pSet->bmSet[0] = fMask;
for (i = 1; i < RT_ELEMENTS(pSet->bmSet); i++)
pSet->bmSet[i] = 0;
return pSet;
}
/**
* Count the CPUs in the set.
*
* @returns CPU count.
* @param pSet Pointer to the set.
*/
DECLINLINE(int) RTCpuSetCount(PCRTCPUSET pSet)
{
int cCpus = 0;
size_t i;
for (i = 0; i < RT_ELEMENTS(pSet->bmSet); i++)
{
uint64_t u64 = pSet->bmSet[i];
if (u64 != 0)
{
unsigned iCpu = 64;
while (iCpu-- > 0)
{
if (u64 & 1)
cCpus++;
u64 >>= 1;
}
}
}
return cCpus;
}
/**
* Get the highest set index.
*
* @returns The higest set index, -1 if all bits are clear.
* @param pSet Pointer to the set.
*/
DECLINLINE(int) RTCpuLastIndex(PCRTCPUSET pSet)
{
size_t i = RT_ELEMENTS(pSet->bmSet);
while (i-- > 0)
{
uint64_t u64 = pSet->bmSet[i];
if (u64)
{
/* There are more efficient ways to do this in asm.h... */
unsigned iBit;
for (iBit = 63; iBit > 0; iBit--)
{
if (u64 & RT_BIT_64(63))
break;
u64 <<= 1;
}
return (int)i * 64 + (int)iBit;
}
}
return 0;
}
/** @} */
RT_C_DECLS_END
#endif /* !IPRT_INCLUDED_cpuset_h */