1  /** @file


2  * IPRT  CPU Set.


3  */


4 


5  /*


6  * Copyright (C) 20082023 Oracle and/or its affiliates.


7  *


8  * This file is part of VirtualBox base platform packages, as


9  * available from https://www.virtualbox.org.


10  *


11  * This program is free software; you can redistribute it and/or


12  * modify it under the terms of the GNU General Public License


13  * as published by the Free Software Foundation, in version 3 of the


14  * License.


15  *


16  * This program is distributed in the hope that it will be useful, but


17  * WITHOUT ANY WARRANTY; without even the implied warranty of


18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU


19  * General Public License for more details.


20  *


21  * You should have received a copy of the GNU General Public License


22  * along with this program; if not, see <https://www.gnu.org/licenses>.


23  *


24  * The contents of this file may alternatively be used under the terms


25  * of the Common Development and Distribution License Version 1.0


26  * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included


27  * in the VirtualBox distribution, in which case the provisions of the


28  * CDDL are applicable instead of those of the GPL.


29  *


30  * You may elect to license modified versions of this file under the


31  * terms and conditions of either the GPL or the CDDL or both.


32  *


33  * SPDXLicenseIdentifier: GPL3.0only OR CDDL1.0


34  */


35 


36  #ifndef IPRT_INCLUDED_cpuset_h


37  #define IPRT_INCLUDED_cpuset_h


38  #ifndef RT_WITHOUT_PRAGMA_ONCE


39  # pragma once


40  #endif


41 


42  #include <iprt/types.h>


43  #include <iprt/mp.h> /* RTMpCpuIdToSetIndex */


44  #include <iprt/asmmem.h> /* not necessary, but avoids trouble */


45  #include <iprt/asm.h>


46 


47 


48  RT_C_DECLS_BEGIN


49 


50  /** @defgroup grp_rt_cpuset RTCpuSet  CPU Set


51  * @ingroup grp_rt


52  * @{


53  */


54 


55 


56  /**


57  * Clear all CPUs.


58  *


59  * @returns pSet.


60  * @param pSet Pointer to the set.


61  */


62  DECLINLINE(PRTCPUSET) RTCpuSetEmpty(PRTCPUSET pSet)


63  {


64  size_t i;


65  for (i = 0; i < RT_ELEMENTS(pSet>bmSet); i++)


66  pSet>bmSet[i] = 0;


67  return pSet;


68  }


69 


70 


71  /**


72  * Set all CPUs.


73  *


74  * @returns pSet.


75  * @param pSet Pointer to the set.


76  */


77  DECLINLINE(PRTCPUSET) RTCpuSetFill(PRTCPUSET pSet)


78  {


79  size_t i;


80  for (i = 0; i < RT_ELEMENTS(pSet>bmSet); i++)


81  pSet>bmSet[i] = UINT64_MAX;


82  return pSet;


83  }


84 


85 


86  /**


87  * Copies one set to another.


88  *


89  * @param pDst Pointer to the destination set.


90  * @param pSrc Pointer to the source set.


91  */


92  DECLINLINE(void) RTCpuSetCopy(PRTCPUSET pDst, PRTCPUSET pSrc)


93  {


94  size_t i;


95  for (i = 0; i < RT_ELEMENTS(pDst>bmSet); i++)


96  pDst>bmSet[i] = pSrc>bmSet[i];


97  }


98 


99 


100  /**


101  * ANDs the given CPU set with another.


102  *


103  * @returns pSet.


104  * @param pSet Pointer to the set.


105  * @param pAndMaskSet Pointer to the ANDmask set.


106  */


107  DECLINLINE(PRTCPUSET) RTCpuSetAnd(PRTCPUSET pSet, PRTCPUSET pAndMaskSet)


108  {


109  size_t i;


110  for (i = 0; i < RT_ELEMENTS(pSet>bmSet); i++)


111  ASMAtomicAndU64((volatile uint64_t *)&pSet>bmSet[i], pAndMaskSet>bmSet[i]);


112  return pSet;


113  }


114 


115 


116  /**


117  * Adds a CPU given by its identifier to the set.


118  *


119  * @returns 0 on success, 1 if idCpu isn't valid.


120  * @param pSet Pointer to the set.


121  * @param idCpu The identifier of the CPU to add.


122  * @remarks The modification is atomic.


123  */


124  DECLINLINE(int) RTCpuSetAdd(PRTCPUSET pSet, RTCPUID idCpu)


125  {


126  int iCpu = RTMpCpuIdToSetIndex(idCpu);


127  if (RT_LIKELY(iCpu >= 0))


128  {


129  ASMAtomicBitSet(pSet, iCpu);


130  return 0;


131  }


132  return 1;


133  }


134 


135 


136  /**


137  * Adds a CPU given by its identifier to the set.


138  *


139  * @returns 0 on success, 1 if iCpu isn't valid.


140  * @param pSet Pointer to the set.


141  * @param iCpu The index of the CPU to add.


142  * @remarks The modification is atomic.


143  */


144  DECLINLINE(int) RTCpuSetAddByIndex(PRTCPUSET pSet, int iCpu)


145  {


146  if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS))


147  {


148  ASMAtomicBitSet(pSet, iCpu);


149  return 0;


150  }


151  return 1;


152  }


153 


154 


155  /**


156  * Removes a CPU given by its identifier from the set.


157  *


158  * @returns 0 on success, 1 if idCpu isn't valid.


159  * @param pSet Pointer to the set.


160  * @param idCpu The identifier of the CPU to delete.


161  * @remarks The modification is atomic.


162  */


163  DECLINLINE(int) RTCpuSetDel(PRTCPUSET pSet, RTCPUID idCpu)


164  {


165  int iCpu = RTMpCpuIdToSetIndex(idCpu);


166  if (RT_LIKELY(iCpu >= 0))


167  {


168  ASMAtomicBitClear(pSet, iCpu);


169  return 0;


170  }


171  return 1;


172  }


173 


174 


175  /**


176  * Removes a CPU given by its index from the set.


177  *


178  * @returns 0 on success, 1 if iCpu isn't valid.


179  * @param pSet Pointer to the set.


180  * @param iCpu The index of the CPU to delete.


181  * @remarks The modification is atomic.


182  */


183  DECLINLINE(int) RTCpuSetDelByIndex(PRTCPUSET pSet, int iCpu)


184  {


185  if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS))


186  {


187  ASMAtomicBitClear(pSet, iCpu);


188  return 0;


189  }


190  return 1;


191  }


192 


193 


194  /**


195  * Checks if a CPU given by its identifier is a member of the set.


196  *


197  * @returns true / false accordingly.


198  * @param pSet Pointer to the set.


199  * @param idCpu The identifier of the CPU to look for.


200  * @remarks The test is atomic.


201  */


202  DECLINLINE(bool) RTCpuSetIsMember(PCRTCPUSET pSet, RTCPUID idCpu)


203  {


204  int iCpu = RTMpCpuIdToSetIndex(idCpu);


205  if (RT_LIKELY(iCpu >= 0))


206  return ASMBitTest((volatile void *)pSet, iCpu);


207  return false;


208  }


209 


210 


211  /**


212  * Checks if a CPU given by its index is a member of the set.


213  *


214  * @returns true / false accordingly.


215  * @param pSet Pointer to the set.


216  * @param iCpu The index of the CPU in the set.


217  * @remarks The test is atomic.


218  */


219  DECLINLINE(bool) RTCpuSetIsMemberByIndex(PCRTCPUSET pSet, int iCpu)


220  {


221  if (RT_LIKELY((unsigned)iCpu < RTCPUSET_MAX_CPUS))


222  return ASMBitTest((volatile void *)pSet, iCpu);


223  return false;


224  }


225 


226 


227  /**


228  * Checks if the two sets match or not.


229  *


230  * @returns true / false accordingly.


231  * @param pSet1 The first set.


232  * @param pSet2 The second set.


233  */


234  DECLINLINE(bool) RTCpuSetIsEqual(PCRTCPUSET pSet1, PCRTCPUSET pSet2)


235  {


236  size_t i;


237  for (i = 0; i < RT_ELEMENTS(pSet1>bmSet); i++)


238  if (pSet1>bmSet[i] != pSet2>bmSet[i])


239  return false;


240  return true;


241  }


242 


243 


244  /**


245  * Checks if the CPU set is empty or not.


246  *


247  * @returns true / false accordingly.


248  * @param pSet Pointer to the set.


249  */


250  DECLINLINE(bool) RTCpuSetIsEmpty(PRTCPUSET pSet)


251  {


252  size_t i;


253  for (i = 0; i < RT_ELEMENTS(pSet>bmSet); i++)


254  if (pSet>bmSet[i])


255  return false;


256  return true;


257  }


258 


259 


260  /**


261  * Converts the CPU set to a 64bit mask.


262  *


263  * @returns The mask.


264  * @param pSet Pointer to the set.


265  * @remarks Use with extreme care as it may lose information!


266  */


267  DECLINLINE(uint64_t) RTCpuSetToU64(PCRTCPUSET pSet)


268  {


269  return pSet>bmSet[0];


270  }


271 


272 


273  /**


274  * Initializes the CPU set from a 64bit mask.


275  *


276  * @param pSet Pointer to the set.


277  * @param fMask The mask.


278  */


279  DECLINLINE(PRTCPUSET) RTCpuSetFromU64(PRTCPUSET pSet, uint64_t fMask)


280  {


281  size_t i;


282 


283  pSet>bmSet[0] = fMask;


284  for (i = 1; i < RT_ELEMENTS(pSet>bmSet); i++)


285  pSet>bmSet[i] = 0;


286 


287  return pSet;


288  }


289 


290 


291  /**


292  * Count the CPUs in the set.


293  *


294  * @returns CPU count.


295  * @param pSet Pointer to the set.


296  */


297  DECLINLINE(int) RTCpuSetCount(PCRTCPUSET pSet)


298  {


299  int cCpus = 0;


300  size_t i;


301 


302  for (i = 0; i < RT_ELEMENTS(pSet>bmSet); i++)


303  {


304  uint64_t u64 = pSet>bmSet[i];


305  if (u64 != 0)


306  {


307  unsigned iCpu = 64;


308  while (iCpu > 0)


309  {


310  if (u64 & 1)


311  cCpus++;


312  u64 >>= 1;


313  }


314  }


315  }


316  return cCpus;


317  }


318 


319 


320  /**


321  * Get the highest set index.


322  *


323  * @returns The higest set index, 1 if all bits are clear.


324  * @param pSet Pointer to the set.


325  */


326  DECLINLINE(int) RTCpuLastIndex(PCRTCPUSET pSet)


327  {


328  size_t i = RT_ELEMENTS(pSet>bmSet);


329  while (i > 0)


330  {


331  uint64_t u64 = pSet>bmSet[i];


332  if (u64)


333  {


334  /* There are more efficient ways to do this in asm.h... */


335  unsigned iBit;


336  for (iBit = 63; iBit > 0; iBit)


337  {


338  if (u64 & RT_BIT_64(63))


339  break;


340  u64 <<= 1;


341  }


342  return (int)i * 64 + (int)iBit;


343  }


344  }


345  return 0;


346  }


347 


348 


349  /** @} */


350 


351  RT_C_DECLS_END


352 


353  #endif /* !IPRT_INCLUDED_cpuset_h */


354 

