1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/sys_info.h" 6 7 #include <errno.h> 8 #include <stddef.h> 9 #include <stdint.h> 10 #include <string.h> 11 #include <sys/param.h> 12 #include <sys/resource.h> 13 #include <sys/utsname.h> 14 #include <unistd.h> 15 16 #include "base/files/file_util.h" 17 #include "base/lazy_instance.h" 18 #include "base/logging.h" 19 #include "base/strings/utf_string_conversions.h" 20 #include "base/sys_info_internal.h" 21 #include "base/threading/thread_restrictions.h" 22 #include "build/build_config.h" 23 24 #if defined(OS_ANDROID) 25 #include <sys/vfs.h> 26 #define statvfs statfs // Android uses a statvfs-like statfs struct and call. 27 #else 28 #include <sys/statvfs.h> 29 #endif 30 31 #if defined(OS_LINUX) 32 #include <linux/magic.h> 33 #include <sys/vfs.h> 34 #endif 35 36 namespace { 37 38 #if !defined(OS_OPENBSD) 39 int NumberOfProcessors() { 40 // sysconf returns the number of "logical" (not "physical") processors on both 41 // Mac and Linux. So we get the number of max available "logical" processors. 42 // 43 // Note that the number of "currently online" processors may be fewer than the 44 // returned value of NumberOfProcessors(). On some platforms, the kernel may 45 // make some processors offline intermittently, to save power when system 46 // loading is low. 47 // 48 // One common use case that needs to know the processor count is to create 49 // optimal number of threads for optimization. It should make plan according 50 // to the number of "max available" processors instead of "currently online" 51 // ones. The kernel should be smart enough to make all processors online when 52 // it has sufficient number of threads waiting to run. 53 long res = sysconf(_SC_NPROCESSORS_CONF); 54 if (res == -1) { 55 NOTREACHED(); 56 return 1; 57 } 58 59 return static_cast<int>(res); 60 } 61 62 base::LazyInstance< 63 base::internal::LazySysInfoValue<int, NumberOfProcessors> >::Leaky 64 g_lazy_number_of_processors = LAZY_INSTANCE_INITIALIZER; 65 #endif 66 67 int64_t AmountOfVirtualMemory() { 68 struct rlimit limit; 69 int result = getrlimit(RLIMIT_DATA, &limit); 70 if (result != 0) { 71 NOTREACHED(); 72 return 0; 73 } 74 return limit.rlim_cur == RLIM_INFINITY ? 0 : limit.rlim_cur; 75 } 76 77 base::LazyInstance< 78 base::internal::LazySysInfoValue<int64_t, AmountOfVirtualMemory>>::Leaky 79 g_lazy_virtual_memory = LAZY_INSTANCE_INITIALIZER; 80 81 #if defined(OS_LINUX) 82 bool IsStatsZeroIfUnlimited(const base::FilePath& path) { 83 struct statfs stats; 84 85 if (HANDLE_EINTR(statfs(path.value().c_str(), &stats)) != 0) 86 return false; 87 88 // In some platforms, |statfs_buf.f_type| is declared as signed, but some of 89 // the values will overflow it, causing narrowing warnings. Cast to the 90 // largest possible unsigned integer type to avoid it. 91 switch (static_cast<uintmax_t>(stats.f_type)) { 92 case TMPFS_MAGIC: 93 case HUGETLBFS_MAGIC: 94 case RAMFS_MAGIC: 95 return true; 96 } 97 return false; 98 } 99 #endif 100 101 bool GetDiskSpaceInfo(const base::FilePath& path, 102 int64_t* available_bytes, 103 int64_t* total_bytes) { 104 struct statvfs stats; 105 if (HANDLE_EINTR(statvfs(path.value().c_str(), &stats)) != 0) 106 return false; 107 108 #if defined(OS_LINUX) 109 const bool zero_size_means_unlimited = 110 stats.f_blocks == 0 && IsStatsZeroIfUnlimited(path); 111 #else 112 const bool zero_size_means_unlimited = false; 113 #endif 114 115 if (available_bytes) { 116 *available_bytes = 117 zero_size_means_unlimited 118 ? std::numeric_limits<int64_t>::max() 119 : static_cast<int64_t>(stats.f_bavail) * stats.f_frsize; 120 } 121 122 if (total_bytes) { 123 *total_bytes = zero_size_means_unlimited 124 ? std::numeric_limits<int64_t>::max() 125 : static_cast<int64_t>(stats.f_blocks) * stats.f_frsize; 126 } 127 return true; 128 } 129 130 } // namespace 131 132 namespace base { 133 134 #if !defined(OS_OPENBSD) 135 int SysInfo::NumberOfProcessors() { 136 return g_lazy_number_of_processors.Get().value(); 137 } 138 #endif 139 140 // static 141 int64_t SysInfo::AmountOfVirtualMemory() { 142 return g_lazy_virtual_memory.Get().value(); 143 } 144 145 // static 146 int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) { 147 base::ThreadRestrictions::AssertIOAllowed(); 148 149 int64_t available; 150 if (!GetDiskSpaceInfo(path, &available, nullptr)) 151 return -1; 152 return available; 153 } 154 155 // static 156 int64_t SysInfo::AmountOfTotalDiskSpace(const FilePath& path) { 157 base::ThreadRestrictions::AssertIOAllowed(); 158 159 int64_t total; 160 if (!GetDiskSpaceInfo(path, nullptr, &total)) 161 return -1; 162 return total; 163 } 164 165 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) 166 // static 167 std::string SysInfo::OperatingSystemName() { 168 struct utsname info; 169 if (uname(&info) < 0) { 170 NOTREACHED(); 171 return std::string(); 172 } 173 return std::string(info.sysname); 174 } 175 #endif 176 177 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) 178 // static 179 std::string SysInfo::OperatingSystemVersion() { 180 struct utsname info; 181 if (uname(&info) < 0) { 182 NOTREACHED(); 183 return std::string(); 184 } 185 return std::string(info.release); 186 } 187 #endif 188 189 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS) 190 // static 191 void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version, 192 int32_t* minor_version, 193 int32_t* bugfix_version) { 194 struct utsname info; 195 if (uname(&info) < 0) { 196 NOTREACHED(); 197 *major_version = 0; 198 *minor_version = 0; 199 *bugfix_version = 0; 200 return; 201 } 202 int num_read = sscanf(info.release, "%d.%d.%d", major_version, minor_version, 203 bugfix_version); 204 if (num_read < 1) 205 *major_version = 0; 206 if (num_read < 2) 207 *minor_version = 0; 208 if (num_read < 3) 209 *bugfix_version = 0; 210 } 211 #endif 212 213 // static 214 std::string SysInfo::OperatingSystemArchitecture() { 215 struct utsname info; 216 if (uname(&info) < 0) { 217 NOTREACHED(); 218 return std::string(); 219 } 220 std::string arch(info.machine); 221 if (arch == "i386" || arch == "i486" || arch == "i586" || arch == "i686") { 222 arch = "x86"; 223 } else if (arch == "amd64") { 224 arch = "x86_64"; 225 } 226 return arch; 227 } 228 229 // static 230 size_t SysInfo::VMAllocationGranularity() { 231 return getpagesize(); 232 } 233 234 } // namespace base 235