VirtualBox

Changeset 10452 in vbox for trunk/src/VBox/Runtime/r3


Ignore:
Timestamp:
Jul 10, 2008 2:43:48 AM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
33119
Message:

Cooked up some basic RTMp for darwin.

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/darwin/mp-darwin.cpp

    r10451 r10452  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Multiprocessor, Linux.
     3 * IPRT - Multiprocessor, Darwin.
    44 */
    55
     
    3434*******************************************************************************/
    3535#define LOG_GROUP RTLOGGROUP_SYSTEM
     36#include <iprt/types.h>
     37
    3638#include <unistd.h>
    3739#include <stdio.h>
     
    4749
    4850
    49 /** @todo move the rtLinuxSysFs* bits into sysfs.cpp and sysfs.h. */
    50 
    51 /**
    52  * Checks if a sysfs file (or directory, device, symlink, whatever) exists.
    53  *
    54  * @returns true / false, errno is preserved.
    55  * @param   pszFormat   The name format, without "/sys/".
    56  * @param   va          The format args.
    57  */
    58 bool rtLinuxSysFsExistsV(const char *pszFormat, va_list va)
    59 {
    60     int iSavedErrno = errno;
    61 
    62     /*
    63      * Construct the filename and call stat.
    64      */
    65     char szFilename[128];
    66     static const size_t cchPrefix = sizeof("/sys/") - 1;
    67     strcpy(szFilename, "/sys/");
    68     size_t cch = RTStrPrintfV(&szFilename[cchPrefix], sizeof(szFilename) - cchPrefix, pszFormat, va);
    69     Assert(cch < sizeof(szFilename) - cchPrefix - 1);
    70 
    71     struct stat st;
    72     bool fRet = stat(szFilename, &st) == 0;
    73 
    74     errno = iSavedErrno;
    75     return fRet;
    76 }
    77 
    78 /**
    79  * Checks if a sysfs file (or directory, device, symlink, whatever) exists.
    80  *
    81  * @returns true / false, errno is preserved.
    82  * @param   pszFormat   The name format, without "/sys/".
    83  * @param   ...         The format args.
    84  */
    85 bool rtLinuxSysFsExists(const char *pszFormat, ...)
    86 {
    87     va_list va;
    88     va_start(va, pszFormat);
    89     bool fRet = rtLinuxSysFsExistsV(pszFormat, va);
    90     va_end(va);
    91     return fRet;
    92 }
    93 
    94 
    95 /**
    96  * Opens a sysfs file.
    97  *
    98  * @returns The file descriptor. -1 and errno on failure.
    99  * @param   pszFormat   The name format, without "/sys/".
    100  * @param   va          The format args.
    101  */
    102 int rtLinuxSysFsOpenV(const char *pszFormat, va_list va)
    103 {
    104     /*
    105      * Construct the filename and call open.
    106      */
    107     char szFilename[128];
    108     static const size_t cchPrefix = sizeof("/sys/") - 1;
    109     strcpy(szFilename, "/sys/");
    110     size_t cch = RTStrPrintfV(&szFilename[cchPrefix], sizeof(szFilename) - cchPrefix, pszFormat, va);
    111     Assert(cch < sizeof(szFilename) - cchPrefix - 1);
    112 
    113     return open(szFilename, O_RDONLY, 0);
    114 }
    115 
    116 
    117 /**
    118  * Opens a sysfs file.
    119  *
    120  * @returns The file descriptor. -1 and errno on failure.
    121  * @param   pszFormat   The name format, without "/sys/".
    122  * @param   ...         The format args.
    123  */
    124 int rtLinuxSysFsOpen(const char *pszFormat, ...)
    125 {
    126     va_list va;
    127     va_start(va, pszFormat);
    128     int fd = rtLinuxSysFsOpenV(pszFormat, va);
    129     va_end(va);
    130     return fd;
    131 }
    132 
    133 
    134 /**
    135  * Closes a file opened with rtLinuxSysFsOpen or rtLinuxSysFsOpenV.
    136  *
    137  * @param   fd
    138  */
    139 void rtLinuxSysFsClose(int fd)
    140 {
    141     int iSavedErrno = errno;
    142     close(fd);
    143     errno = iSavedErrno;
    144 }
    145 
    146 
    147 /**
    148  * Closes a file opened with rtLinuxSysFsOpen or rtLinuxSysFsOpenV.
    149  *
    150  * @returns The number of bytes read. -1 and errno on failure.
    151  * @param   fd          The file descriptor returned by rtLinuxSysFsOpen or rtLinuxSysFsOpenV.
    152  * @param   pszBuf      Where to store the string.
    153  * @param   cchBuf      The size of the buffer. Must be at least 2 bytes.
    154  */
    155 ssize_t rtLinuxSysFsReadStr(int fd, char *pszBuf, size_t cchBuf)
    156 {
    157     Assert(cchBuf > 1);
    158     ssize_t cchRead = read(fd, pszBuf, cchBuf - 1);
    159     pszBuf[cchRead >= 0 ? cchRead : 0] = '\0';
    160     return cchRead;
    161 }
    162 
    163 
    164 /**
    165  * Reads a sysfs file.
    166  *
    167  * @returns 64-bit signed value on success, -1 and errno on failure.
    168  * @param   uBase       The number base, 0 for autodetect.
    169  * @param   pszFormat   The filename format, without "/sys/".
    170  * @param   va          Format args.
    171  */
    172 int64_t rtLinuxSysFsReadIntFileV(unsigned uBase, const char *pszFormat, va_list va)
    173 {
    174     int fd = rtLinuxSysFsOpenV(pszFormat, va);
    175     if (fd == -1)
    176         return -1;
    177 
    178     int64_t i64Ret = -1;
    179     char szNum[128];
    180     ssize_t cchNum = rtLinuxSysFsReadStr(fd, szNum, sizeof(szNum));
    181     if (cchNum > 0)
    182     {
    183         int rc = RTStrToInt64Ex(szNum, NULL, uBase, &i64Ret);
    184         if (RT_FAILURE(rc))
    185         {
    186             i64Ret = -1;
    187             errno = -ETXTBSY; /* just something that won't happen at read / open. */
    188         }
    189     }
    190     else if (cchNum == 0)
    191         errno = -ETXTBSY; /* just something that won't happen at read / open. */
    192 
    193     rtLinuxSysFsClose(fd);
    194     return i64Ret;
    195 }
    196 
    197 
    198 /**
    199  * Reads a sysfs file.
    200  *
    201  * @returns 64-bit signed value on success, -1 and errno on failure.
    202  * @param   uBase       The number base, 0 for autodetect.
    203  * @param   pszFormat   The filename format, without "/sys/".
    204  * @param   ...         Format args.
    205  */
    206 static int64_t rtLinuxSysFsReadIntFile(unsigned uBase, const char *pszFormat, ...)
    207 {
    208     va_list va;
    209     va_start(va, pszFormat);
    210     int64_t i64Ret = rtLinuxSysFsReadIntFileV(uBase, pszFormat, va);
    211     va_end(va);
    212     return i64Ret;
    213 }
    214 
    215 
    21651/**
    21752 * Internal worker that determins the max possible CPU count.
     
    21954 * @returns Max cpus.
    22055 */
    221 static RTCPUID rtMpLinuxMaxCpus(void)
     56static RTCPUID rtMpDarwinMaxCpus(void)
    22257{
    223 #if 0 /* this doesn't do the right thing :-/ */
    224     int cMax = sysconf(_SC_NPROCESSORS_CONF);
    225     Assert(cMax >= 1);
    226     return cMax;
    227 #else
    228     static uint32_t s_cMax = 0;
    229     if (!s_cMax)
    230     {
    231         int cMax = 1;
    232         for (unsigned iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
    233             if (rtLinuxSysFsExists("devices/system/cpu/cpu%d", iCpu))
    234                 cMax = iCpu + 1;
    235         ASMAtomicUoWriteU32((uint32_t volatile *)&s_cMax, cMax);
    236         return cMax;
    237     }
    238     return s_cMax;
    239 #endif
    240 }
    241 
    242 /**
    243  * Internal worker that picks the processor speed in MHz from /proc/cpuinfo.
    244  *
    245  * @returns CPU frequency.
    246  */
    247 static uint32_t rtMpLinuxGetFrequency(RTCPUID idCpu)
    248 {
    249     FILE *f = fopen("/proc/cpuinfo", "r");
    250     if (!f)
    251         return 0;
    252 
    253     char sz[256];
    254     char *psz = NULL;
    255     RTCPUID idCpuFound = NIL_RTCPUID;
    256     uint32_t freq = 0;
    257     while (fgets(sz, sizeof(sz), f))
    258     {
    259         if (   !strncmp(sz, "processor", 9)
    260             && (sz[10] == ' ' || sz[10] == '\t' || sz[10] == ':')
    261             && (psz = strchr(sz, ':')))
    262         {
    263             psz += 2;
    264             int64_t iCpu;
    265             int rc = RTStrToInt64Ex(psz, NULL, 0, &iCpu);
    266             if (RT_SUCCESS(rc))
    267                 idCpuFound = iCpu;
    268         }
    269         else if (   idCpu == idCpuFound
    270                  && !strncmp(sz, "cpu MHz", 7)
    271                  && (sz[10] == ' ' || sz[10] == '\t' || sz[10] == ':')
    272                  && (psz = strchr(sz, ':')))
    273         {
    274             psz += 2;
    275             int64_t v;
    276             int rc = RTStrToInt64Ex(psz, &psz, 0, &v);
    277             if (RT_SUCCESS(rc))
    278             {
    279                 freq = v;
    280                 break;
    281             }
    282         }
    283     }
    284     fclose(f);
    285     return freq;
     58    int aiMib[2];
     59    aiMib[0] = CTL_HW;
     60    aiMib[1] = HW_NCPU;
     61    int cCpus = -1;
     62    size_t cb = sizeof(cCpus);
     63    int rc = sysctl(aiMib, ELEMENTS(aiMib), &cCpus, &cb, NULL, 0);
     64    if (rc != -1 && cCpus >= 1)
     65        return cCpus;
     66    AssertFailed();
     67    return 1;
    28668}
    28769
     
    29173RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
    29274{
    293     return idCpu < rtMpLinuxMaxCpus() ? idCpu : -1;
     75    return idCpu < rtMpDarwinMaxCpus() ? idCpu : -1;
    29476}
    29577
     
    29779RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
    29880{
    299     return (unsigned)iCpu < rtMpLinuxMaxCpus() ? iCpu : NIL_RTCPUID;
     81    return (unsigned)iCpu < rtMpDarwinMaxCpus() ? iCpu : NIL_RTCPUID;
    30082}
    30183
     
    30385RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
    30486{
    305     return rtMpLinuxMaxCpus() - 1;
     87    return rtMpDarwinMaxCpus() - 1;
    30688}
    30789
     
    30991RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
    31092{
    311     /** @todo check if there is a simpler interface than this... */
    312     int i = rtLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/online", (int)idCpu);
    313     if (    i == -1
    314         &&  rtLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu))
    315     {
    316         Assert(!rtLinuxSysFsExists("devices/system/cpu/cpu%d/online", (int)idCpu));
    317         i = 1;
    318     }
    319 
    320     Assert(i == 0 || i == -1 || i == 1);
    321     return i != 0 && i != -1;
     93#if 1
     94    return RTMpIsCpuPossible(idCpu);
     95#else
     96    /** @todo proper ring-3 support on darwin, see #3014. */
     97#endif
    32298}
    32399
     
    325101RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
    326102{
    327     /** @todo check this up with hotplugging! */
    328     return rtLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu);
     103    return idCpu != NIL_RTCPUID
     104        && idCpu < rtMpDarwinMaxCpus();
    329105}
    330106
     
    332108RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
    333109{
     110#if 0
     111    RTCPUID cCpus = rtMpDarwinMaxCpus();
     112    return RTCpuSetFromU64(RT_BIT_64(cCpus) - 1);
     113
     114#else
    334115    RTCpuSetEmpty(pSet);
    335     RTCPUID cMax = rtMpLinuxMaxCpus();
     116    RTCPUID cMax = rtMpDarwinMaxCpus();
    336117    for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
    337118        if (RTMpIsCpuPossible(idCpu))
    338119            RTCpuSetAdd(pSet, idCpu);
    339120    return pSet;
     121#endif
    340122}
    341123
     
    343125RTDECL(RTCPUID) RTMpGetCount(void)
    344126{
    345     RTCPUSET Set;
    346     RTMpGetSet(&Set);
    347     return RTCpuSetCount(&Set);
     127    return rtMpDarwinMaxCpus();
    348128}
    349129
     
    351131RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
    352132{
     133#if 1
     134    return RTMpGetSet(pSet);
     135#else
    353136    RTCpuSetEmpty(pSet);
    354     RTCPUID cMax = rtMpLinuxMaxCpus();
     137    RTCPUID cMax = rtMpDarwinMaxCpus();
    355138    for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
    356139        if (RTMpIsCpuOnline(idCpu))
    357140            RTCpuSetAdd(pSet, idCpu);
    358141    return pSet;
     142#endif
    359143}
    360144
     
    370154RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu)
    371155{
    372     int64_t kHz = rtLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq", (int)idCpu);
    373     if (kHz == -1)
    374     {
    375         /* The file may be just unreadable - in that case use plan B, i.e.
    376          * /proc/cpuinfo to get the data we want. The assumption is that if
    377          * cpuinfo_cur_freq doesn't exist then the speed won't change, and
    378          * thus cur == max. If it does exist then cpuinfo contains the
    379          * current frequency. */
    380         kHz = rtMpLinuxGetFrequency(idCpu) * 1000;
    381     }
    382     return (kHz + 999) / 1000;
     156    /** @todo figure out how to get the current cpu speed on darwin. */
     157    return 0;
    383158}
    384159
     
    386161RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu)
    387162{
    388     int64_t kHz = rtLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu);
    389     if (kHz == -1)
    390     {
    391         /* Check if the file isn't there - if it is there, then /proc/cpuinfo
    392          * would provide current frequency information, which is wrong. */
    393         if (!rtLinuxSysFsExists("devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu))
    394             kHz = rtMpLinuxGetFrequency(idCpu) * 1000;
    395         else
    396             kHz = 0;
    397     }
    398     return (kHz + 999) / 1000;
     163    if (!RTMpIsCpuOnline(idCpu))
     164        return 0;
     165
     166    /*
     167     * Try the 'hw.cpufrequency_max' one.
     168     */
     169    uint64_t CpuFrequencyMax = 0;
     170    size_t cb = sizeof(CpuFrequencyMax);
     171    int rc = sysctlbyname("hw.cpufrequency_max", &CpuFrequencyMax, &cb, NULL, 0);
     172    if (!rc)
     173        return CpuFrequencyMax + 999999 / 1000000;
     174
     175    /*
     176     * Use the depricated one.
     177     */
     178    int aiMib[2];
     179    aiMib[0] = CTL_HW;
     180    aiMib[1] = HW_CPU_FREQ;
     181    int cCpus = -1;
     182    cb = sizeof(cCpus);
     183    rc = sysctl(aiMib, ELEMENTS(aiMib), &cCpus, &cb, NULL, 0);
     184    if (rc != -1 && cCpus >= 1)
     185        return cCpus;
     186    AssertFailed();
     187    return 0;
    399188}
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette