Changeset 15399 in vbox
- Timestamp:
- Dec 12, 2008 10:02:14 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 1 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/linux/sysfs.h
r14990 r15399 1 /* $Id$ */ 1 2 /** @file 2 * IPRT - Multiprocessor.3 * IPRT - Linux sysfs access. 3 4 */ 4 5 … … 28 29 */ 29 30 30 #ifndef ___iprt_ mp_h31 #define ___iprt_ mp_h31 #ifndef ___iprt_linux_sysfs_h 32 #define ___iprt_linux_sysfs_h 32 33 33 34 #include <iprt/cdefs.h> 34 35 #include <iprt/types.h> 35 36 37 #include <stdarg.h> 36 38 37 39 __BEGIN_DECLS 38 40 39 /** @defgroup grp_rt_mp RT Mp - Multiprocessor41 /** @defgroup grp_rt_mp RTLinuxSysfs - Linux sysfs 40 42 * @ingroup grp_rt 41 43 * @{ … … 43 45 44 46 /** 45 * Gets the identifier of the CPU executing the call.47 * Checks if a sysfs file (or directory, device, symlink, whatever) exists. 46 48 * 47 * When called from a system mode where scheduling is active, like ring-3 or 48 * kernel mode with interrupts enabled on some systems, no assumptions should 49 * be made about the current CPU when the call returns. 50 * 51 * @returns CPU Id. 49 * @returns true / false, errno is preserved. 50 * @param pszFormat The name format, either absolute or relative to "/sys/". 51 * @param va The format args. 52 52 */ 53 RTDECL( RTCPUID) RTMpCpuId(void);53 RTDECL(bool) RTLinuxSysFsExistsV(const char *pszFormat, va_list va); 54 54 55 55 /** 56 * C onverts a CPU identifier to a CPU set index.56 * Checks if a sysfs file (or directory, device, symlink, whatever) exists. 57 57 * 58 * This may or may not validate the presence of the CPU. 59 * 60 * @returns The CPU set index on success, -1 on failure. 61 * @param idCpu The identifier of the CPU. 58 * @returns true / false, errno is preserved. 59 * @param pszFormat The name format, either absolute or relative to "/sys/". 60 * @param ... The format args. 62 61 */ 63 RTDECL( int) RTMpCpuIdToSetIndex(RTCPUID idCpu);62 RTDECL(bool) RTLinuxSysFsExists(const char *pszFormat, ...); 64 63 65 64 /** 66 * Converts a CPU set index to a a CPU identifier.65 * Opens a sysfs file. 67 66 * 68 * This may or may not validate the presence of the CPU, so, use 69 * RTMpIsCpuPossible for that. 70 * 71 * @returns The corresponding CPU identifier, NIL_RTCPUID on failure. 72 * @param iCpu The CPU set index. 67 * @returns The file descriptor. -1 and errno on failure. 68 * @param pszFormat The name format, either absolute or relative to "/sys/". 69 * @param va The format args. 73 70 */ 74 RTDECL( RTCPUID) RTMpCpuIdFromSetIndex(int iCpu);71 RTDECL(int) RTLinuxSysFsOpenV(const char *pszFormat, va_list va); 75 72 76 73 /** 77 * Gets the max CPU identifier (inclusive).74 * Opens a sysfs file. 78 75 * 79 * Inteded for brute force enumerations, but use with 80 * care as it may be expensive. 81 * 82 * @returns The current higest CPU identifier value. 76 * @returns The file descriptor. -1 and errno on failure. 77 * @param pszFormat The name format, either absolute or relative to "/sys/". 78 * @param ... The format args. 83 79 */ 84 RTDECL(RTCPUID) RTMpGetMaxCpuId(void); 85 80 RTDECL(int) RTLinuxSysFsOpen(const char *pszFormat, ...); 86 81 87 82 /** 88 * C hecks if a CPU exists in the system or may possibly be hotplugged later.83 * Closes a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV. 89 84 * 90 * @returns true/false accordingly. 91 * @param idCpu The identifier of the CPU. 85 * @param fd 92 86 */ 93 RTDECL( bool) RTMpIsCpuPossible(RTCPUID idCpu);87 RTDECL(void) RTLinuxSysFsClose(int fd); 94 88 95 89 /** 96 * Gets set of the CPUs present in the system pluss any that may 97 * possibly be hotplugged later. 90 * Reads a string from a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV. 98 91 * 99 * @returns pSet. 100 * @param pSet Where to put the set. 92 * @returns The number of bytes read. -1 and errno on failure. 93 * @param fd The file descriptor returned by RTLinuxSysFsOpen or RTLinuxSysFsOpenV. 94 * @param pszBuf Where to store the string. 95 * @param cchBuf The size of the buffer. Must be at least 2 bytes. 101 96 */ 102 RTDECL( PRTCPUSET) RTMpGetSet(PRTCPUSET pSet);97 RTDECL(ssize_t) RTLinuxSysFsReadStr(int fd, char *pszBuf, size_t cchBuf); 103 98 104 99 /** 105 * Get the count of CPUs present in the system plus any that may 106 * possibly be hotplugged later. 100 * Reads a number from a sysfs file. 107 101 * 108 * @return The count. 102 * @returns 64-bit signed value on success, -1 and errno on failure. 103 * @param uBase The number base, 0 for autodetect. 104 * @param pszFormat The filename format, either absolute or relative to "/sys/". 105 * @param va Format args. 109 106 */ 110 RTDECL(RTCPUID) RTMpGetCount(void); 111 107 RTDECL(int64_t) RTLinuxSysFsReadIntFileV(unsigned uBase, const char *pszFormat, va_list va); 112 108 113 109 /** 114 * Gets set of the CPUs present that are currently online.110 * Reads a number from a sysfs file. 115 111 * 116 * @returns pSet. 117 * @param pSet Where to put the set. 112 * @returns 64-bit signed value on success, -1 and errno on failure. 113 * @param uBase The number base, 0 for autodetect. 114 * @param pszFormat The filename format, either absolute or relative to "/sys/". 115 * @param ... Format args. 118 116 */ 119 RTDECL( PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet);117 RTDECL(int64_t) RTLinuxSysFsReadIntFile(unsigned uBase, const char *pszFormat, ...); 120 118 121 119 /** 122 * Get the count of CPUs that are currently online. 120 * Reads a string from a sysfs file. If the file contains a newline, we only 121 * return the text up until there. 123 122 * 124 * @return The count. 123 * @returns number of characters read on success, -1 and errno on failure. 124 * @param pszBuf Where to store the path element. Must be at least two 125 * characters, but a longer buffer would be advisable. 126 * @param cchBuf The size of the buffer pointed to by @a pszBuf. 127 * @param pszFormat The filename format, either absolute or relative to "/sys/". 128 * @param va Format args. 125 129 */ 126 RTDECL( RTCPUID) RTMpGetOnlineCount(void);130 RTDECL(ssize_t) RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va); 127 131 128 132 /** 129 * Checks if a CPU is online or not. 133 * Reads a string from a sysfs file. If the file contains a newline, we only 134 * return the text up until there. 130 135 * 131 * @returns true/false accordingly. 132 * @param idCpu The identifier of the CPU. 136 * @returns number of characters read on success, -1 and errno on failure. 137 * @param pszBuf Where to store the path element. Must be at least two 138 * characters, but a longer buffer would be advisable. 139 * @param cchBuf The size of the buffer pointed to by @a pszBuf. 140 * @param pszFormat The filename format, either absolute or relative to "/sys/". 141 * @param ... Format args. 133 142 */ 134 RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu); 135 143 RTDECL(ssize_t) RTLinuxSysFsReadStrFile(char *pszBuf, size_t cchBuf, const char *pszFormat, ...); 136 144 137 145 /** 138 * Gets set of the CPUs present in the system. 146 * Reads the last element of the path of the file pointed to by the symbolic 147 * link specified. This is needed at least to get the name of the driver 148 * associated with a device, where pszFormat should be the "driver" link in the 149 * devices sysfs directory. 139 150 * 140 * @returns pSet. 141 * @param pSet Where to put the set. 151 * @returns The number of characters written on success, -1 and errno on failure. 152 * @param pszBuf Where to store the path element. Must be at least two 153 * characters, but a longer buffer would be advisable. 154 * @param cchBuf The size of the buffer pointed to by @a pszBuf. 155 * @param pszFormat The filename format, either absolute or relative to "/sys/". 156 * @param ... Format args. 142 157 */ 143 RTDECL(PRTCPUSET) RTMpGetPresentSet(PRTCPUSET pSet); 144 145 /** 146 * Get the count of CPUs that are present in the system. 147 * 148 * @return The count. 149 */ 150 RTDECL(RTCPUID) RTMpGetPresentCount(void); 151 152 /** 153 * Checks if a CPU is present in the system. 154 * 155 * @returns true/false accordingly. 156 * @param idCpu The identifier of the CPU. 157 */ 158 RTDECL(bool) RTMpIsCpuPresent(RTCPUID idCpu); 159 160 161 /** 162 * Get the current frequency of a CPU. 163 * 164 * The CPU must be online. 165 * 166 * @returns The frequency as MHz. 0 if the CPU is offline 167 * or the information is not available. 168 * @param idCpu The identifier of the CPU. 169 */ 170 RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu); 171 172 173 /** 174 * Get the maximum frequency of a CPU. 175 * 176 * The CPU must be online. 177 * 178 * @returns The frequency as MHz. 0 if the CPU is offline 179 * or the information is not available. 180 * @param idCpu The identifier of the CPU. 181 */ 182 RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu); 183 184 185 #ifdef IN_RING0 186 187 /** 188 * Worker function passed to RTMpOnAll, RTMpOnOthers and RTMpOnSpecific that 189 * is to be called on the target cpus. 190 * 191 * @param idCpu The identifier for the CPU the function is called on. 192 * @param pvUser1 The 1st user argument. 193 * @param pvUser2 The 2nd user argument. 194 */ 195 typedef DECLCALLBACK(void) FNRTMPWORKER(RTCPUID idCpu, void *pvUser1, void *pvUser2); 196 /** Pointer to a FNRTMPWORKER. */ 197 typedef FNRTMPWORKER *PFNRTMPWORKER; 198 199 /** 200 * Executes a function on each (online) CPU in the system. 201 * 202 * @returns IPRT status code. 203 * @retval VINF_SUCCESS on success. 204 * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the system. 205 * 206 * @param pfnWorker The worker function. 207 * @param pvUser1 The first user argument for the worker. 208 * @param pvUser2 The second user argument for the worker. 209 * 210 * @remarks The execution isn't in any way guaranteed to be simultaneous, 211 * it might even be serial (cpu by cpu). 212 */ 213 RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); 214 215 /** 216 * Executes a function on a all other (online) CPUs in the system. 217 * 218 * @returns IPRT status code. 219 * @retval VINF_SUCCESS on success. 220 * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the system. 221 * 222 * @param pfnWorker The worker function. 223 * @param pvUser1 The first user argument for the worker. 224 * @param pvUser2 The second user argument for the worker. 225 * 226 * @remarks The execution isn't in any way guaranteed to be simultaneous, 227 * it might even be serial (cpu by cpu). 228 */ 229 RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); 230 231 /** 232 * Executes a function on a specific CPU in the system. 233 * 234 * @returns IPRT status code. 235 * @retval VINF_SUCCESS on success. 236 * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the system. 237 * @retval VERR_CPU_OFFLINE if the CPU is offline. 238 * @retval VERR_CPU_NOT_FOUND if the CPU wasn't found. 239 * 240 * @param idCpu The id of the CPU. 241 * @param pfnWorker The worker function. 242 * @param pvUser1 The first user argument for the worker. 243 * @param pvUser2 The second user argument for the worker. 244 */ 245 RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2); 246 247 248 /** 249 * MP event, see FNRTMPNOTIFICATION. 250 */ 251 typedef enum RTMPEVENT 252 { 253 /** The CPU goes online. */ 254 RTMPEVENT_ONLINE = 1, 255 /** The CPU goes offline. */ 256 RTMPEVENT_OFFLINE 257 } RTMPEVENT; 258 259 /** 260 * Notification callback. 261 * 262 * The context this is called in differs a bit from platform to 263 * platform, so be careful while in here. 264 * 265 * @param idCpu The CPU this applies to. 266 * @param enmEvent The event. 267 * @param pvUser The user argument. 268 */ 269 typedef DECLCALLBACK(void) FNRTMPNOTIFICATION(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser); 270 /** Pointer to a FNRTMPNOTIFICATION(). */ 271 typedef FNRTMPNOTIFICATION *PFNRTMPNOTIFICATION; 272 273 /** 274 * Registers a notification callback for cpu events. 275 * 276 * On platforms which doesn't do cpu offline/online events this API 277 * will just be a no-op that pretends to work. 278 * 279 * @todo We'll be adding a flag to this soon to indicate whether the callback should be called on all 280 * CPUs that are currently online while it's being registered. This is to help avoid some race 281 * conditions (we'll hopefully be able to implement this on linux, solaris/win is no issue). 282 * 283 * @returns IPRT status code. 284 * @retval VINF_SUCCESS on success. 285 * @retval VERR_NO_MEMORY if a registration record cannot be allocated. 286 * @retval VERR_ALREADY_EXISTS if the pfnCallback and pvUser already exist 287 * in the callback list. 288 * 289 * @param pfnCallback The callback. 290 * @param pvUser The user argument to the callback function. 291 */ 292 RTDECL(int) RTMpNotificationRegister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser); 293 294 /** 295 * This deregisters a notification callback registered via RTMpNotificationRegister(). 296 * 297 * The pfnCallback and pvUser arguments must be identical to the registration call 298 * of we won't find the right entry. 299 * 300 * @returns IPRT status code. 301 * @retval VINF_SUCCESS on success. 302 * @retval VERR_NOT_FOUND if no matching entry was found. 303 * 304 * @param pfnCallback The callback. 305 * @param pvUser The user argument to the callback function. 306 */ 307 RTDECL(int) RTMpNotificationDeregister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser); 308 309 #endif /* IN_RING0 */ 158 RTDECL(int) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char *pszFormat, ...); 310 159 311 160 /** @} */ -
trunk/src/VBox/Runtime/r3/linux/mp-linux.cpp
r10482 r15399 34 34 *******************************************************************************/ 35 35 #define LOG_GROUP RTLOGGROUP_SYSTEM 36 #include <unistd.h>37 36 #include <stdio.h> 38 #include <sys/sysctl.h>39 #include <sys/stat.h>40 #include <sys/fcntl.h>41 37 #include <errno.h> 42 38 … … 45 41 #include <iprt/assert.h> 46 42 #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 */ 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); NOREF(cch); 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); NOREF(cch); 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 } 43 #include <iprt/linux/sysfs.h> 214 44 215 45 … … 231 61 int cMax = 1; 232 62 for (unsigned iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++) 233 if ( rtLinuxSysFsExists("devices/system/cpu/cpu%d", iCpu))63 if (RTLinuxSysFsExists("devices/system/cpu/cpu%d", iCpu)) 234 64 cMax = iCpu + 1; 235 65 ASMAtomicUoWriteU32((uint32_t volatile *)&s_cMax, cMax); … … 310 140 { 311 141 /** @todo check if there is a simpler interface than this... */ 312 int i = rtLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/online", (int)idCpu);142 int i = RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/online", (int)idCpu); 313 143 if ( i == -1 314 && rtLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu))315 { 316 Assert(! rtLinuxSysFsExists("devices/system/cpu/cpu%d/online", (int)idCpu));144 && RTLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu)) 145 { 146 Assert(!RTLinuxSysFsExists("devices/system/cpu/cpu%d/online", (int)idCpu)); 317 147 i = 1; 318 148 } … … 326 156 { 327 157 /** @todo check this up with hotplugging! */ 328 return rtLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu);158 return RTLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu); 329 159 } 330 160 … … 370 200 RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu) 371 201 { 372 int64_t kHz = rtLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq", (int)idCpu);202 int64_t kHz = RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq", (int)idCpu); 373 203 if (kHz == -1) 374 204 { … … 388 218 RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu) 389 219 { 390 int64_t kHz = rtLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu);220 int64_t kHz = RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu); 391 221 if (kHz == -1) 392 222 { … … 395 225 * would provide current frequency information, which is wrong. 396 226 */ 397 if (! rtLinuxSysFsExists("devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu))227 if (!RTLinuxSysFsExists("devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu)) 398 228 kHz = rtMpLinuxGetFrequency(idCpu) * 1000; 399 229 else -
trunk/src/VBox/Runtime/r3/linux/sysfs.cpp
r14990 r15399 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Multiprocessor, Linux.3 * IPRT - Linux sysfs access. 4 4 */ 5 5 … … 41 41 #include <errno.h> 42 42 43 #include <iprt/mp.h> 44 #include <iprt/cpuset.h> 43 #include <iprt/linux/sysfs.h> 45 44 #include <iprt/assert.h> 45 #include <iprt/param.h> 46 46 #include <iprt/string.h> 47 47 48 48 49 /** @todo move the rtLinuxSysFs* bits into sysfs.cpp and sysfs.h. */ 49 /** 50 * Constructs the path of a sysfs file from the format paramaters passed, 51 * prepending "/sys/" if the path is relative. 52 * 53 * @returns The number of characters written, or -1 and errno on failure. 54 * @param pszBuf Where to write the path. Must be at least 55 * sizeof("/sys/") characters long 56 * @param cchBuf The size of the buffer pointed to by @a pszBuf 57 * @param pszFormat The name format, either absolute or relative to "/sys/". 58 * @param va The format args. 59 */ 60 static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf, 61 const char *pszFormat, va_list va) 62 { 63 char szFilename[RTPATH_MAX]; 64 const char szPrefix[] = "/sys/"; 65 if (cchBuf < sizeof(szPrefix)) 66 AssertFailedReturnStmt(errno = EINVAL, -1); 67 size_t cch = RTStrPrintfV(szFilename, sizeof(szFilename), pszFormat, va); 68 if (szFilename[0] == '/') 69 *pszBuf = '\0'; 70 else 71 strcpy(pszBuf, szPrefix); 72 strncat(pszBuf, szFilename, cchBuf); 73 return strlen(pszBuf); 74 } 50 75 51 76 /** … … 53 78 * 54 79 * @returns true / false, errno is preserved. 55 * @param pszFormat The name format, without"/sys/".80 * @param pszFormat The name format, either absolute or relative to "/sys/". 56 81 * @param va The format args. 57 82 */ 58 bool rtLinuxSysFsExistsV(const char *pszFormat, va_list va)83 bool RTLinuxSysFsExistsV(const char *pszFormat, va_list va) 59 84 { 60 85 int iSavedErrno = errno; … … 63 88 * Construct the filename and call stat. 64 89 */ 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); NOREF(cch); 70 71 struct stat st; 72 bool fRet = stat(szFilename, &st) == 0; 90 char szFilename[RTPATH_MAX]; 91 bool fRet = false; 92 ssize_t rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), 93 pszFormat, va); 94 if (rc > 0 && static_cast<size_t>(rc) < sizeof(szFilename)) 95 { 96 struct stat st; 97 fRet = stat(szFilename, &st) == 0; 98 } 73 99 74 100 errno = iSavedErrno; … … 80 106 * 81 107 * @returns true / false, errno is preserved. 82 * @param pszFormat The name format, without"/sys/".108 * @param pszFormat The name format, either absolute or relative to "/sys/". 83 109 * @param ... The format args. 84 110 */ 85 bool rtLinuxSysFsExists(const char *pszFormat, ...)86 { 87 va_list va; 88 va_start(va, pszFormat); 89 bool fRet = rtLinuxSysFsExistsV(pszFormat, va);111 bool RTLinuxSysFsExists(const char *pszFormat, ...) 112 { 113 va_list va; 114 va_start(va, pszFormat); 115 bool fRet = RTLinuxSysFsExistsV(pszFormat, va); 90 116 va_end(va); 91 117 return fRet; … … 97 123 * 98 124 * @returns The file descriptor. -1 and errno on failure. 99 * @param pszFormat The name format, without"/sys/".125 * @param pszFormat The name format, either absolute or relative to "/sys/". 100 126 * @param va The format args. 101 127 */ 102 int rtLinuxSysFsOpenV(const char *pszFormat, va_list va)128 int RTLinuxSysFsOpenV(const char *pszFormat, va_list va) 103 129 { 104 130 /* 105 131 * Construct the filename and call open. 106 132 */ 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); NOREF(cch); 112 113 return open(szFilename, O_RDONLY, 0); 133 char szFilename[RTPATH_MAX]; 134 ssize_t rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), 135 pszFormat, va); 136 if (rc > 0 && static_cast<size_t>(rc) < sizeof(szFilename)) 137 rc = open(szFilename, O_RDONLY, 0); 138 return rc; 114 139 } 115 140 … … 119 144 * 120 145 * @returns The file descriptor. -1 and errno on failure. 121 * @param pszFormat The name format, without"/sys/".146 * @param pszFormat The name format, either absolute or relative to "/sys/". 122 147 * @param ... The format args. 123 148 */ 124 int rtLinuxSysFsOpen(const char *pszFormat, ...)125 { 126 va_list va; 127 va_start(va, pszFormat); 128 int fd = rtLinuxSysFsOpenV(pszFormat, va);149 int RTLinuxSysFsOpen(const char *pszFormat, ...) 150 { 151 va_list va; 152 va_start(va, pszFormat); 153 int fd = RTLinuxSysFsOpenV(pszFormat, va); 129 154 va_end(va); 130 155 return fd; … … 133 158 134 159 /** 135 * Closes a file opened with rtLinuxSysFsOpen or rtLinuxSysFsOpenV.160 * Closes a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV. 136 161 * 137 162 * @param fd 138 163 */ 139 void rtLinuxSysFsClose(int fd)164 void RTLinuxSysFsClose(int fd) 140 165 { 141 166 int iSavedErrno = errno; … … 146 171 147 172 /** 148 * Closes a file opened with rtLinuxSysFsOpen or rtLinuxSysFsOpenV.173 * Reads a string from a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV. 149 174 * 150 175 * @returns The number of bytes read. -1 and errno on failure. 151 * @param fd The file descriptor returned by rtLinuxSysFsOpen or rtLinuxSysFsOpenV.176 * @param fd The file descriptor returned by RTLinuxSysFsOpen or RTLinuxSysFsOpenV. 152 177 * @param pszBuf Where to store the string. 153 178 * @param cchBuf The size of the buffer. Must be at least 2 bytes. 154 179 */ 155 ssize_t rtLinuxSysFsReadStr(int fd, char *pszBuf, size_t cchBuf)180 ssize_t RTLinuxSysFsReadStr(int fd, char *pszBuf, size_t cchBuf) 156 181 { 157 182 Assert(cchBuf > 1); … … 163 188 164 189 /** 165 * Reads a sysfs file.190 * Reads a number from a sysfs file. 166 191 * 167 192 * @returns 64-bit signed value on success, -1 and errno on failure. 168 193 * @param uBase The number base, 0 for autodetect. 169 * @param pszFormat The filename format, without"/sys/".194 * @param pszFormat The filename format, either absolute or relative to "/sys/". 170 195 * @param va Format args. 171 196 */ 172 int64_t rtLinuxSysFsReadIntFileV(unsigned uBase, const char *pszFormat, va_list va)173 { 174 int fd = rtLinuxSysFsOpenV(pszFormat, va);197 int64_t RTLinuxSysFsReadIntFileV(unsigned uBase, const char *pszFormat, va_list va) 198 { 199 int fd = RTLinuxSysFsOpenV(pszFormat, va); 175 200 if (fd == -1) 176 201 return -1; … … 178 203 int64_t i64Ret = -1; 179 204 char szNum[128]; 180 ssize_t cchNum = rtLinuxSysFsReadStr(fd, szNum, sizeof(szNum));205 ssize_t cchNum = RTLinuxSysFsReadStr(fd, szNum, sizeof(szNum)); 181 206 if (cchNum > 0) 182 207 { … … 191 216 errno = -ETXTBSY; /* just something that won't happen at read / open. */ 192 217 193 rtLinuxSysFsClose(fd);218 RTLinuxSysFsClose(fd); 194 219 return i64Ret; 195 220 } … … 197 222 198 223 /** 199 * Reads a sysfs file.224 * Reads a number from a sysfs file. 200 225 * 201 226 * @returns 64-bit signed value on success, -1 and errno on failure. 202 227 * @param uBase The number base, 0 for autodetect. 203 * @param pszFormat The filename format, without"/sys/".228 * @param pszFormat The filename format, either absolute or relative to "/sys/". 204 229 * @param ... Format args. 205 230 */ 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);231 int64_t RTLinuxSysFsReadIntFile(unsigned uBase, const char *pszFormat, ...) 232 { 233 va_list va; 234 va_start(va, pszFormat); 235 int64_t i64Ret = RTLinuxSysFsReadIntFileV(uBase, pszFormat, va); 211 236 va_end(va); 212 237 return i64Ret; … … 215 240 216 241 /** 217 * Internal worker that determins the max possible CPU count. 218 * 219 * @returns Max cpus. 220 */ 221 static 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 * 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 *pFile = fopen("/proc/cpuinfo", "r"); 250 if (!pFile) 251 return 0; 252 253 char sz[256]; 254 RTCPUID idCpuFound = NIL_RTCPUID; 255 uint32_t Frequency = 0; 256 while (fgets(sz, sizeof(sz), pFile)) 257 { 258 char *psz; 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 Frequency = v; 280 break; 281 } 282 } 283 } 284 fclose(pFile); 285 return Frequency; 286 } 287 288 289 /** @todo RTmpCpuId(). */ 290 291 RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu) 292 { 293 return idCpu < rtMpLinuxMaxCpus() ? idCpu : -1; 294 } 295 296 297 RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu) 298 { 299 return (unsigned)iCpu < rtMpLinuxMaxCpus() ? iCpu : NIL_RTCPUID; 300 } 301 302 303 RTDECL(RTCPUID) RTMpGetMaxCpuId(void) 304 { 305 return rtMpLinuxMaxCpus() - 1; 306 } 307 308 309 RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu) 310 { 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; 322 } 323 324 325 RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu) 326 { 327 /** @todo check this up with hotplugging! */ 328 return rtLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu); 329 } 330 331 332 RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet) 333 { 334 RTCpuSetEmpty(pSet); 335 RTCPUID cMax = rtMpLinuxMaxCpus(); 336 for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) 337 if (RTMpIsCpuPossible(idCpu)) 338 RTCpuSetAdd(pSet, idCpu); 339 return pSet; 340 } 341 342 343 RTDECL(RTCPUID) RTMpGetCount(void) 344 { 345 RTCPUSET Set; 346 RTMpGetSet(&Set); 347 return RTCpuSetCount(&Set); 348 } 349 350 351 RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) 352 { 353 RTCpuSetEmpty(pSet); 354 RTCPUID cMax = rtMpLinuxMaxCpus(); 355 for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) 356 if (RTMpIsCpuOnline(idCpu)) 357 RTCpuSetAdd(pSet, idCpu); 358 return pSet; 359 } 360 361 362 RTDECL(RTCPUID) RTMpGetOnlineCount(void) 363 { 364 RTCPUSET Set; 365 RTMpGetOnlineSet(&Set); 366 return RTCpuSetCount(&Set); 367 } 368 369 370 RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu) 371 { 372 int64_t kHz = rtLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq", (int)idCpu); 373 if (kHz == -1) 374 { 375 /* 376 * The file may be just unreadable - in that case use plan B, i.e. 377 * /proc/cpuinfo to get the data we want. The assumption is that if 378 * cpuinfo_cur_freq doesn't exist then the speed won't change, and 379 * thus cur == max. If it does exist then cpuinfo contains the 380 * current frequency. 381 */ 382 kHz = rtMpLinuxGetFrequency(idCpu) * 1000; 383 } 384 return (kHz + 999) / 1000; 385 } 386 387 388 RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu) 389 { 390 int64_t kHz = rtLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu); 391 if (kHz == -1) 392 { 393 /* 394 * Check if the file isn't there - if it is there, then /proc/cpuinfo 395 * would provide current frequency information, which is wrong. 396 */ 397 if (!rtLinuxSysFsExists("devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu)) 398 kHz = rtMpLinuxGetFrequency(idCpu) * 1000; 399 else 400 kHz = 0; 401 } 402 return (kHz + 999) / 1000; 403 } 242 * Reads a string from a sysfs file. If the file contains a newline, we only 243 * return the text up until there. 244 * 245 * @returns number of characters read on success, -1 and errno on failure. 246 * @param pszBuf Where to store the path element. Must be at least two 247 * characters, but a longer buffer would be advisable. 248 * @param cchBuf The size of the buffer pointed to by @a pszBuf. 249 * @param pszFormat The filename format, either absolute or relative to "/sys/". 250 * @param va Format args. 251 */ 252 ssize_t RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va) 253 { 254 int fd = RTLinuxSysFsOpenV(pszFormat, va); 255 if (fd == -1) 256 return -1; 257 258 ssize_t cchRet = RTLinuxSysFsReadStr(fd, pszBuf, cchBuf); 259 RTLinuxSysFsClose(fd); 260 char *pchNewLine = NULL; 261 if (cchRet > 0) 262 pchNewLine = reinterpret_cast<char *>(memchr(pszBuf, '\n', cchRet)); 263 if (pchNewLine != NULL) 264 *pchNewLine = '\0'; 265 return cchRet; 266 } 267 268 269 /** 270 * Reads a string from a sysfs file. If the file contains a newline, we only 271 * return the text up until there. 272 * 273 * @returns number of characters read on success, -1 and errno on failure. 274 * @param pszBuf Where to store the path element. Must be at least two 275 * characters, but a longer buffer would be advisable. 276 * @param cchBuf The size of the buffer pointed to by @a pszBuf. 277 * @param pszFormat The filename format, either absolute or relative to "/sys/". 278 * @param ... Format args. 279 */ 280 ssize_t RTLinuxSysFsReadStrFile(char *pszBuf, size_t cchBuf, const char *pszFormat, ...) 281 { 282 va_list va; 283 va_start(va, pszFormat); 284 ssize_t cchRet = RTLinuxSysFsReadStrFileV(pszBuf, cchBuf, pszFormat, va); 285 va_end(va); 286 return cchRet; 287 } 288 289 290 /** 291 * Reads the last element of the path of the file pointed to by the symbolic 292 * link specified. This is needed at least to get the name of the driver 293 * associated with a device, where pszFormat should be the "driver" link in the 294 * devices sysfs directory. 295 * 296 * @returns The number of characters written on success, -1 and errno on failure. 297 * @param pszBuf Where to store the path element. Must be at least two 298 * characters, but a longer buffer would be advisable. 299 * @param cchBuf The size of the buffer pointed to by @a pszBuf. 300 * @param pszFormat The filename format, either absolute or relative to "/sys/". 301 * @param ... Format args. 302 */ 303 int RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char *pszFormat, ...) 304 { 305 if (cchBuf < 2) 306 AssertFailedReturnStmt(errno = EINVAL, -1); 307 va_list va; 308 va_start(va, pszFormat); 309 char szFilename[RTPATH_MAX], szLink[RTPATH_MAX]; 310 int rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va); 311 va_end(va); 312 if (rc == sizeof(szFilename)) 313 { 314 rc = -1; 315 errno = EINVAL; /* Bad format arguements */ 316 } 317 if (rc > 0) 318 rc = readlink(szFilename, szLink, sizeof(szLink)); 319 if (rc > 0 && static_cast<size_t>(rc) > sizeof(szLink) - 1) 320 { 321 rc = -1; 322 errno = EIO; /* The path name can't be this big. */ 323 } 324 if (rc >= 0) 325 { 326 szLink[rc] = '\0'; 327 char *lastPart = strrchr(szLink, '/'); 328 Assert(lastPart != NULL); /* rtLinuxSysFsConstructPath guarantees a path 329 * starting with '/'. */ 330 *pszBuf = '\0'; 331 strncat(pszBuf, lastPart + 1, cchBuf); 332 rc = strlen(pszBuf); 333 } 334 return rc; 335 } 336
Note:
See TracChangeset
for help on using the changeset viewer.