Changeset 10452 in vbox for trunk/src/VBox/Runtime/r3
- Timestamp:
- Jul 10, 2008 2:43:48 AM (17 years ago)
- svn:sync-xref-src-repo-rev:
- 33119
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/darwin/mp-darwin.cpp
r10451 r10452 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Multiprocessor, Linux.3 * IPRT - Multiprocessor, Darwin. 4 4 */ 5 5 … … 34 34 *******************************************************************************/ 35 35 #define LOG_GROUP RTLOGGROUP_SYSTEM 36 #include <iprt/types.h> 37 36 38 #include <unistd.h> 37 39 #include <stdio.h> … … 47 49 48 50 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 fd138 */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 216 51 /** 217 52 * Internal worker that determins the max possible CPU count. … … 219 54 * @returns Max cpus. 220 55 */ 221 static RTCPUID rtMp LinuxMaxCpus(void)56 static RTCPUID rtMpDarwinMaxCpus(void) 222 57 { 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; 286 68 } 287 69 … … 291 73 RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu) 292 74 { 293 return idCpu < rtMp LinuxMaxCpus() ? idCpu : -1;75 return idCpu < rtMpDarwinMaxCpus() ? idCpu : -1; 294 76 } 295 77 … … 297 79 RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu) 298 80 { 299 return (unsigned)iCpu < rtMp LinuxMaxCpus() ? iCpu : NIL_RTCPUID;81 return (unsigned)iCpu < rtMpDarwinMaxCpus() ? iCpu : NIL_RTCPUID; 300 82 } 301 83 … … 303 85 RTDECL(RTCPUID) RTMpGetMaxCpuId(void) 304 86 { 305 return rtMp LinuxMaxCpus() - 1;87 return rtMpDarwinMaxCpus() - 1; 306 88 } 307 89 … … 309 91 RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu) 310 92 { 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 322 98 } 323 99 … … 325 101 RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu) 326 102 { 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(); 329 105 } 330 106 … … 332 108 RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet) 333 109 { 110 #if 0 111 RTCPUID cCpus = rtMpDarwinMaxCpus(); 112 return RTCpuSetFromU64(RT_BIT_64(cCpus) - 1); 113 114 #else 334 115 RTCpuSetEmpty(pSet); 335 RTCPUID cMax = rtMp LinuxMaxCpus();116 RTCPUID cMax = rtMpDarwinMaxCpus(); 336 117 for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) 337 118 if (RTMpIsCpuPossible(idCpu)) 338 119 RTCpuSetAdd(pSet, idCpu); 339 120 return pSet; 121 #endif 340 122 } 341 123 … … 343 125 RTDECL(RTCPUID) RTMpGetCount(void) 344 126 { 345 RTCPUSET Set; 346 RTMpGetSet(&Set); 347 return RTCpuSetCount(&Set); 127 return rtMpDarwinMaxCpus(); 348 128 } 349 129 … … 351 131 RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) 352 132 { 133 #if 1 134 return RTMpGetSet(pSet); 135 #else 353 136 RTCpuSetEmpty(pSet); 354 RTCPUID cMax = rtMp LinuxMaxCpus();137 RTCPUID cMax = rtMpDarwinMaxCpus(); 355 138 for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) 356 139 if (RTMpIsCpuOnline(idCpu)) 357 140 RTCpuSetAdd(pSet, idCpu); 358 141 return pSet; 142 #endif 359 143 } 360 144 … … 370 154 RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu) 371 155 { 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; 383 158 } 384 159 … … 386 161 RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu) 387 162 { 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; 399 188 }
Note:
See TracChangeset
for help on using the changeset viewer.