Home | History | Annotate | Download | only in base
      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