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