summaryrefslogtreecommitdiffstats
path: root/include/iprt/cpuset.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--include/iprt/cpuset.h353
1 files changed, 353 insertions, 0 deletions
diff --git a/include/iprt/cpuset.h b/include/iprt/cpuset.h
new file mode 100644
index 00000000..c5882472
--- /dev/null
+++ b/include/iprt/cpuset.h
@@ -0,0 +1,353 @@
+/** @file
+ * IPRT - CPU Set.
+ */
+
+/*
+ * Copyright (C) 2008-2022 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 */
+