• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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