/ src / common / system.cpp
system.cpp
  1  // Copyright (c) 2009-2010 Satoshi Nakamoto
  2  // Copyright (c) 2009-present The Bitcoin Core developers
  3  // Distributed under the MIT software license, see the accompanying
  4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5  
  6  #include <bitcoin-build-config.h> // IWYU pragma: keep
  7  
  8  #include <common/system.h>
  9  
 10  #include <logging.h>
 11  #include <util/string.h>
 12  #include <util/time.h>
 13  
 14  #ifdef WIN32
 15  #include <cassert>
 16  #include <codecvt>
 17  #include <compat/compat.h>
 18  #include <windows.h>
 19  #else
 20  #include <sys/stat.h>
 21  #include <unistd.h>
 22  #endif
 23  
 24  #ifdef HAVE_MALLOPT_ARENA_MAX
 25  #include <malloc.h>
 26  #endif
 27  
 28  #include <algorithm>
 29  #include <cstddef>
 30  #include <cstdint>
 31  #include <cstdlib>
 32  #include <locale>
 33  #include <optional>
 34  #include <stdexcept>
 35  #include <string>
 36  #include <thread>
 37  
 38  using util::ReplaceAll;
 39  
 40  #ifndef WIN32
 41  std::string ShellEscape(const std::string& arg)
 42  {
 43      std::string escaped = arg;
 44      ReplaceAll(escaped, "'", "'\"'\"'");
 45      return "'" + escaped + "'";
 46  }
 47  #endif
 48  
 49  #if HAVE_SYSTEM
 50  void runCommand(const std::string& strCommand)
 51  {
 52      if (strCommand.empty()) return;
 53  #ifndef WIN32
 54      int nErr = ::system(strCommand.c_str());
 55  #else
 56      int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str());
 57  #endif
 58      if (nErr) {
 59          LogWarning("runCommand error: system(%s) returned %d", strCommand, nErr);
 60      }
 61  }
 62  #endif
 63  
 64  void SetupEnvironment()
 65  {
 66  #ifdef HAVE_MALLOPT_ARENA_MAX
 67      // glibc-specific: On 32-bit systems set the number of arenas to 1.
 68      // By default, since glibc 2.10, the C library will create up to two heap
 69      // arenas per core. This is known to cause excessive virtual address space
 70      // usage in our usage. Work around it by setting the maximum number of
 71      // arenas to 1.
 72      if (sizeof(void*) == 4) {
 73          mallopt(M_ARENA_MAX, 1);
 74      }
 75  #endif
 76      // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
 77      // may be invalid, in which case the "C.UTF-8" locale is used as fallback.
 78  #if !defined(WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
 79      try {
 80          std::locale(""); // Raises a runtime error if current locale is invalid
 81      } catch (const std::runtime_error&) {
 82          setenv("LC_ALL", "C.UTF-8", 1);
 83      }
 84  #elif defined(WIN32)
 85      assert(GetACP() == CP_UTF8);
 86      // Set the default input/output charset is utf-8
 87      SetConsoleCP(CP_UTF8);
 88      SetConsoleOutputCP(CP_UTF8);
 89  #endif
 90  
 91  #ifndef WIN32
 92      constexpr mode_t private_umask = 0077;
 93      umask(private_umask);
 94  #endif
 95  }
 96  
 97  bool SetupNetworking()
 98  {
 99  #ifdef WIN32
100      // Initialize Windows Sockets
101      WSADATA wsadata;
102      int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
103      if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
104          return false;
105  #endif
106      return true;
107  }
108  
109  int GetNumCores()
110  {
111      return std::thread::hardware_concurrency();
112  }
113  
114  std::optional<size_t> GetTotalRAM()
115  {
116      [[maybe_unused]] auto clamp{[](uint64_t v) { return size_t(std::min(v, uint64_t{std::numeric_limits<size_t>::max()})); }};
117  #ifdef WIN32
118      if (MEMORYSTATUSEX m{}; (m.dwLength = sizeof(m), GlobalMemoryStatusEx(&m))) return clamp(m.ullTotalPhys);
119  #elif defined(__APPLE__) || \
120        defined(__FreeBSD__) || \
121        defined(__NetBSD__) || \
122        defined(__OpenBSD__) || \
123        defined(__illumos__) || \
124        defined(__linux__)
125      if (long p{sysconf(_SC_PHYS_PAGES)}, s{sysconf(_SC_PAGESIZE)}; p > 0 && s > 0) return clamp(1ULL * p * s);
126  #endif
127      return std::nullopt;
128  }
129  
130  namespace {
131      const auto g_startup_time{SteadyClock::now()};
132  } // namespace
133  
134  SteadyClock::duration GetUptime() { return SteadyClock::now() - g_startup_time; }