VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/linux/mp-linux.cpp@ 10421

Last change on this file since 10421 was 10421, checked in by vboxsync, 17 years ago

_SC_NPROCESSORS_CONF doesn't work.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.4 KB
Line 
1/* $Id: mp-linux.cpp 10421 2008-07-09 13:52:22Z vboxsync $ */
2/** @file
3 * IPRT - Multiprocessor, Linux.
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#define LOG_GROUP RTLOGGROUP_SYSTEM
36#include <unistd.h>
37#include <stdio.h>
38#include <sys/sysctl.h>
39#include <sys/stat.h>
40#include <sys/fcntl.h>
41#include <errno.h>
42
43#include <iprt/mp.h>
44#include <iprt/cpuset.h>
45#include <iprt/assert.h>
46#include <iprt/string.h>
47
48
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 */
58bool 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 */
85bool 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 */
102int 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 */
124int 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 */
139void 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 */
155ssize_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 */
172int64_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 */
206static 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/**
217 * Internal worker that determins the max possible CPU count.
218 *
219 * @returns Max cpus.
220 */
221static RTCPUID rtMpLinuxMaxCpus(void)
222{
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/** @todo RTmpCpuId(). */
244
245RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
246{
247 return idCpu < rtMpLinuxMaxCpus() ? idCpu : -1;
248}
249
250
251RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
252{
253 return (unsigned)iCpu < rtMpLinuxMaxCpus() ? iCpu : NIL_RTCPUID;
254}
255
256
257RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
258{
259 return rtMpLinuxMaxCpus() - 1;
260}
261
262
263RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
264{
265 /** @todo check if there is a simpler interface than this... */
266 int i = rtLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/online", (int)idCpu);
267 if ( i == -1
268 && rtLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu))
269 {
270 Assert(!rtLinuxSysFsExists("devices/system/cpu/cpu%d/online", (int)idCpu));
271 i = 1;
272 }
273
274 Assert(i == 0 || i == -1 || i == 1);
275 return i != 0 && i != -1;
276}
277
278
279RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
280{
281 /** @todo check this up with hotplugging! */
282 return rtLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu);
283}
284
285
286RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
287{
288 RTCpuSetEmpty(pSet);
289 RTCPUID cMax = rtMpLinuxMaxCpus();
290 for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
291 if (RTMpIsCpuPossible(idCpu))
292 RTCpuSetAdd(pSet, idCpu);
293 return pSet;
294}
295
296
297RTDECL(RTCPUID) RTMpGetCount(void)
298{
299 RTCPUSET Set;
300 RTMpGetSet(&Set);
301 return RTCpuSetCount(&Set);
302}
303
304
305RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
306{
307 RTCpuSetEmpty(pSet);
308 RTCPUID cMax = rtMpLinuxMaxCpus();
309 for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
310 if (RTMpIsCpuOnline(idCpu))
311 RTCpuSetAdd(pSet, idCpu);
312 return pSet;
313}
314
315
316RTDECL(RTCPUID) RTMpGetOnlineCount(void)
317{
318 RTCPUSET Set;
319 RTMpGetOnlineSet(&Set);
320 return RTCpuSetCount(&Set);
321}
322
Note: See TracBrowser for help on using the repository browser.

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