diff options
| author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
|---|---|---|
| committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
| commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
| tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/llvm12/lib/Support/Unix | |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/llvm12/lib/Support/Unix')
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/COM.inc | 26 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/DynamicLibrary.inc | 134 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Host.inc | 84 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Memory.inc | 265 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Path.inc | 1379 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Process.inc | 457 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Program.inc | 559 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/README.txt | 16 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Signals.inc | 659 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/ThreadLocal.inc | 70 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Threading.inc | 311 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Unix.h | 110 | ||||
| -rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Watchdog.inc | 33 | 
13 files changed, 4103 insertions, 0 deletions
| diff --git a/contrib/libs/llvm12/lib/Support/Unix/COM.inc b/contrib/libs/llvm12/lib/Support/Unix/COM.inc new file mode 100644 index 00000000000..03a690ac376 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/COM.inc @@ -0,0 +1,26 @@ +//===- llvm/Support/Unix/COM.inc - Unix COM Implementation -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix portion of COM support. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//===          is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm { +namespace sys { + +InitializeCOMRAII::InitializeCOMRAII(COMThreadingMode Threading, +                                     bool SpeedOverMemory) {} + +InitializeCOMRAII::~InitializeCOMRAII() {} +} +} diff --git a/contrib/libs/llvm12/lib/Support/Unix/DynamicLibrary.inc b/contrib/libs/llvm12/lib/Support/Unix/DynamicLibrary.inc new file mode 100644 index 00000000000..a2a379963de --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/DynamicLibrary.inc @@ -0,0 +1,134 @@ +//===- Unix/DynamicLibrary.cpp - Unix DL Implementation ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the UNIX specific implementation of DynamicLibrary. +// +//===----------------------------------------------------------------------===// + +#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN) +#include <dlfcn.h> + +DynamicLibrary::HandleSet::~HandleSet() { +  // Close the libraries in reverse order. +  for (void *Handle : llvm::reverse(Handles)) +    ::dlclose(Handle); +  if (Process) +    ::dlclose(Process); + +  // llvm_shutdown called, Return to default +  DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; +} + +void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { +  void *Handle = ::dlopen(File, RTLD_LAZY|RTLD_GLOBAL); +  if (!Handle) { +    if (Err) *Err = ::dlerror(); +    return &DynamicLibrary::Invalid; +  } + +#ifdef __CYGWIN__ +  // Cygwin searches symbols only in the main +  // with the handle of dlopen(NULL, RTLD_GLOBAL). +  if (!File) +    Handle = RTLD_DEFAULT; +#endif + +  return Handle; +} + +void DynamicLibrary::HandleSet::DLClose(void *Handle) { +  ::dlclose(Handle); +} + +void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { +  return ::dlsym(Handle, Symbol); +} + +#else // !HAVE_DLOPEN + +DynamicLibrary::HandleSet::~HandleSet() {} + +void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { +  if (Err) *Err = "dlopen() not supported on this platform"; +  return &Invalid; +} + +void DynamicLibrary::HandleSet::DLClose(void *Handle) { +} + +void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { +  return nullptr; +} + +#endif + +// Must declare the symbols in the global namespace. +static void *DoSearch(const char* SymbolName) { +#define EXPLICIT_SYMBOL(SYM) \ +   extern void *SYM; if (!strcmp(SymbolName, #SYM)) return (void*)&SYM + +  // If this is darwin, it has some funky issues, try to solve them here.  Some +  // important symbols are marked 'private external' which doesn't allow +  // SearchForAddressOfSymbol to find them.  As such, we special case them here, +  // there is only a small handful of them. + +#ifdef __APPLE__ +  { +    // __eprintf is sometimes used for assert() handling on x86. +    // +    // FIXME: Currently disabled when using Clang, as we don't always have our +    // runtime support libraries available. +#ifndef __clang__ +#ifdef __i386__ +    EXPLICIT_SYMBOL(__eprintf); +#endif +#endif +  } +#endif + +#ifdef __CYGWIN__ +  { +    EXPLICIT_SYMBOL(_alloca); +    EXPLICIT_SYMBOL(__main); +  } +#endif + +#undef EXPLICIT_SYMBOL + +// This macro returns the address of a well-known, explicit symbol +#define EXPLICIT_SYMBOL(SYM) \ +   if (!strcmp(SymbolName, #SYM)) return &SYM + +// Under glibc we have a weird situation. The stderr/out/in symbols are both +// macros and global variables because of standards requirements. So, we +// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first. +#if defined(__GLIBC__) +  { +    EXPLICIT_SYMBOL(stderr); +    EXPLICIT_SYMBOL(stdout); +    EXPLICIT_SYMBOL(stdin); +  } +#else +  // For everything else, we want to check to make sure the symbol isn't defined +  // as a macro before using EXPLICIT_SYMBOL. +  { +#ifndef stdin +    EXPLICIT_SYMBOL(stdin); +#endif +#ifndef stdout +    EXPLICIT_SYMBOL(stdout); +#endif +#ifndef stderr +    EXPLICIT_SYMBOL(stderr); +#endif +  } +#endif +#undef EXPLICIT_SYMBOL + +  return nullptr; +} diff --git a/contrib/libs/llvm12/lib/Support/Unix/Host.inc b/contrib/libs/llvm12/lib/Support/Unix/Host.inc new file mode 100644 index 00000000000..dfcfdd0dee6 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/Host.inc @@ -0,0 +1,84 @@ +//===- llvm/Support/Unix/Host.inc -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the UNIX Host support. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//===          is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" +#include <cctype> +#include <string> +#include <sys/utsname.h> + +using namespace llvm; + +static std::string getOSVersion() { +  struct utsname info; + +  if (uname(&info)) +    return ""; + +  return info.release; +} + +static std::string updateTripleOSVersion(std::string TargetTripleString) { +  // On darwin, we want to update the version to match that of the target. +  std::string::size_type DarwinDashIdx = TargetTripleString.find("-darwin"); +  if (DarwinDashIdx != std::string::npos) { +    TargetTripleString.resize(DarwinDashIdx + strlen("-darwin")); +    TargetTripleString += getOSVersion(); +    return TargetTripleString; +  } +  std::string::size_type MacOSDashIdx = TargetTripleString.find("-macos"); +  if (MacOSDashIdx != std::string::npos) { +    TargetTripleString.resize(MacOSDashIdx); +    // Reset the OS to darwin as the OS version from `uname` doesn't use the +    // macOS version scheme. +    TargetTripleString += "-darwin"; +    TargetTripleString += getOSVersion(); +  } +  // On AIX, the AIX version and release should be that of the current host +  // unless if the version has already been specified. +  if (Triple(LLVM_HOST_TRIPLE).getOS() == Triple::AIX) { +    Triple TT(TargetTripleString); +    if (TT.getOS() == Triple::AIX && !TT.getOSMajorVersion()) { +      struct utsname name; +      if (uname(&name) != -1) { +        std::string NewOSName = std::string(Triple::getOSTypeName(Triple::AIX)); +        NewOSName += name.version; +        NewOSName += '.'; +        NewOSName += name.release; +        NewOSName += ".0.0"; +        TT.setOSName(NewOSName); +        return TT.str(); +      } +    } +  } +  return TargetTripleString; +} + +std::string sys::getDefaultTargetTriple() { +  std::string TargetTripleString = +      updateTripleOSVersion(LLVM_DEFAULT_TARGET_TRIPLE); + +  // Override the default target with an environment variable named by +  // LLVM_TARGET_TRIPLE_ENV. +#if defined(LLVM_TARGET_TRIPLE_ENV) +  if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) +    TargetTripleString = EnvTriple; +#endif + +  return TargetTripleString; +} diff --git a/contrib/libs/llvm12/lib/Support/Unix/Memory.inc b/contrib/libs/llvm12/lib/Support/Unix/Memory.inc new file mode 100644 index 00000000000..be88e7db140 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/Memory.inc @@ -0,0 +1,265 @@ +//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines some functions for various memory management utilities. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Process.h" + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#ifdef __APPLE__ +#include <mach/mach.h> +#endif + +#ifdef __Fuchsia__ +#include <zircon/syscalls.h> +#endif + +#if defined(__mips__) +#  if defined(__OpenBSD__) +#    include <mips64/sysarch.h> +#  elif !defined(__FreeBSD__) +#    include <sys/cachectl.h> +#  endif +#endif + +#if defined(__APPLE__) +extern "C" void sys_icache_invalidate(const void *Addr, size_t len); +#else +extern "C" void __clear_cache(void *, void*); +#endif + +static int getPosixProtectionFlags(unsigned Flags) { +  switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { +  case llvm::sys::Memory::MF_READ: +    return PROT_READ; +  case llvm::sys::Memory::MF_WRITE: +    return PROT_WRITE; +  case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: +    return PROT_READ | PROT_WRITE; +  case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: +    return PROT_READ | PROT_EXEC; +  case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE | +      llvm::sys::Memory::MF_EXEC: +    return PROT_READ | PROT_WRITE | PROT_EXEC; +  case llvm::sys::Memory::MF_EXEC: +#if (defined(__FreeBSD__) || defined(__POWERPC__) || defined (__ppc__) || \ +     defined(_POWER) || defined(_ARCH_PPC)) +    // On PowerPC, having an executable page that has no read permission +    // can have unintended consequences.  The function InvalidateInstruction- +    // Cache uses instructions dcbf and icbi, both of which are treated by +    // the processor as loads.  If the page has no read permissions, +    // executing these instructions will result in a segmentation fault. +    return PROT_READ | PROT_EXEC; +#else +    return PROT_EXEC; +#endif +  default: +    llvm_unreachable("Illegal memory protection flag specified!"); +  } +  // Provide a default return value as required by some compilers. +  return PROT_NONE; +} + +namespace llvm { +namespace sys { + +MemoryBlock +Memory::allocateMappedMemory(size_t NumBytes, +                             const MemoryBlock *const NearBlock, +                             unsigned PFlags, +                             std::error_code &EC) { +  EC = std::error_code(); +  if (NumBytes == 0) +    return MemoryBlock(); + +  // On platforms that have it, we can use MAP_ANON to get a memory-mapped +  // page without file backing, but we need a fallback of opening /dev/zero +  // for strictly POSIX platforms instead. +  int fd; +#if defined(MAP_ANON) +  fd = -1; +#else +  fd = open("/dev/zero", O_RDWR); +  if (fd == -1) { +    EC = std::error_code(errno, std::generic_category()); +    return MemoryBlock(); +  } +#endif + +  int MMFlags = MAP_PRIVATE; +#if defined(MAP_ANON) +  MMFlags |= MAP_ANON; +#endif +  int Protect = getPosixProtectionFlags(PFlags); + +#if defined(__NetBSD__) && defined(PROT_MPROTECT) +  Protect |= PROT_MPROTECT(PROT_READ | PROT_WRITE | PROT_EXEC); +#endif + +  // Use any near hint and the page size to set a page-aligned starting address +  uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + +                                      NearBlock->allocatedSize() : 0; +  static const size_t PageSize = Process::getPageSizeEstimate(); +  const size_t NumPages = (NumBytes+PageSize-1)/PageSize; + +  if (Start && Start % PageSize) +    Start += PageSize - Start % PageSize; + +  // FIXME: Handle huge page requests (MF_HUGE_HINT). +  void *Addr = ::mmap(reinterpret_cast<void *>(Start), PageSize*NumPages, Protect, +                      MMFlags, fd, 0); +  if (Addr == MAP_FAILED) { +    if (NearBlock) { //Try again without a near hint +#if !defined(MAP_ANON) +      close(fd); +#endif +      return allocateMappedMemory(NumBytes, nullptr, PFlags, EC); +    } + +    EC = std::error_code(errno, std::generic_category()); +#if !defined(MAP_ANON) +    close(fd); +#endif +    return MemoryBlock(); +  } + +#if !defined(MAP_ANON) +  close(fd); +#endif + +  MemoryBlock Result; +  Result.Address = Addr; +  Result.AllocatedSize = PageSize*NumPages; +  Result.Flags = PFlags; + +  // Rely on protectMappedMemory to invalidate instruction cache. +  if (PFlags & MF_EXEC) { +    EC = Memory::protectMappedMemory (Result, PFlags); +    if (EC != std::error_code()) +      return MemoryBlock(); +  } + +  return Result; +} + +std::error_code +Memory::releaseMappedMemory(MemoryBlock &M) { +  if (M.Address == nullptr || M.AllocatedSize == 0) +    return std::error_code(); + +  if (0 != ::munmap(M.Address, M.AllocatedSize)) +    return std::error_code(errno, std::generic_category()); + +  M.Address = nullptr; +  M.AllocatedSize = 0; + +  return std::error_code(); +} + +std::error_code +Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { +  static const Align PageSize = Align(Process::getPageSizeEstimate()); +  if (M.Address == nullptr || M.AllocatedSize == 0) +    return std::error_code(); + +  if (!Flags) +    return std::error_code(EINVAL, std::generic_category()); + +  int Protect = getPosixProtectionFlags(Flags); +  uintptr_t Start = alignAddr((const uint8_t *)M.Address - PageSize.value() + 1, PageSize); +  uintptr_t End = alignAddr((const uint8_t *)M.Address + M.AllocatedSize, PageSize); + +  bool InvalidateCache = (Flags & MF_EXEC); + +#if defined(__arm__) || defined(__aarch64__) +  // Certain ARM implementations treat icache clear instruction as a memory read, +  // and CPU segfaults on trying to clear cache on !PROT_READ page.  Therefore we need +  // to temporarily add PROT_READ for the sake of flushing the instruction caches. +  if (InvalidateCache && !(Protect & PROT_READ)) { +    int Result = ::mprotect((void *)Start, End - Start, Protect | PROT_READ); +    if (Result != 0) +      return std::error_code(errno, std::generic_category()); + +    Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); +    InvalidateCache = false; +  } +#endif + +  int Result = ::mprotect((void *)Start, End - Start, Protect); + +  if (Result != 0) +    return std::error_code(errno, std::generic_category()); + +  if (InvalidateCache) +    Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); + +  return std::error_code(); +} + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void Memory::InvalidateInstructionCache(const void *Addr, +                                        size_t Len) { + +// icache invalidation for PPC and ARM. +#if defined(__APPLE__) + +#  if (defined(__POWERPC__) || defined (__ppc__) || \ +       defined(_POWER) || defined(_ARCH_PPC) || defined(__arm__) || \ +       defined(__arm64__)) +  sys_icache_invalidate(const_cast<void *>(Addr), Len); +#  endif + +#elif defined(__Fuchsia__) + +  zx_status_t Status = zx_cache_flush(Addr, Len, ZX_CACHE_FLUSH_INSN); +  assert(Status == ZX_OK && "cannot invalidate instruction cache"); + +#else + +#  if (defined(__POWERPC__) || defined (__ppc__) || \ +       defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) +  const size_t LineSize = 32; + +  const intptr_t Mask = ~(LineSize - 1); +  const intptr_t StartLine = ((intptr_t) Addr) & Mask; +  const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; + +  for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) +    asm volatile("dcbf 0, %0" : : "r"(Line)); +  asm volatile("sync"); + +  for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) +    asm volatile("icbi 0, %0" : : "r"(Line)); +  asm volatile("isync"); +#  elif (defined(__arm__) || defined(__aarch64__) || defined(__mips__)) && \ +        defined(__GNUC__) +  // FIXME: Can we safely always call this for __GNUC__ everywhere? +  const char *Start = static_cast<const char *>(Addr); +  const char *End = Start + Len; +  __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); +#  endif + +#endif  // end apple + +  ValgrindDiscardTranslations(Addr, Len); +} + +} // namespace sys +} // namespace llvm diff --git a/contrib/libs/llvm12/lib/Support/Unix/Path.inc b/contrib/libs/llvm12/lib/Support/Unix/Path.inc new file mode 100644 index 00000000000..996b8aebf61 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/Path.inc @@ -0,0 +1,1379 @@ +//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific implementation of the Path API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//===          is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include <limits.h> +#include <stdio.h> +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#include <dirent.h> +#include <pwd.h> +#include <sys/file.h> + +#ifdef __APPLE__ +#include <mach-o/dyld.h> +#include <sys/attr.h> +#include <copyfile.h> +#elif defined(__FreeBSD__) +#include <osreldate.h> +#if __FreeBSD_version >= 1300057 +#include <sys/auxv.h> +#else +#error #include <machine/elf.h> +extern char **environ; +#endif +#elif defined(__DragonFly__) +#include <sys/mount.h> +#elif defined(__MVS__) +#error #include <sys/ps.h> +#endif + +// Both stdio.h and cstdio are included via different paths and +// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros +// either. +#undef ferror +#undef feof + +#if !defined(PATH_MAX) +// For GNU Hurd +#if defined(__GNU__) +#define PATH_MAX 4096 +#elif defined(__MVS__) +#define PATH_MAX _XOPEN_PATH_MAX +#endif +#endif + +#include <sys/types.h> +#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) &&   \ +    !defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX) +#include <sys/statvfs.h> +#define STATVFS statvfs +#define FSTATVFS fstatvfs +#define STATVFS_F_FRSIZE(vfs) vfs.f_frsize +#else +#if defined(__OpenBSD__) || defined(__FreeBSD__) +#include <sys/mount.h> +#include <sys/param.h> +#elif defined(__linux__) +#if defined(HAVE_LINUX_MAGIC_H) +#include <linux/magic.h> +#else +#if defined(HAVE_LINUX_NFS_FS_H) +#include <linux/nfs_fs.h> +#endif +#if defined(HAVE_LINUX_SMB_H) +#include <linux/smb.h> +#endif +#endif +#include <sys/vfs.h> +#elif defined(_AIX) +#include <sys/statfs.h> + +// <sys/vmount.h> depends on `uint` to be a typedef from <sys/types.h> to +// `uint_t`; however, <sys/types.h> does not always declare `uint`. We provide +// the typedef prior to including <sys/vmount.h> to work around this issue. +typedef uint_t uint; +#include <sys/vmount.h> +#else +#include <sys/mount.h> +#endif +#define STATVFS statfs +#define FSTATVFS fstatfs +#define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize) +#endif + +#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__) || \ +    defined(__MVS__) +#define STATVFS_F_FLAG(vfs) (vfs).f_flag +#else +#define STATVFS_F_FLAG(vfs) (vfs).f_flags +#endif + +using namespace llvm; + +namespace llvm { +namespace sys  { +namespace fs { + +const file_t kInvalidFile = -1; + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \ +    defined(__minix) || defined(__FreeBSD_kernel__) || defined(__linux__) ||   \ +    defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX) || defined(__GNU__) +static int +test_dir(char ret[PATH_MAX], const char *dir, const char *bin) +{ +  struct stat sb; +  char fullpath[PATH_MAX]; + +  int chars = snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin); +  // We cannot write PATH_MAX characters because the string will be terminated +  // with a null character. Fail if truncation happened. +  if (chars >= PATH_MAX) +    return 1; +  if (!realpath(fullpath, ret)) +    return 1; +  if (stat(fullpath, &sb) != 0) +    return 1; + +  return 0; +} + +static char * +getprogpath(char ret[PATH_MAX], const char *bin) +{ +  if (bin == nullptr) +    return nullptr; + +  /* First approach: absolute path. */ +  if (bin[0] == '/') { +    if (test_dir(ret, "/", bin) == 0) +      return ret; +    return nullptr; +  } + +  /* Second approach: relative path. */ +  if (strchr(bin, '/')) { +    char cwd[PATH_MAX]; +    if (!getcwd(cwd, PATH_MAX)) +      return nullptr; +    if (test_dir(ret, cwd, bin) == 0) +      return ret; +    return nullptr; +  } + +  /* Third approach: $PATH */ +  char *pv; +  if ((pv = getenv("PATH")) == nullptr) +    return nullptr; +  char *s = strdup(pv); +  if (!s) +    return nullptr; +  char *state; +  for (char *t = strtok_r(s, ":", &state); t != nullptr; +       t = strtok_r(nullptr, ":", &state)) { +    if (test_dir(ret, t, bin) == 0) { +      free(s); +      return ret; +    } +  } +  free(s); +  return nullptr; +} +#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ + +/// GetMainExecutable - Return the path to the main executable, given the +/// value of argv[0] from program startup. +std::string getMainExecutable(const char *argv0, void *MainAddr) { +#if defined(__APPLE__) +  // On OS X the executable path is saved to the stack by dyld. Reading it +  // from there is much faster than calling dladdr, especially for large +  // binaries with symbols. +  char exe_path[PATH_MAX]; +  uint32_t size = sizeof(exe_path); +  if (_NSGetExecutablePath(exe_path, &size) == 0) { +    char link_path[PATH_MAX]; +    if (realpath(exe_path, link_path)) +      return link_path; +  } +#elif defined(__FreeBSD__) +  // On FreeBSD if the exec path specified in ELF auxiliary vectors is +  // preferred, if available.  /proc/curproc/file and the KERN_PROC_PATHNAME +  // sysctl may not return the desired path if there are multiple hardlinks +  // to the file. +  char exe_path[PATH_MAX]; +#if __FreeBSD_version >= 1300057 +  if (elf_aux_info(AT_EXECPATH, exe_path, sizeof(exe_path)) == 0) +    return exe_path; +#else +  // elf_aux_info(AT_EXECPATH, ... is not available in all supported versions, +  // fall back to finding the ELF auxiliary vectors after the process's +  // environment. +  char **p = ::environ; +  while (*p++ != 0) +    ; +  // Iterate through auxiliary vectors for AT_EXECPATH. +  for (; *(uintptr_t *)p != AT_NULL; p++) { +    if (*(uintptr_t *)p++ == AT_EXECPATH) +      return *p; +  } +#endif +  // Fall back to argv[0] if auxiliary vectors are not available. +  if (getprogpath(exe_path, argv0) != NULL) +    return exe_path; +#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__minix) ||       \ +    defined(__DragonFly__) || defined(__FreeBSD_kernel__) || defined(_AIX) +  const char *curproc = "/proc/curproc/file"; +  char exe_path[PATH_MAX]; +  if (sys::fs::exists(curproc)) { +    ssize_t len = readlink(curproc, exe_path, sizeof(exe_path)); +    if (len > 0) { +      // Null terminate the string for realpath. readlink never null +      // terminates its output. +      len = std::min(len, ssize_t(sizeof(exe_path) - 1)); +      exe_path[len] = '\0'; +      return exe_path; +    } +  } +  // If we don't have procfs mounted, fall back to argv[0] +  if (getprogpath(exe_path, argv0) != NULL) +    return exe_path; +#elif defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__) +  char exe_path[PATH_MAX]; +  const char *aPath = "/proc/self/exe"; +  if (sys::fs::exists(aPath)) { +    // /proc is not always mounted under Linux (chroot for example). +    ssize_t len = readlink(aPath, exe_path, sizeof(exe_path)); +    if (len < 0) +      return ""; + +    // Null terminate the string for realpath. readlink never null +    // terminates its output. +    len = std::min(len, ssize_t(sizeof(exe_path) - 1)); +    exe_path[len] = '\0'; + +    // On Linux, /proc/self/exe always looks through symlinks. However, on +    // GNU/Hurd, /proc/self/exe is a symlink to the path that was used to start +    // the program, and not the eventual binary file. Therefore, call realpath +    // so this behaves the same on all platforms. +#if _POSIX_VERSION >= 200112 || defined(__GLIBC__) +    if (char *real_path = realpath(exe_path, NULL)) { +      std::string ret = std::string(real_path); +      free(real_path); +      return ret; +    } +#else +    char real_path[PATH_MAX]; +    if (realpath(exe_path, real_path)) +      return std::string(real_path); +#endif +  } +  // Fall back to the classical detection. +  if (getprogpath(exe_path, argv0)) +    return exe_path; +#elif defined(__MVS__) +  int token = 0; +  W_PSPROC buf; +  char exe_path[PS_PATHBLEN]; +  pid_t pid = getpid(); + +  memset(&buf, 0, sizeof(buf)); +  buf.ps_pathptr = exe_path; +  buf.ps_pathlen = sizeof(exe_path); + +  while (true) { +    if ((token = w_getpsent(token, &buf, sizeof(buf))) <= 0) +      break; +    if (buf.ps_pid != pid) +      continue; +    char real_path[PATH_MAX]; +    if (realpath(exe_path, real_path)) +      return std::string(real_path); +    break;  // Found entry, but realpath failed. +  } +#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR) +  // Use dladdr to get executable path if available. +  Dl_info DLInfo; +  int err = dladdr(MainAddr, &DLInfo); +  if (err == 0) +    return ""; + +  // If the filename is a symlink, we need to resolve and return the location of +  // the actual executable. +  char link_path[PATH_MAX]; +  if (realpath(DLInfo.dli_fname, link_path)) +    return link_path; +#else +#error GetMainExecutable is not implemented on this host yet. +#endif +  return ""; +} + +TimePoint<> basic_file_status::getLastAccessedTime() const { +  return toTimePoint(fs_st_atime, fs_st_atime_nsec); +} + +TimePoint<> basic_file_status::getLastModificationTime() const { +  return toTimePoint(fs_st_mtime, fs_st_mtime_nsec); +} + +UniqueID file_status::getUniqueID() const { +  return UniqueID(fs_st_dev, fs_st_ino); +} + +uint32_t file_status::getLinkCount() const { +  return fs_st_nlinks; +} + +ErrorOr<space_info> disk_space(const Twine &Path) { +  struct STATVFS Vfs; +  if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs)) +    return std::error_code(errno, std::generic_category()); +  auto FrSize = STATVFS_F_FRSIZE(Vfs); +  space_info SpaceInfo; +  SpaceInfo.capacity = static_cast<uint64_t>(Vfs.f_blocks) * FrSize; +  SpaceInfo.free = static_cast<uint64_t>(Vfs.f_bfree) * FrSize; +  SpaceInfo.available = static_cast<uint64_t>(Vfs.f_bavail) * FrSize; +  return SpaceInfo; +} + +std::error_code current_path(SmallVectorImpl<char> &result) { +  result.clear(); + +  const char *pwd = ::getenv("PWD"); +  llvm::sys::fs::file_status PWDStatus, DotStatus; +  if (pwd && llvm::sys::path::is_absolute(pwd) && +      !llvm::sys::fs::status(pwd, PWDStatus) && +      !llvm::sys::fs::status(".", DotStatus) && +      PWDStatus.getUniqueID() == DotStatus.getUniqueID()) { +    result.append(pwd, pwd + strlen(pwd)); +    return std::error_code(); +  } + +  result.reserve(PATH_MAX); + +  while (true) { +    if (::getcwd(result.data(), result.capacity()) == nullptr) { +      // See if there was a real error. +      if (errno != ENOMEM) +        return std::error_code(errno, std::generic_category()); +      // Otherwise there just wasn't enough space. +      result.reserve(result.capacity() * 2); +    } else +      break; +  } + +  result.set_size(strlen(result.data())); +  return std::error_code(); +} + +std::error_code set_current_path(const Twine &path) { +  SmallString<128> path_storage; +  StringRef p = path.toNullTerminatedStringRef(path_storage); + +  if (::chdir(p.begin()) == -1) +    return std::error_code(errno, std::generic_category()); + +  return std::error_code(); +} + +std::error_code create_directory(const Twine &path, bool IgnoreExisting, +                                 perms Perms) { +  SmallString<128> path_storage; +  StringRef p = path.toNullTerminatedStringRef(path_storage); + +  if (::mkdir(p.begin(), Perms) == -1) { +    if (errno != EEXIST || !IgnoreExisting) +      return std::error_code(errno, std::generic_category()); +  } + +  return std::error_code(); +} + +// Note that we are using symbolic link because hard links are not supported by +// all filesystems (SMB doesn't). +std::error_code create_link(const Twine &to, const Twine &from) { +  // Get arguments. +  SmallString<128> from_storage; +  SmallString<128> to_storage; +  StringRef f = from.toNullTerminatedStringRef(from_storage); +  StringRef t = to.toNullTerminatedStringRef(to_storage); + +  if (::symlink(t.begin(), f.begin()) == -1) +    return std::error_code(errno, std::generic_category()); + +  return std::error_code(); +} + +std::error_code create_hard_link(const Twine &to, const Twine &from) { +  // Get arguments. +  SmallString<128> from_storage; +  SmallString<128> to_storage; +  StringRef f = from.toNullTerminatedStringRef(from_storage); +  StringRef t = to.toNullTerminatedStringRef(to_storage); + +  if (::link(t.begin(), f.begin()) == -1) +    return std::error_code(errno, std::generic_category()); + +  return std::error_code(); +} + +std::error_code remove(const Twine &path, bool IgnoreNonExisting) { +  SmallString<128> path_storage; +  StringRef p = path.toNullTerminatedStringRef(path_storage); + +  struct stat buf; +  if (lstat(p.begin(), &buf) != 0) { +    if (errno != ENOENT || !IgnoreNonExisting) +      return std::error_code(errno, std::generic_category()); +    return std::error_code(); +  } + +  // Note: this check catches strange situations. In all cases, LLVM should +  // only be involved in the creation and deletion of regular files.  This +  // check ensures that what we're trying to erase is a regular file. It +  // effectively prevents LLVM from erasing things like /dev/null, any block +  // special file, or other things that aren't "regular" files. +  if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode) && !S_ISLNK(buf.st_mode)) +    return make_error_code(errc::operation_not_permitted); + +  if (::remove(p.begin()) == -1) { +    if (errno != ENOENT || !IgnoreNonExisting) +      return std::error_code(errno, std::generic_category()); +  } + +  return std::error_code(); +} + +static bool is_local_impl(struct STATVFS &Vfs) { +#if defined(__linux__) || defined(__GNU__) +#ifndef NFS_SUPER_MAGIC +#define NFS_SUPER_MAGIC 0x6969 +#endif +#ifndef SMB_SUPER_MAGIC +#define SMB_SUPER_MAGIC 0x517B +#endif +#ifndef CIFS_MAGIC_NUMBER +#define CIFS_MAGIC_NUMBER 0xFF534D42 +#endif +#ifdef __GNU__ +  switch ((uint32_t)Vfs.__f_type) { +#else +  switch ((uint32_t)Vfs.f_type) { +#endif +  case NFS_SUPER_MAGIC: +  case SMB_SUPER_MAGIC: +  case CIFS_MAGIC_NUMBER: +    return false; +  default: +    return true; +  } +#elif defined(__CYGWIN__) +  // Cygwin doesn't expose this information; would need to use Win32 API. +  return false; +#elif defined(__Fuchsia__) +  // Fuchsia doesn't yet support remote filesystem mounts. +  return true; +#elif defined(__EMSCRIPTEN__) +  // Emscripten doesn't currently support remote filesystem mounts. +  return true; +#elif defined(__HAIKU__) +  // Haiku doesn't expose this information. +  return false; +#elif defined(__sun) +  // statvfs::f_basetype contains a null-terminated FSType name of the mounted target +  StringRef fstype(Vfs.f_basetype); +  // NFS is the only non-local fstype?? +  return !fstype.equals("nfs"); +#elif defined(_AIX) +  // Call mntctl; try more than twice in case of timing issues with a concurrent +  // mount. +  int Ret; +  size_t BufSize = 2048u; +  std::unique_ptr<char[]> Buf; +  int Tries = 3; +  while (Tries--) { +    Buf = std::make_unique<char[]>(BufSize); +    Ret = mntctl(MCTL_QUERY, BufSize, Buf.get()); +    if (Ret != 0) +      break; +    BufSize = *reinterpret_cast<unsigned int *>(Buf.get()); +    Buf.reset(); +  } + +  if (Ret == -1) +    // There was an error; "remote" is the conservative answer. +    return false; + +  // Look for the correct vmount entry. +  char *CurObjPtr = Buf.get(); +  while (Ret--) { +    struct vmount *Vp = reinterpret_cast<struct vmount *>(CurObjPtr); +    static_assert(sizeof(Vfs.f_fsid) == sizeof(Vp->vmt_fsid), +                  "fsid length mismatch"); +    if (memcmp(&Vfs.f_fsid, &Vp->vmt_fsid, sizeof Vfs.f_fsid) == 0) +      return (Vp->vmt_flags & MNT_REMOTE) == 0; + +    CurObjPtr += Vp->vmt_length; +  } + +  // vmount entry not found; "remote" is the conservative answer. +  return false; +#elif defined(__MVS__) +  // The file system can have an arbitrary structure on z/OS; must go with the +  // conservative answer. +  return false; +#else +  return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL); +#endif +} + +std::error_code is_local(const Twine &Path, bool &Result) { +  struct STATVFS Vfs; +  if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs)) +    return std::error_code(errno, std::generic_category()); + +  Result = is_local_impl(Vfs); +  return std::error_code(); +} + +std::error_code is_local(int FD, bool &Result) { +  struct STATVFS Vfs; +  if (::FSTATVFS(FD, &Vfs)) +    return std::error_code(errno, std::generic_category()); + +  Result = is_local_impl(Vfs); +  return std::error_code(); +} + +std::error_code rename(const Twine &from, const Twine &to) { +  // Get arguments. +  SmallString<128> from_storage; +  SmallString<128> to_storage; +  StringRef f = from.toNullTerminatedStringRef(from_storage); +  StringRef t = to.toNullTerminatedStringRef(to_storage); + +  if (::rename(f.begin(), t.begin()) == -1) +    return std::error_code(errno, std::generic_category()); + +  return std::error_code(); +} + +std::error_code resize_file(int FD, uint64_t Size) { +#if defined(HAVE_POSIX_FALLOCATE) +  // If we have posix_fallocate use it. Unlike ftruncate it always allocates +  // space, so we get an error if the disk is full. +  if (int Err = ::posix_fallocate(FD, 0, Size)) { +#ifdef _AIX +    constexpr int NotSupportedError = ENOTSUP; +#else +    constexpr int NotSupportedError = EOPNOTSUPP; +#endif +    if (Err != EINVAL && Err != NotSupportedError) +      return std::error_code(Err, std::generic_category()); +  } +#endif +  // Use ftruncate as a fallback. It may or may not allocate space. At least on +  // OS X with HFS+ it does. +  if (::ftruncate(FD, Size) == -1) +    return std::error_code(errno, std::generic_category()); + +  return std::error_code(); +} + +static int convertAccessMode(AccessMode Mode) { +  switch (Mode) { +  case AccessMode::Exist: +    return F_OK; +  case AccessMode::Write: +    return W_OK; +  case AccessMode::Execute: +    return R_OK | X_OK; // scripts also need R_OK. +  } +  llvm_unreachable("invalid enum"); +} + +std::error_code access(const Twine &Path, AccessMode Mode) { +  SmallString<128> PathStorage; +  StringRef P = Path.toNullTerminatedStringRef(PathStorage); + +  if (::access(P.begin(), convertAccessMode(Mode)) == -1) +    return std::error_code(errno, std::generic_category()); + +  if (Mode == AccessMode::Execute) { +    // Don't say that directories are executable. +    struct stat buf; +    if (0 != stat(P.begin(), &buf)) +      return errc::permission_denied; +    if (!S_ISREG(buf.st_mode)) +      return errc::permission_denied; +  } + +  return std::error_code(); +} + +bool can_execute(const Twine &Path) { +  return !access(Path, AccessMode::Execute); +} + +bool equivalent(file_status A, file_status B) { +  assert(status_known(A) && status_known(B)); +  return A.fs_st_dev == B.fs_st_dev && +         A.fs_st_ino == B.fs_st_ino; +} + +std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { +  file_status fsA, fsB; +  if (std::error_code ec = status(A, fsA)) +    return ec; +  if (std::error_code ec = status(B, fsB)) +    return ec; +  result = equivalent(fsA, fsB); +  return std::error_code(); +} + +static void expandTildeExpr(SmallVectorImpl<char> &Path) { +  StringRef PathStr(Path.begin(), Path.size()); +  if (PathStr.empty() || !PathStr.startswith("~")) +    return; + +  PathStr = PathStr.drop_front(); +  StringRef Expr = +      PathStr.take_until([](char c) { return path::is_separator(c); }); +  StringRef Remainder = PathStr.substr(Expr.size() + 1); +  SmallString<128> Storage; +  if (Expr.empty()) { +    // This is just ~/..., resolve it to the current user's home dir. +    if (!path::home_directory(Storage)) { +      // For some reason we couldn't get the home directory.  Just exit. +      return; +    } + +    // Overwrite the first character and insert the rest. +    Path[0] = Storage[0]; +    Path.insert(Path.begin() + 1, Storage.begin() + 1, Storage.end()); +    return; +  } + +  // This is a string of the form ~username/, look up this user's entry in the +  // password database. +  struct passwd *Entry = nullptr; +  std::string User = Expr.str(); +  Entry = ::getpwnam(User.c_str()); + +  if (!Entry) { +    // Unable to look up the entry, just return back the original path. +    return; +  } + +  Storage = Remainder; +  Path.clear(); +  Path.append(Entry->pw_dir, Entry->pw_dir + strlen(Entry->pw_dir)); +  llvm::sys::path::append(Path, Storage); +} + + +void expand_tilde(const Twine &path, SmallVectorImpl<char> &dest) { +  dest.clear(); +  if (path.isTriviallyEmpty()) +    return; + +  path.toVector(dest); +  expandTildeExpr(dest); +} + +static file_type typeForMode(mode_t Mode) { +  if (S_ISDIR(Mode)) +    return file_type::directory_file; +  else if (S_ISREG(Mode)) +    return file_type::regular_file; +  else if (S_ISBLK(Mode)) +    return file_type::block_file; +  else if (S_ISCHR(Mode)) +    return file_type::character_file; +  else if (S_ISFIFO(Mode)) +    return file_type::fifo_file; +  else if (S_ISSOCK(Mode)) +    return file_type::socket_file; +  else if (S_ISLNK(Mode)) +    return file_type::symlink_file; +  return file_type::type_unknown; +} + +static std::error_code fillStatus(int StatRet, const struct stat &Status, +                                  file_status &Result) { +  if (StatRet != 0) { +    std::error_code EC(errno, std::generic_category()); +    if (EC == errc::no_such_file_or_directory) +      Result = file_status(file_type::file_not_found); +    else +      Result = file_status(file_type::status_error); +    return EC; +  } + +  uint32_t atime_nsec, mtime_nsec; +#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) +  atime_nsec = Status.st_atimespec.tv_nsec; +  mtime_nsec = Status.st_mtimespec.tv_nsec; +#elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) +  atime_nsec = Status.st_atim.tv_nsec; +  mtime_nsec = Status.st_mtim.tv_nsec; +#else +  atime_nsec = mtime_nsec = 0; +#endif + +  perms Perms = static_cast<perms>(Status.st_mode) & all_perms; +  Result = file_status(typeForMode(Status.st_mode), Perms, Status.st_dev, +                       Status.st_nlink, Status.st_ino, +                       Status.st_atime, atime_nsec, Status.st_mtime, mtime_nsec, +                       Status.st_uid, Status.st_gid, Status.st_size); + +  return std::error_code(); +} + +std::error_code status(const Twine &Path, file_status &Result, bool Follow) { +  SmallString<128> PathStorage; +  StringRef P = Path.toNullTerminatedStringRef(PathStorage); + +  struct stat Status; +  int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status); +  return fillStatus(StatRet, Status, Result); +} + +std::error_code status(int FD, file_status &Result) { +  struct stat Status; +  int StatRet = ::fstat(FD, &Status); +  return fillStatus(StatRet, Status, Result); +} + +unsigned getUmask() { +  // Chose arbitary new mask and reset the umask to the old mask. +  // umask(2) never fails so ignore the return of the second call. +  unsigned Mask = ::umask(0); +  (void) ::umask(Mask); +  return Mask; +} + +std::error_code setPermissions(const Twine &Path, perms Permissions) { +  SmallString<128> PathStorage; +  StringRef P = Path.toNullTerminatedStringRef(PathStorage); + +  if (::chmod(P.begin(), Permissions)) +    return std::error_code(errno, std::generic_category()); +  return std::error_code(); +} + +std::error_code setPermissions(int FD, perms Permissions) { +  if (::fchmod(FD, Permissions)) +    return std::error_code(errno, std::generic_category()); +  return std::error_code(); +} + +std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, +                                                 TimePoint<> ModificationTime) { +#if defined(HAVE_FUTIMENS) +  timespec Times[2]; +  Times[0] = sys::toTimeSpec(AccessTime); +  Times[1] = sys::toTimeSpec(ModificationTime); +  if (::futimens(FD, Times)) +    return std::error_code(errno, std::generic_category()); +  return std::error_code(); +#elif defined(HAVE_FUTIMES) +  timeval Times[2]; +  Times[0] = sys::toTimeVal( +      std::chrono::time_point_cast<std::chrono::microseconds>(AccessTime)); +  Times[1] = +      sys::toTimeVal(std::chrono::time_point_cast<std::chrono::microseconds>( +          ModificationTime)); +  if (::futimes(FD, Times)) +    return std::error_code(errno, std::generic_category()); +  return std::error_code(); +#elif defined(__MVS__) +  attrib_t Attr; +  memset(&Attr, 0, sizeof(Attr)); +  Attr.att_atimechg = 1; +  Attr.att_atime = sys::toTimeT(AccessTime); +  Attr.att_mtimechg = 1; +  Attr.att_mtime = sys::toTimeT(ModificationTime); +  if (::__fchattr(FD, &Attr, sizeof(Attr)) != 0) +    return std::error_code(errno, std::generic_category()); +  return std::error_code(); +#else +#warning Missing futimes() and futimens() +  return make_error_code(errc::function_not_supported); +#endif +} + +std::error_code mapped_file_region::init(int FD, uint64_t Offset, +                                         mapmode Mode) { +  assert(Size != 0); + +  int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; +  int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); +#if defined(__APPLE__) +  //---------------------------------------------------------------------- +  // Newer versions of MacOSX have a flag that will allow us to read from +  // binaries whose code signature is invalid without crashing by using +  // the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media +  // is mapped we can avoid crashing and return zeroes to any pages we try +  // to read if the media becomes unavailable by using the +  // MAP_RESILIENT_MEDIA flag.  These flags are only usable when mapping +  // with PROT_READ, so take care not to specify them otherwise. +  //---------------------------------------------------------------------- +  if (Mode == readonly) { +#if defined(MAP_RESILIENT_CODESIGN) +    flags |= MAP_RESILIENT_CODESIGN; +#endif +#if defined(MAP_RESILIENT_MEDIA) +    flags |= MAP_RESILIENT_MEDIA; +#endif +  } +#endif // #if defined (__APPLE__) + +  Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset); +  if (Mapping == MAP_FAILED) +    return std::error_code(errno, std::generic_category()); +  return std::error_code(); +} + +mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, +                                       uint64_t offset, std::error_code &ec) +    : Size(length), Mapping(), Mode(mode) { +  (void)Mode; +  ec = init(fd, offset, mode); +  if (ec) +    Mapping = nullptr; +} + +mapped_file_region::~mapped_file_region() { +  if (Mapping) +    ::munmap(Mapping, Size); +} + +size_t mapped_file_region::size() const { +  assert(Mapping && "Mapping failed but used anyway!"); +  return Size; +} + +char *mapped_file_region::data() const { +  assert(Mapping && "Mapping failed but used anyway!"); +  return reinterpret_cast<char*>(Mapping); +} + +const char *mapped_file_region::const_data() const { +  assert(Mapping && "Mapping failed but used anyway!"); +  return reinterpret_cast<const char*>(Mapping); +} + +int mapped_file_region::alignment() { +  return Process::getPageSizeEstimate(); +} + +std::error_code detail::directory_iterator_construct(detail::DirIterState &it, +                                                     StringRef path, +                                                     bool follow_symlinks) { +  SmallString<128> path_null(path); +  DIR *directory = ::opendir(path_null.c_str()); +  if (!directory) +    return std::error_code(errno, std::generic_category()); + +  it.IterationHandle = reinterpret_cast<intptr_t>(directory); +  // Add something for replace_filename to replace. +  path::append(path_null, "."); +  it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks); +  return directory_iterator_increment(it); +} + +std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) { +  if (it.IterationHandle) +    ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); +  it.IterationHandle = 0; +  it.CurrentEntry = directory_entry(); +  return std::error_code(); +} + +static file_type direntType(dirent* Entry) { +  // Most platforms provide the file type in the dirent: Linux/BSD/Mac. +  // The DTTOIF macro lets us reuse our status -> type conversion. +  // Note that while glibc provides a macro to see if this is supported, +  // _DIRENT_HAVE_D_TYPE, it's not defined on BSD/Mac, so we test for the +  // d_type-to-mode_t conversion macro instead. +#if defined(DTTOIF) +  return typeForMode(DTTOIF(Entry->d_type)); +#else +  // Other platforms such as Solaris require a stat() to get the type. +  return file_type::type_unknown; +#endif +} + +std::error_code detail::directory_iterator_increment(detail::DirIterState &It) { +  errno = 0; +  dirent *CurDir = ::readdir(reinterpret_cast<DIR *>(It.IterationHandle)); +  if (CurDir == nullptr && errno != 0) { +    return std::error_code(errno, std::generic_category()); +  } else if (CurDir != nullptr) { +    StringRef Name(CurDir->d_name); +    if ((Name.size() == 1 && Name[0] == '.') || +        (Name.size() == 2 && Name[0] == '.' && Name[1] == '.')) +      return directory_iterator_increment(It); +    It.CurrentEntry.replace_filename(Name, direntType(CurDir)); +  } else +    return directory_iterator_destruct(It); + +  return std::error_code(); +} + +ErrorOr<basic_file_status> directory_entry::status() const { +  file_status s; +  if (auto EC = fs::status(Path, s, FollowSymlinks)) +    return EC; +  return s; +} + +#if !defined(F_GETPATH) +static bool hasProcSelfFD() { +  // If we have a /proc filesystem mounted, we can quickly establish the +  // real name of the file with readlink +  static const bool Result = (::access("/proc/self/fd", R_OK) == 0); +  return Result; +} +#endif + +static int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags, +                           FileAccess Access) { +  int Result = 0; +  if (Access == FA_Read) +    Result |= O_RDONLY; +  else if (Access == FA_Write) +    Result |= O_WRONLY; +  else if (Access == (FA_Read | FA_Write)) +    Result |= O_RDWR; + +  // This is for compatibility with old code that assumed OF_Append implied +  // would open an existing file.  See Windows/Path.inc for a longer comment. +  if (Flags & OF_Append) +    Disp = CD_OpenAlways; + +  if (Disp == CD_CreateNew) { +    Result |= O_CREAT; // Create if it doesn't exist. +    Result |= O_EXCL;  // Fail if it does. +  } else if (Disp == CD_CreateAlways) { +    Result |= O_CREAT; // Create if it doesn't exist. +    Result |= O_TRUNC; // Truncate if it does. +  } else if (Disp == CD_OpenAlways) { +    Result |= O_CREAT; // Create if it doesn't exist. +  } else if (Disp == CD_OpenExisting) { +    // Nothing special, just don't add O_CREAT and we get these semantics. +  } + +  if (Flags & OF_Append) +    Result |= O_APPEND; + +#ifdef O_CLOEXEC +  if (!(Flags & OF_ChildInherit)) +    Result |= O_CLOEXEC; +#endif + +  return Result; +} + +std::error_code openFile(const Twine &Name, int &ResultFD, +                         CreationDisposition Disp, FileAccess Access, +                         OpenFlags Flags, unsigned Mode) { +  int OpenFlags = nativeOpenFlags(Disp, Flags, Access); + +  SmallString<128> Storage; +  StringRef P = Name.toNullTerminatedStringRef(Storage); +  // Call ::open in a lambda to avoid overload resolution in RetryAfterSignal +  // when open is overloaded, such as in Bionic. +  auto Open = [&]() { return ::open(P.begin(), OpenFlags, Mode); }; +  if ((ResultFD = sys::RetryAfterSignal(-1, Open)) < 0) +    return std::error_code(errno, std::generic_category()); +#ifndef O_CLOEXEC +  if (!(Flags & OF_ChildInherit)) { +    int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC); +    (void)r; +    assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); +  } +#endif +  return std::error_code(); +} + +Expected<int> openNativeFile(const Twine &Name, CreationDisposition Disp, +                             FileAccess Access, OpenFlags Flags, +                             unsigned Mode) { + +  int FD; +  std::error_code EC = openFile(Name, FD, Disp, Access, Flags, Mode); +  if (EC) +    return errorCodeToError(EC); +  return FD; +} + +std::error_code openFileForRead(const Twine &Name, int &ResultFD, +                                OpenFlags Flags, +                                SmallVectorImpl<char> *RealPath) { +  std::error_code EC = +      openFile(Name, ResultFD, CD_OpenExisting, FA_Read, Flags, 0666); +  if (EC) +    return EC; + +  // Attempt to get the real name of the file, if the user asked +  if(!RealPath) +    return std::error_code(); +  RealPath->clear(); +#if defined(F_GETPATH) +  // When F_GETPATH is availble, it is the quickest way to get +  // the real path name. +  char Buffer[PATH_MAX]; +  if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1) +    RealPath->append(Buffer, Buffer + strlen(Buffer)); +#else +  char Buffer[PATH_MAX]; +  if (hasProcSelfFD()) { +    char ProcPath[64]; +    snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", ResultFD); +    ssize_t CharCount = ::readlink(ProcPath, Buffer, sizeof(Buffer)); +    if (CharCount > 0) +      RealPath->append(Buffer, Buffer + CharCount); +  } else { +    SmallString<128> Storage; +    StringRef P = Name.toNullTerminatedStringRef(Storage); + +    // Use ::realpath to get the real path name +    if (::realpath(P.begin(), Buffer) != nullptr) +      RealPath->append(Buffer, Buffer + strlen(Buffer)); +  } +#endif +  return std::error_code(); +} + +Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, +                                       SmallVectorImpl<char> *RealPath) { +  file_t ResultFD; +  std::error_code EC = openFileForRead(Name, ResultFD, Flags, RealPath); +  if (EC) +    return errorCodeToError(EC); +  return ResultFD; +} + +file_t getStdinHandle() { return 0; } +file_t getStdoutHandle() { return 1; } +file_t getStderrHandle() { return 2; } + +Expected<size_t> readNativeFile(file_t FD, MutableArrayRef<char> Buf) { +#if defined(__APPLE__) +  size_t Size = std::min<size_t>(Buf.size(), INT32_MAX); +#else +  size_t Size = Buf.size(); +#endif +  ssize_t NumRead = +      sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Size); +  if (ssize_t(NumRead) == -1) +    return errorCodeToError(std::error_code(errno, std::generic_category())); +  return NumRead; +} + +Expected<size_t> readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf, +                                     uint64_t Offset) { +#if defined(__APPLE__) +  size_t Size = std::min<size_t>(Buf.size(), INT32_MAX); +#else +  size_t Size = Buf.size(); +#endif +#ifdef HAVE_PREAD +  ssize_t NumRead = +      sys::RetryAfterSignal(-1, ::pread, FD, Buf.data(), Size, Offset); +#else +  if (lseek(FD, Offset, SEEK_SET) == -1) +    return errorCodeToError(std::error_code(errno, std::generic_category())); +  ssize_t NumRead = +      sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Size); +#endif +  if (NumRead == -1) +    return errorCodeToError(std::error_code(errno, std::generic_category())); +  return NumRead; +} + +std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout) { +  auto Start = std::chrono::steady_clock::now(); +  auto End = Start + Timeout; +  do { +    struct flock Lock; +    memset(&Lock, 0, sizeof(Lock)); +    Lock.l_type = F_WRLCK; +    Lock.l_whence = SEEK_SET; +    Lock.l_start = 0; +    Lock.l_len = 0; +    if (::fcntl(FD, F_SETLK, &Lock) != -1) +      return std::error_code(); +    int Error = errno; +    if (Error != EACCES && Error != EAGAIN) +      return std::error_code(Error, std::generic_category()); +    usleep(1000); +  } while (std::chrono::steady_clock::now() < End); +  return make_error_code(errc::no_lock_available); +} + +std::error_code lockFile(int FD) { +  struct flock Lock; +  memset(&Lock, 0, sizeof(Lock)); +  Lock.l_type = F_WRLCK; +  Lock.l_whence = SEEK_SET; +  Lock.l_start = 0; +  Lock.l_len = 0; +  if (::fcntl(FD, F_SETLKW, &Lock) != -1) +    return std::error_code(); +  int Error = errno; +  return std::error_code(Error, std::generic_category()); +} + +std::error_code unlockFile(int FD) { +  struct flock Lock; +  Lock.l_type = F_UNLCK; +  Lock.l_whence = SEEK_SET; +  Lock.l_start = 0; +  Lock.l_len = 0; +  if (::fcntl(FD, F_SETLK, &Lock) != -1) +    return std::error_code(); +  return std::error_code(errno, std::generic_category()); +} + +std::error_code closeFile(file_t &F) { +  file_t TmpF = F; +  F = kInvalidFile; +  return Process::SafelyCloseFileDescriptor(TmpF); +} + +template <typename T> +static std::error_code remove_directories_impl(const T &Entry, +                                               bool IgnoreErrors) { +  std::error_code EC; +  directory_iterator Begin(Entry, EC, false); +  directory_iterator End; +  while (Begin != End) { +    auto &Item = *Begin; +    ErrorOr<basic_file_status> st = Item.status(); +    if (!st && !IgnoreErrors) +      return st.getError(); + +    if (is_directory(*st)) { +      EC = remove_directories_impl(Item, IgnoreErrors); +      if (EC && !IgnoreErrors) +        return EC; +    } + +    EC = fs::remove(Item.path(), true); +    if (EC && !IgnoreErrors) +      return EC; + +    Begin.increment(EC); +    if (EC && !IgnoreErrors) +      return EC; +  } +  return std::error_code(); +} + +std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { +  auto EC = remove_directories_impl(path, IgnoreErrors); +  if (EC && !IgnoreErrors) +    return EC; +  EC = fs::remove(path, true); +  if (EC && !IgnoreErrors) +    return EC; +  return std::error_code(); +} + +std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, +                          bool expand_tilde) { +  dest.clear(); +  if (path.isTriviallyEmpty()) +    return std::error_code(); + +  if (expand_tilde) { +    SmallString<128> Storage; +    path.toVector(Storage); +    expandTildeExpr(Storage); +    return real_path(Storage, dest, false); +  } + +  SmallString<128> Storage; +  StringRef P = path.toNullTerminatedStringRef(Storage); +  char Buffer[PATH_MAX]; +  if (::realpath(P.begin(), Buffer) == nullptr) +    return std::error_code(errno, std::generic_category()); +  dest.append(Buffer, Buffer + strlen(Buffer)); +  return std::error_code(); +} + +} // end namespace fs + +namespace path { + +bool home_directory(SmallVectorImpl<char> &result) { +  char *RequestedDir = getenv("HOME"); +  if (!RequestedDir) { +    struct passwd *pw = getpwuid(getuid()); +    if (pw && pw->pw_dir) +      RequestedDir = pw->pw_dir; +  } +  if (!RequestedDir) +    return false; + +  result.clear(); +  result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); +  return true; +} + +static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) { +  #if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR) +  // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. +  // macros defined in <unistd.h> on darwin >= 9 +  int ConfName = TempDir ? _CS_DARWIN_USER_TEMP_DIR +                         : _CS_DARWIN_USER_CACHE_DIR; +  size_t ConfLen = confstr(ConfName, nullptr, 0); +  if (ConfLen > 0) { +    do { +      Result.resize(ConfLen); +      ConfLen = confstr(ConfName, Result.data(), Result.size()); +    } while (ConfLen > 0 && ConfLen != Result.size()); + +    if (ConfLen > 0) { +      assert(Result.back() == 0); +      Result.pop_back(); +      return true; +    } + +    Result.clear(); +  } +  #endif +  return false; +} + +bool user_config_directory(SmallVectorImpl<char> &result) { +#ifdef __APPLE__ +  // Mac: ~/Library/Preferences/ +  if (home_directory(result)) { +    append(result, "Library", "Preferences"); +    return true; +  } +#else +  // XDG_CONFIG_HOME as defined in the XDG Base Directory Specification: +  // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html +  if (const char *RequestedDir = getenv("XDG_CONFIG_HOME")) { +    result.clear(); +    result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); +    return true; +  } +#endif +  // Fallback: ~/.config +  if (!home_directory(result)) { +    return false; +  } +  append(result, ".config"); +  return true; +} + +bool cache_directory(SmallVectorImpl<char> &result) { +#ifdef __APPLE__ +  if (getDarwinConfDir(false/*tempDir*/, result)) { +    return true; +  } +#else +  // XDG_CACHE_HOME as defined in the XDG Base Directory Specification: +  // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html +  if (const char *RequestedDir = getenv("XDG_CACHE_HOME")) { +    result.clear(); +    result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); +    return true; +  } +#endif +  if (!home_directory(result)) { +    return false; +  } +  append(result, ".cache"); +  return true; +} + +static const char *getEnvTempDir() { +  // Check whether the temporary directory is specified by an environment +  // variable. +  const char *EnvironmentVariables[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}; +  for (const char *Env : EnvironmentVariables) { +    if (const char *Dir = std::getenv(Env)) +      return Dir; +  } + +  return nullptr; +} + +static const char *getDefaultTempDir(bool ErasedOnReboot) { +#ifdef P_tmpdir +  if ((bool)P_tmpdir) +    return P_tmpdir; +#endif + +  if (ErasedOnReboot) +    return "/tmp"; +  return "/var/tmp"; +} + +void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { +  Result.clear(); + +  if (ErasedOnReboot) { +    // There is no env variable for the cache directory. +    if (const char *RequestedDir = getEnvTempDir()) { +      Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); +      return; +    } +  } + +  if (getDarwinConfDir(ErasedOnReboot, Result)) +    return; + +  const char *RequestedDir = getDefaultTempDir(ErasedOnReboot); +  Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); +} + +} // end namespace path + +namespace fs { + +#ifdef __APPLE__ +/// This implementation tries to perform an APFS CoW clone of the file, +/// which can be much faster and uses less space. +/// Unfortunately fcopyfile(3) does not support COPYFILE_CLONE, so the +/// file descriptor variant of this function still uses the default +/// implementation. +std::error_code copy_file(const Twine &From, const Twine &To) { +  uint32_t Flag = COPYFILE_DATA; +#if __has_builtin(__builtin_available) && defined(COPYFILE_CLONE) +  if (__builtin_available(macos 10.12, *)) { +    bool IsSymlink; +    if (std::error_code Error = is_symlink_file(From, IsSymlink)) +      return Error; +    // COPYFILE_CLONE clones the symlink instead of following it +    // and returns EEXISTS if the target file already exists. +    if (!IsSymlink && !exists(To)) +      Flag = COPYFILE_CLONE; +  } +#endif +  int Status = +      copyfile(From.str().c_str(), To.str().c_str(), /* State */ NULL, Flag); + +  if (Status == 0) +    return std::error_code(); +  return std::error_code(errno, std::generic_category()); +} +#endif // __APPLE__ + +} // end namespace fs + +} // end namespace sys +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/Support/Unix/Process.inc b/contrib/libs/llvm12/lib/Support/Unix/Process.inc new file mode 100644 index 00000000000..7425d084da2 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/Process.inc @@ -0,0 +1,457 @@ +//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Unix implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" +#include "llvm/Support/ManagedStatic.h" +#include <mutex> +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if defined(HAVE_MALLINFO) +#include <malloc.h> +#endif +#if defined(HAVE_MALLCTL) +#include <malloc_np.h> +#endif +#ifdef HAVE_MALLOC_MALLOC_H +#include <malloc/malloc.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +#  include <sys/ioctl.h> +#endif +#ifdef HAVE_TERMIOS_H +#  include <termios.h> +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//===          is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +using namespace llvm; +using namespace sys; + +static std::pair<std::chrono::microseconds, std::chrono::microseconds> getRUsageTimes() { +#if defined(HAVE_GETRUSAGE) +  struct rusage RU; +  ::getrusage(RUSAGE_SELF, &RU); +  return { toDuration(RU.ru_utime), toDuration(RU.ru_stime) }; +#else +#warning Cannot get usage times on this platform +  return { std::chrono::microseconds::zero(), std::chrono::microseconds::zero() }; +#endif +} + +Process::Pid Process::getProcessId() { +  static_assert(sizeof(Pid) >= sizeof(pid_t), +                "Process::Pid should be big enough to store pid_t"); +  return Pid(::getpid()); +} + +// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and +// offset in mmap(3) should be aligned to the AllocationGranularity. +Expected<unsigned> Process::getPageSize() { +#if defined(HAVE_GETPAGESIZE) +  static const int page_size = ::getpagesize(); +#elif defined(HAVE_SYSCONF) +  static long page_size = ::sysconf(_SC_PAGE_SIZE); +#else +#error Cannot get the page size on this machine +#endif +  if (page_size == -1) +    return errorCodeToError(std::error_code(errno, std::generic_category())); + +  return static_cast<unsigned>(page_size); +} + +size_t Process::GetMallocUsage() { +#if defined(HAVE_MALLINFO) +  struct mallinfo mi; +  mi = ::mallinfo(); +  return mi.uordblks; +#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) +  malloc_statistics_t Stats; +  malloc_zone_statistics(malloc_default_zone(), &Stats); +  return Stats.size_in_use;   // darwin +#elif defined(HAVE_MALLCTL) +  size_t alloc, sz; +  sz = sizeof(size_t); +  if (mallctl("stats.allocated", &alloc, &sz, NULL, 0) == 0) +    return alloc; +  return 0; +#elif defined(HAVE_SBRK) +  // Note this is only an approximation and more closely resembles +  // the value returned by mallinfo in the arena field. +  static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); +  char *EndOfMemory = (char*)sbrk(0); +  if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) +    return EndOfMemory - StartOfMemory; +  return 0; +#else +#warning Cannot get malloc info on this platform +  return 0; +#endif +} + +void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time, +                           std::chrono::nanoseconds &sys_time) { +  elapsed = std::chrono::system_clock::now(); +  std::tie(user_time, sys_time) = getRUsageTimes(); +} + +#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) +#include <mach/mach.h> +#endif + +// Some LLVM programs such as bugpoint produce core files as a normal part of +// their operation. To prevent the disk from filling up, this function +// does what's necessary to prevent their generation. +void Process::PreventCoreFiles() { +#if HAVE_SETRLIMIT +  struct rlimit rlim; +  rlim.rlim_cur = rlim.rlim_max = 0; +  setrlimit(RLIMIT_CORE, &rlim); +#endif + +#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) +  // Disable crash reporting on Mac OS X 10.0-10.4 + +  // get information about the original set of exception ports for the task +  mach_msg_type_number_t Count = 0; +  exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; +  exception_port_t OriginalPorts[EXC_TYPES_COUNT]; +  exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; +  thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; +  kern_return_t err = +    task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, +                             &Count, OriginalPorts, OriginalBehaviors, +                             OriginalFlavors); +  if (err == KERN_SUCCESS) { +    // replace each with MACH_PORT_NULL. +    for (unsigned i = 0; i != Count; ++i) +      task_set_exception_ports(mach_task_self(), OriginalMasks[i], +                               MACH_PORT_NULL, OriginalBehaviors[i], +                               OriginalFlavors[i]); +  } + +  // Disable crash reporting on Mac OS X 10.5 +  signal(SIGABRT, _exit); +  signal(SIGILL,  _exit); +  signal(SIGFPE,  _exit); +  signal(SIGSEGV, _exit); +  signal(SIGBUS,  _exit); +#endif + +  coreFilesPrevented = true; +} + +Optional<std::string> Process::GetEnv(StringRef Name) { +  std::string NameStr = Name.str(); +  const char *Val = ::getenv(NameStr.c_str()); +  if (!Val) +    return None; +  return std::string(Val); +} + +namespace { +class FDCloser { +public: +  FDCloser(int &FD) : FD(FD), KeepOpen(false) {} +  void keepOpen() { KeepOpen = true; } +  ~FDCloser() { +    if (!KeepOpen && FD >= 0) +      ::close(FD); +  } + +private: +  FDCloser(const FDCloser &) = delete; +  void operator=(const FDCloser &) = delete; + +  int &FD; +  bool KeepOpen; +}; +} + +std::error_code Process::FixupStandardFileDescriptors() { +  int NullFD = -1; +  FDCloser FDC(NullFD); +  const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}; +  for (int StandardFD : StandardFDs) { +    struct stat st; +    errno = 0; +    if (RetryAfterSignal(-1, ::fstat, StandardFD, &st) < 0) { +      assert(errno && "expected errno to be set if fstat failed!"); +      // fstat should return EBADF if the file descriptor is closed. +      if (errno != EBADF) +        return std::error_code(errno, std::generic_category()); +    } +    // if fstat succeeds, move on to the next FD. +    if (!errno) +      continue; +    assert(errno == EBADF && "expected errno to have EBADF at this point!"); + +    if (NullFD < 0) { +      // Call ::open in a lambda to avoid overload resolution in +      // RetryAfterSignal when open is overloaded, such as in Bionic. +      auto Open = [&]() { return ::open("/dev/null", O_RDWR); }; +      if ((NullFD = RetryAfterSignal(-1, Open)) < 0) +        return std::error_code(errno, std::generic_category()); +    } + +    if (NullFD == StandardFD) +      FDC.keepOpen(); +    else if (dup2(NullFD, StandardFD) < 0) +      return std::error_code(errno, std::generic_category()); +  } +  return std::error_code(); +} + +std::error_code Process::SafelyCloseFileDescriptor(int FD) { +  // Create a signal set filled with *all* signals. +  sigset_t FullSet; +  if (sigfillset(&FullSet) < 0) +    return std::error_code(errno, std::generic_category()); +  // Atomically swap our current signal mask with a full mask. +  sigset_t SavedSet; +#if LLVM_ENABLE_THREADS +  if (int EC = pthread_sigmask(SIG_SETMASK, &FullSet, &SavedSet)) +    return std::error_code(EC, std::generic_category()); +#else +  if (sigprocmask(SIG_SETMASK, &FullSet, &SavedSet) < 0) +    return std::error_code(errno, std::generic_category()); +#endif +  // Attempt to close the file descriptor. +  // We need to save the error, if one occurs, because our subsequent call to +  // pthread_sigmask might tamper with errno. +  int ErrnoFromClose = 0; +  if (::close(FD) < 0) +    ErrnoFromClose = errno; +  // Restore the signal mask back to what we saved earlier. +  int EC = 0; +#if LLVM_ENABLE_THREADS +  EC = pthread_sigmask(SIG_SETMASK, &SavedSet, nullptr); +#else +  if (sigprocmask(SIG_SETMASK, &SavedSet, nullptr) < 0) +    EC = errno; +#endif +  // The error code from close takes precedence over the one from +  // pthread_sigmask. +  if (ErrnoFromClose) +    return std::error_code(ErrnoFromClose, std::generic_category()); +  return std::error_code(EC, std::generic_category()); +} + +bool Process::StandardInIsUserInput() { +  return FileDescriptorIsDisplayed(STDIN_FILENO); +} + +bool Process::StandardOutIsDisplayed() { +  return FileDescriptorIsDisplayed(STDOUT_FILENO); +} + +bool Process::StandardErrIsDisplayed() { +  return FileDescriptorIsDisplayed(STDERR_FILENO); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { +#if HAVE_ISATTY +  return isatty(fd); +#else +  // If we don't have isatty, just return false. +  return false; +#endif +} + +static unsigned getColumns() { +  // If COLUMNS is defined in the environment, wrap to that many columns. +  if (const char *ColumnsStr = std::getenv("COLUMNS")) { +    int Columns = std::atoi(ColumnsStr); +    if (Columns > 0) +      return Columns; +  } + +  // We used to call ioctl TIOCGWINSZ to determine the width. It is considered +  // unuseful. +  return 0; +} + +unsigned Process::StandardOutColumns() { +  if (!StandardOutIsDisplayed()) +    return 0; + +  return getColumns(); +} + +unsigned Process::StandardErrColumns() { +  if (!StandardErrIsDisplayed()) +    return 0; + +  return getColumns(); +} + +#ifdef LLVM_ENABLE_TERMINFO +// We manually declare these extern functions because finding the correct +// headers from various terminfo, curses, or other sources is harder than +// writing their specs down. +extern "C" int setupterm(char *term, int filedes, int *errret); +extern "C" struct term *set_curterm(struct term *termp); +extern "C" int del_curterm(struct term *termp); +extern "C" int tigetnum(char *capname); +#endif + +#ifdef LLVM_ENABLE_TERMINFO +static ManagedStatic<std::mutex> TermColorMutex; +#endif + +static bool terminalHasColors(int fd) { +#ifdef LLVM_ENABLE_TERMINFO +  // First, acquire a global lock because these C routines are thread hostile. +  std::lock_guard<std::mutex> G(*TermColorMutex); + +  int errret = 0; +  if (setupterm(nullptr, fd, &errret) != 0) +    // Regardless of why, if we can't get terminfo, we shouldn't try to print +    // colors. +    return false; + +  // Test whether the terminal as set up supports color output. How to do this +  // isn't entirely obvious. We can use the curses routine 'has_colors' but it +  // would be nice to avoid a dependency on curses proper when we can make do +  // with a minimal terminfo parsing library. Also, we don't really care whether +  // the terminal supports the curses-specific color changing routines, merely +  // if it will interpret ANSI color escape codes in a reasonable way. Thus, the +  // strategy here is just to query the baseline colors capability and if it +  // supports colors at all to assume it will translate the escape codes into +  // whatever range of colors it does support. We can add more detailed tests +  // here if users report them as necessary. +  // +  // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if +  // the terminfo says that no colors are supported. +  bool HasColors = tigetnum(const_cast<char *>("colors")) > 0; + +  // Now extract the structure allocated by setupterm and free its memory +  // through a really silly dance. +  struct term *termp = set_curterm(nullptr); +  (void)del_curterm(termp); // Drop any errors here. + +  // Return true if we found a color capabilities for the current terminal. +  if (HasColors) +    return true; +#else +  // When the terminfo database is not available, check if the current terminal +  // is one of terminals that are known to support ANSI color escape codes. +  if (const char *TermStr = std::getenv("TERM")) { +    return StringSwitch<bool>(TermStr) +      .Case("ansi", true) +      .Case("cygwin", true) +      .Case("linux", true) +      .StartsWith("screen", true) +      .StartsWith("xterm", true) +      .StartsWith("vt100", true) +      .StartsWith("rxvt", true) +      .EndsWith("color", true) +      .Default(false); +  } +#endif + +  // Otherwise, be conservative. +  return false; +} + +bool Process::FileDescriptorHasColors(int fd) { +  // A file descriptor has colors if it is displayed and the terminal has +  // colors. +  return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd); +} + +bool Process::StandardOutHasColors() { +  return FileDescriptorHasColors(STDOUT_FILENO); +} + +bool Process::StandardErrHasColors() { +  return FileDescriptorHasColors(STDERR_FILENO); +} + +void Process::UseANSIEscapeCodes(bool /*enable*/) { +  // No effect. +} + +bool Process::ColorNeedsFlush() { +  // No, we use ANSI escape sequences. +  return false; +} + +const char *Process::OutputColor(char code, bool bold, bool bg) { +  return colorcodes[bg?1:0][bold?1:0][code&7]; +} + +const char *Process::OutputBold(bool bg) { +  return "\033[1m"; +} + +const char *Process::OutputReverse() { +  return "\033[7m"; +} + +const char *Process::ResetColor() { +  return "\033[0m"; +} + +#if !HAVE_DECL_ARC4RANDOM +static unsigned GetRandomNumberSeed() { +  // Attempt to get the initial seed from /dev/urandom, if possible. +  int urandomFD = open("/dev/urandom", O_RDONLY); + +  if (urandomFD != -1) { +    unsigned seed; +    // Don't use a buffered read to avoid reading more data +    // from /dev/urandom than we need. +    int count = read(urandomFD, (void *)&seed, sizeof(seed)); + +    close(urandomFD); + +    // Return the seed if the read was successful. +    if (count == sizeof(seed)) +      return seed; +  } + +  // Otherwise, swizzle the current time and the process ID to form a reasonable +  // seed. +  const auto Now = std::chrono::high_resolution_clock::now(); +  return hash_combine(Now.time_since_epoch().count(), ::getpid()); +} +#endif + +unsigned llvm::sys::Process::GetRandomNumber() { +#if HAVE_DECL_ARC4RANDOM +  return arc4random(); +#else +  static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0); +  (void)x; +  return ::rand(); +#endif +} diff --git a/contrib/libs/llvm12/lib/Support/Unix/Program.inc b/contrib/libs/llvm12/lib/Support/Unix/Program.inc new file mode 100644 index 00000000000..fb56fa4b0d1 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/Program.inc @@ -0,0 +1,559 @@ +//===- llvm/Support/Unix/Program.cpp -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the Program class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//===          is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Program.h" + +#include "Unix.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/raw_ostream.h" +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_POSIX_SPAWN +#include <spawn.h> + +#if defined(__APPLE__) +#include <TargetConditionals.h> +#endif + +#if defined(__APPLE__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) +#define USE_NSGETENVIRON 1 +#else +#define USE_NSGETENVIRON 0 +#endif + +#if !USE_NSGETENVIRON +  extern char **environ; +#else +#include <crt_externs.h> // _NSGetEnviron +#endif +#endif + +using namespace llvm; +using namespace sys; + +ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {} + +ErrorOr<std::string> sys::findProgramByName(StringRef Name, +                                            ArrayRef<StringRef> Paths) { +  assert(!Name.empty() && "Must have a name!"); +  // Use the given path verbatim if it contains any slashes; this matches +  // the behavior of sh(1) and friends. +  if (Name.find('/') != StringRef::npos) return std::string(Name); + +  SmallVector<StringRef, 16> EnvironmentPaths; +  if (Paths.empty()) +    if (const char *PathEnv = std::getenv("PATH")) { +      SplitString(PathEnv, EnvironmentPaths, ":"); +      Paths = EnvironmentPaths; +    } + +  for (auto Path : Paths) { +    if (Path.empty()) +      continue; + +    // Check to see if this first directory contains the executable... +    SmallString<128> FilePath(Path); +    sys::path::append(FilePath, Name); +    if (sys::fs::can_execute(FilePath.c_str())) +      return std::string(FilePath.str());  // Found the executable! +  } +  return errc::no_such_file_or_directory; +} + +static bool RedirectIO(Optional<StringRef> Path, int FD, std::string* ErrMsg) { +  if (!Path) // Noop +    return false; +  std::string File; +  if (Path->empty()) +    // Redirect empty paths to /dev/null +    File = "/dev/null"; +  else +    File = std::string(*Path); + +  // Open the file +  int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); +  if (InFD == -1) { +    MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for " +              + (FD == 0 ? "input" : "output")); +    return true; +  } + +  // Install it as the requested FD +  if (dup2(InFD, FD) == -1) { +    MakeErrMsg(ErrMsg, "Cannot dup2"); +    close(InFD); +    return true; +  } +  close(InFD);      // Close the original FD +  return false; +} + +#ifdef HAVE_POSIX_SPAWN +static bool RedirectIO_PS(const std::string *Path, int FD, std::string *ErrMsg, +                          posix_spawn_file_actions_t *FileActions) { +  if (!Path) // Noop +    return false; +  const char *File; +  if (Path->empty()) +    // Redirect empty paths to /dev/null +    File = "/dev/null"; +  else +    File = Path->c_str(); + +  if (int Err = posix_spawn_file_actions_addopen( +          FileActions, FD, File, +          FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666)) +    return MakeErrMsg(ErrMsg, "Cannot posix_spawn_file_actions_addopen", Err); +  return false; +} +#endif + +static void TimeOutHandler(int Sig) { +} + +static void SetMemoryLimits(unsigned size) { +#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT +  struct rlimit r; +  __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576; + +  // Heap size +  getrlimit (RLIMIT_DATA, &r); +  r.rlim_cur = limit; +  setrlimit (RLIMIT_DATA, &r); +#ifdef RLIMIT_RSS +  // Resident set size. +  getrlimit (RLIMIT_RSS, &r); +  r.rlim_cur = limit; +  setrlimit (RLIMIT_RSS, &r); +#endif +#endif +} + +static std::vector<const char *> +toNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) { +  std::vector<const char *> Result; +  for (StringRef S : Strings) +    Result.push_back(Saver.save(S).data()); +  Result.push_back(nullptr); +  return Result; +} + +static bool Execute(ProcessInfo &PI, StringRef Program, +                    ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, +                    ArrayRef<Optional<StringRef>> Redirects, +                    unsigned MemoryLimit, std::string *ErrMsg, +                    BitVector *AffinityMask) { +  if (!llvm::sys::fs::exists(Program)) { +    if (ErrMsg) +      *ErrMsg = std::string("Executable \"") + Program.str() + +                std::string("\" doesn't exist!"); +    return false; +  } + +  assert(!AffinityMask && "Starting a process with an affinity mask is " +                          "currently not supported on Unix!"); + +  BumpPtrAllocator Allocator; +  StringSaver Saver(Allocator); +  std::vector<const char *> ArgVector, EnvVector; +  const char **Argv = nullptr; +  const char **Envp = nullptr; +  ArgVector = toNullTerminatedCStringArray(Args, Saver); +  Argv = ArgVector.data(); +  if (Env) { +    EnvVector = toNullTerminatedCStringArray(*Env, Saver); +    Envp = EnvVector.data(); +  } + +  // If this OS has posix_spawn and there is no memory limit being implied, use +  // posix_spawn.  It is more efficient than fork/exec. +#ifdef HAVE_POSIX_SPAWN +  if (MemoryLimit == 0) { +    posix_spawn_file_actions_t FileActionsStore; +    posix_spawn_file_actions_t *FileActions = nullptr; + +    // If we call posix_spawn_file_actions_addopen we have to make sure the +    // c strings we pass to it stay alive until the call to posix_spawn, +    // so we copy any StringRefs into this variable. +    std::string RedirectsStorage[3]; + +    if (!Redirects.empty()) { +      assert(Redirects.size() == 3); +      std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr}; +      for (int I = 0; I < 3; ++I) { +        if (Redirects[I]) { +          RedirectsStorage[I] = std::string(*Redirects[I]); +          RedirectsStr[I] = &RedirectsStorage[I]; +        } +      } + +      FileActions = &FileActionsStore; +      posix_spawn_file_actions_init(FileActions); + +      // Redirect stdin/stdout. +      if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) || +          RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions)) +        return false; +      if (!Redirects[1] || !Redirects[2] || *Redirects[1] != *Redirects[2]) { +        // Just redirect stderr +        if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions)) +          return false; +      } else { +        // If stdout and stderr should go to the same place, redirect stderr +        // to the FD already open for stdout. +        if (int Err = posix_spawn_file_actions_adddup2(FileActions, 1, 2)) +          return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err); +      } +    } + +    if (!Envp) +#if !USE_NSGETENVIRON +      Envp = const_cast<const char **>(environ); +#else +      // environ is missing in dylibs. +      Envp = const_cast<const char **>(*_NSGetEnviron()); +#endif + +    constexpr int maxRetries = 8; +    int retries = 0; +    pid_t PID; +    int Err; +    do { +      PID = 0; // Make Valgrind happy. +      Err = posix_spawn(&PID, Program.str().c_str(), FileActions, +                        /*attrp*/ nullptr, const_cast<char **>(Argv), +                        const_cast<char **>(Envp)); +    } while (Err == EINTR && ++retries < maxRetries); + +    if (FileActions) +      posix_spawn_file_actions_destroy(FileActions); + +    if (Err) +     return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); + +    PI.Pid = PID; +    PI.Process = PID; + +    return true; +  } +#endif + +  // Create a child process. +  int child = fork(); +  switch (child) { +    // An error occurred:  Return to the caller. +    case -1: +      MakeErrMsg(ErrMsg, "Couldn't fork"); +      return false; + +    // Child process: Execute the program. +    case 0: { +      // Redirect file descriptors... +      if (!Redirects.empty()) { +        // Redirect stdin +        if (RedirectIO(Redirects[0], 0, ErrMsg)) { return false; } +        // Redirect stdout +        if (RedirectIO(Redirects[1], 1, ErrMsg)) { return false; } +        if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) { +          // If stdout and stderr should go to the same place, redirect stderr +          // to the FD already open for stdout. +          if (-1 == dup2(1,2)) { +            MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); +            return false; +          } +        } else { +          // Just redirect stderr +          if (RedirectIO(Redirects[2], 2, ErrMsg)) { return false; } +        } +      } + +      // Set memory limits +      if (MemoryLimit!=0) { +        SetMemoryLimits(MemoryLimit); +      } + +      // Execute! +      std::string PathStr = std::string(Program); +      if (Envp != nullptr) +        execve(PathStr.c_str(), const_cast<char **>(Argv), +               const_cast<char **>(Envp)); +      else +        execv(PathStr.c_str(), const_cast<char **>(Argv)); +      // If the execve() failed, we should exit. Follow Unix protocol and +      // return 127 if the executable was not found, and 126 otherwise. +      // Use _exit rather than exit so that atexit functions and static +      // object destructors cloned from the parent process aren't +      // redundantly run, and so that any data buffered in stdio buffers +      // cloned from the parent aren't redundantly written out. +      _exit(errno == ENOENT ? 127 : 126); +    } + +    // Parent process: Break out of the switch to do our processing. +    default: +      break; +  } + +  PI.Pid = child; +  PI.Process = child; + +  return true; +} + +namespace llvm { +namespace sys { + +#ifndef _AIX +using ::wait4; +#else +static pid_t (wait4)(pid_t pid, int *status, int options, struct rusage *usage); +#endif + +} // namespace sys +} // namespace llvm + +#ifdef _AIX +#ifndef _ALL_SOURCE +extern "C" pid_t (wait4)(pid_t pid, int *status, int options, +                         struct rusage *usage); +#endif +pid_t (llvm::sys::wait4)(pid_t pid, int *status, int options, +                         struct rusage *usage) { +  assert(pid > 0 && "Only expecting to handle actual PID values!"); +  assert((options & ~WNOHANG) == 0 && "Expecting WNOHANG at most!"); +  assert(usage && "Expecting usage collection!"); + +  // AIX wait4 does not work well with WNOHANG. +  if (!(options & WNOHANG)) +    return ::wait4(pid, status, options, usage); + +  // For WNOHANG, we use waitid (which supports WNOWAIT) until the child process +  // has terminated. +  siginfo_t WaitIdInfo; +  WaitIdInfo.si_pid = 0; +  int WaitIdRetVal = +      waitid(P_PID, pid, &WaitIdInfo, WNOWAIT | WEXITED | options); + +  if (WaitIdRetVal == -1 || WaitIdInfo.si_pid == 0) +    return WaitIdRetVal; + +  assert(WaitIdInfo.si_pid == pid); + +  // The child has already terminated, so a blocking wait on it is okay in the +  // absence of indiscriminate `wait` calls from the current process (which +  // would cause the call here to fail with ECHILD). +  return ::wait4(pid, status, options & ~WNOHANG, usage); +} +#endif + +ProcessInfo llvm::sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, +                            bool WaitUntilTerminates, std::string *ErrMsg, +                            Optional<ProcessStatistics> *ProcStat) { +  struct sigaction Act, Old; +  assert(PI.Pid && "invalid pid to wait on, process not started?"); + +  int WaitPidOptions = 0; +  pid_t ChildPid = PI.Pid; +  if (WaitUntilTerminates) { +    SecondsToWait = 0; +  } else if (SecondsToWait) { +    // Install a timeout handler.  The handler itself does nothing, but the +    // simple fact of having a handler at all causes the wait below to return +    // with EINTR, unlike if we used SIG_IGN. +    memset(&Act, 0, sizeof(Act)); +    Act.sa_handler = TimeOutHandler; +    sigemptyset(&Act.sa_mask); +    sigaction(SIGALRM, &Act, &Old); +    // FIXME The alarm signal may be delivered to another thread. +    alarm(SecondsToWait); +  } else if (SecondsToWait == 0) +    WaitPidOptions = WNOHANG; + +  // Parent process: Wait for the child process to terminate. +  int status; +  ProcessInfo WaitResult; +  rusage Info; +  if (ProcStat) +    ProcStat->reset(); + +  do { +    WaitResult.Pid = sys::wait4(ChildPid, &status, WaitPidOptions, &Info); +  } while (WaitUntilTerminates && WaitResult.Pid == -1 && errno == EINTR); + +  if (WaitResult.Pid != PI.Pid) { +    if (WaitResult.Pid == 0) { +      // Non-blocking wait. +      return WaitResult; +    } else { +      if (SecondsToWait && errno == EINTR) { +        // Kill the child. +        kill(PI.Pid, SIGKILL); + +        // Turn off the alarm and restore the signal handler +        alarm(0); +        sigaction(SIGALRM, &Old, nullptr); + +        // Wait for child to die +        // FIXME This could grab some other child process out from another +        // waiting thread and then leave a zombie anyway. +        if (wait(&status) != ChildPid) +          MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); +        else +          MakeErrMsg(ErrMsg, "Child timed out", 0); + +        WaitResult.ReturnCode = -2; // Timeout detected +        return WaitResult; +      } else if (errno != EINTR) { +        MakeErrMsg(ErrMsg, "Error waiting for child process"); +        WaitResult.ReturnCode = -1; +        return WaitResult; +      } +    } +  } + +  // We exited normally without timeout, so turn off the timer. +  if (SecondsToWait && !WaitUntilTerminates) { +    alarm(0); +    sigaction(SIGALRM, &Old, nullptr); +  } + +  if (ProcStat) { +    std::chrono::microseconds UserT = toDuration(Info.ru_utime); +    std::chrono::microseconds KernelT = toDuration(Info.ru_stime); +    uint64_t PeakMemory = static_cast<uint64_t>(Info.ru_maxrss); +    *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory}; +  } + +  // Return the proper exit status. Detect error conditions +  // so we can return -1 for them and set ErrMsg informatively. +  int result = 0; +  if (WIFEXITED(status)) { +    result = WEXITSTATUS(status); +    WaitResult.ReturnCode = result; + +    if (result == 127) { +      if (ErrMsg) +        *ErrMsg = llvm::sys::StrError(ENOENT); +      WaitResult.ReturnCode = -1; +      return WaitResult; +    } +    if (result == 126) { +      if (ErrMsg) +        *ErrMsg = "Program could not be executed"; +      WaitResult.ReturnCode = -1; +      return WaitResult; +    } +  } else if (WIFSIGNALED(status)) { +    if (ErrMsg) { +      *ErrMsg = strsignal(WTERMSIG(status)); +#ifdef WCOREDUMP +      if (WCOREDUMP(status)) +        *ErrMsg += " (core dumped)"; +#endif +    } +    // Return a special value to indicate that the process received an unhandled +    // signal during execution as opposed to failing to execute. +    WaitResult.ReturnCode = -2; +  } +  return WaitResult; +} + +std::error_code llvm::sys::ChangeStdinToBinary() { +  // Do nothing, as Unix doesn't differentiate between text and binary. +  return std::error_code(); +} + +std::error_code llvm::sys::ChangeStdoutToBinary() { +  // Do nothing, as Unix doesn't differentiate between text and binary. +  return std::error_code(); +} + +std::error_code +llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, +                                 WindowsEncodingMethod Encoding /*unused*/) { +  std::error_code EC; +  llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::OF_Text); + +  if (EC) +    return EC; + +  OS << Contents; + +  if (OS.has_error()) +    return make_error_code(errc::io_error); + +  return EC; +} + +bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, +                                                  ArrayRef<StringRef> Args) { +  static long ArgMax = sysconf(_SC_ARG_MAX); +  // POSIX requires that _POSIX_ARG_MAX is 4096, which is the lowest possible +  // value for ARG_MAX on a POSIX compliant system. +  static long ArgMin = _POSIX_ARG_MAX; + +  // This the same baseline used by xargs. +  long EffectiveArgMax = 128 * 1024; + +  if (EffectiveArgMax > ArgMax) +    EffectiveArgMax = ArgMax; +  else if (EffectiveArgMax < ArgMin) +    EffectiveArgMax = ArgMin; + +  // System says no practical limit. +  if (ArgMax == -1) +    return true; + +  // Conservatively account for space required by environment variables. +  long HalfArgMax = EffectiveArgMax / 2; + +  size_t ArgLength = Program.size() + 1; +  for (StringRef Arg : Args) { +    // Ensure that we do not exceed the MAX_ARG_STRLEN constant on Linux, which +    // does not have a constant unlike what the man pages would have you +    // believe. Since this limit is pretty high, perform the check +    // unconditionally rather than trying to be aggressive and limiting it to +    // Linux only. +    if (Arg.size() >= (32 * 4096)) +      return false; + +    ArgLength += Arg.size() + 1; +    if (ArgLength > size_t(HalfArgMax)) { +      return false; +    } +  } + +  return true; +} diff --git a/contrib/libs/llvm12/lib/Support/Unix/README.txt b/contrib/libs/llvm12/lib/Support/Unix/README.txt new file mode 100644 index 00000000000..3d547c2990d --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/README.txt @@ -0,0 +1,16 @@ +llvm/lib/Support/Unix README +=========================== + +This directory provides implementations of the lib/System classes that +are common to two or more variants of UNIX. For example, the directory +structure underneath this directory could look like this: + +Unix           - only code that is truly generic to all UNIX platforms +  Posix        - code that is specific to Posix variants of UNIX +  SUS          - code that is specific to the Single Unix Specification +  SysV         - code that is specific to System V variants of UNIX + +As a rule, only those directories actually needing to be created should be +created. Also, further subdirectories could be created to reflect versions of +the various standards. For example, under SUS there could be v1, v2, and v3 +subdirectories to reflect the three major versions of SUS. diff --git a/contrib/libs/llvm12/lib/Support/Unix/Signals.inc b/contrib/libs/llvm12/lib/Support/Unix/Signals.inc new file mode 100644 index 00000000000..3d7b5d2fe5a --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/Signals.inc @@ -0,0 +1,659 @@ +//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// Unix signals occurring while your program is running. +// +//===----------------------------------------------------------------------===// +// +// This file is extremely careful to only do signal-safe things while in a +// signal handler. In particular, memory allocation and acquiring a mutex +// while in a signal handler should never occur. ManagedStatic isn't usable from +// a signal handler for 2 reasons: +// +//  1. Creating a new one allocates. +//  2. The signal handler could fire while llvm_shutdown is being processed, in +//     which case the ManagedStatic is in an unknown state because it could +//     already have been destroyed, or be in the process of being destroyed. +// +// Modifying the behavior of the signal handlers (such as registering new ones) +// can acquire a mutex, but all this guarantees is that the signal handler +// behavior is only modified by one thread at a time. A signal handler can still +// fire while this occurs! +// +// Adding work to a signal handler requires lock-freedom (and assume atomics are +// always lock-free) because the signal handler could fire while new work is +// being added. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Config/config.h" +#include "llvm/Demangle/Demangle.h" +#include "llvm/Support/ExitCodes.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <string> +#ifdef HAVE_BACKTRACE +# include BACKTRACE_HEADER         // For backtrace(). +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif +#if HAVE_MACH_MACH_H +#include <mach/mach.h> +#endif +#if HAVE_LINK_H +#include <link.h> +#endif +#ifdef HAVE__UNWIND_BACKTRACE +// FIXME: We should be able to use <unwind.h> for any target that has an +// _Unwind_Backtrace function, but on FreeBSD the configure test passes +// despite the function not existing, and on Android, <unwind.h> conflicts +// with <link.h>. +#ifdef __GLIBC__ +#include <unwind.h> +#else +#undef HAVE__UNWIND_BACKTRACE +#endif +#endif + +using namespace llvm; + +static RETSIGTYPE SignalHandler(int Sig);  // defined below. +static RETSIGTYPE InfoSignalHandler(int Sig);  // defined below. + +using SignalHandlerFunctionType = void (*)(); +/// The function to call if ctrl-c is pressed. +static std::atomic<SignalHandlerFunctionType> InterruptFunction = +    ATOMIC_VAR_INIT(nullptr); +static std::atomic<SignalHandlerFunctionType> InfoSignalFunction = +    ATOMIC_VAR_INIT(nullptr); +/// The function to call on SIGPIPE (one-time use only). +static std::atomic<SignalHandlerFunctionType> OneShotPipeSignalFunction = +    ATOMIC_VAR_INIT(nullptr); + +namespace { +/// Signal-safe removal of files. +/// Inserting and erasing from the list isn't signal-safe, but removal of files +/// themselves is signal-safe. Memory is freed when the head is freed, deletion +/// is therefore not signal-safe either. +class FileToRemoveList { +  std::atomic<char *> Filename = ATOMIC_VAR_INIT(nullptr); +  std::atomic<FileToRemoveList *> Next = ATOMIC_VAR_INIT(nullptr); + +  FileToRemoveList() = default; +  // Not signal-safe. +  FileToRemoveList(const std::string &str) : Filename(strdup(str.c_str())) {} + +public: +  // Not signal-safe. +  ~FileToRemoveList() { +    if (FileToRemoveList *N = Next.exchange(nullptr)) +      delete N; +    if (char *F = Filename.exchange(nullptr)) +      free(F); +  } + +  // Not signal-safe. +  static void insert(std::atomic<FileToRemoveList *> &Head, +                     const std::string &Filename) { +    // Insert the new file at the end of the list. +    FileToRemoveList *NewHead = new FileToRemoveList(Filename); +    std::atomic<FileToRemoveList *> *InsertionPoint = &Head; +    FileToRemoveList *OldHead = nullptr; +    while (!InsertionPoint->compare_exchange_strong(OldHead, NewHead)) { +      InsertionPoint = &OldHead->Next; +      OldHead = nullptr; +    } +  } + +  // Not signal-safe. +  static void erase(std::atomic<FileToRemoveList *> &Head, +                    const std::string &Filename) { +    // Use a lock to avoid concurrent erase: the comparison would access +    // free'd memory. +    static ManagedStatic<sys::SmartMutex<true>> Lock; +    sys::SmartScopedLock<true> Writer(*Lock); + +    for (FileToRemoveList *Current = Head.load(); Current; +         Current = Current->Next.load()) { +      if (char *OldFilename = Current->Filename.load()) { +        if (OldFilename != Filename) +          continue; +        // Leave an empty filename. +        OldFilename = Current->Filename.exchange(nullptr); +        // The filename might have become null between the time we +        // compared it and we exchanged it. +        if (OldFilename) +          free(OldFilename); +      } +    } +  } + +  // Signal-safe. +  static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) { +    // If cleanup were to occur while we're removing files we'd have a bad time. +    // Make sure we're OK by preventing cleanup from doing anything while we're +    // removing files. If cleanup races with us and we win we'll have a leak, +    // but we won't crash. +    FileToRemoveList *OldHead = Head.exchange(nullptr); + +    for (FileToRemoveList *currentFile = OldHead; currentFile; +         currentFile = currentFile->Next.load()) { +      // If erasing was occuring while we're trying to remove files we'd look +      // at free'd data. Take away the path and put it back when done. +      if (char *path = currentFile->Filename.exchange(nullptr)) { +        // Get the status so we can determine if it's a file or directory. If we +        // can't stat the file, ignore it. +        struct stat buf; +        if (stat(path, &buf) != 0) +          continue; + +        // If this is not a regular file, ignore it. We want to prevent removal +        // of special files like /dev/null, even if the compiler is being run +        // with the super-user permissions. +        if (!S_ISREG(buf.st_mode)) +          continue; + +        // Otherwise, remove the file. We ignore any errors here as there is +        // nothing else we can do. +        unlink(path); + +        // We're done removing the file, erasing can safely proceed. +        currentFile->Filename.exchange(path); +      } +    } + +    // We're done removing files, cleanup can safely proceed. +    Head.exchange(OldHead); +  } +}; +static std::atomic<FileToRemoveList *> FilesToRemove = ATOMIC_VAR_INIT(nullptr); + +/// Clean up the list in a signal-friendly manner. +/// Recall that signals can fire during llvm_shutdown. If this occurs we should +/// either clean something up or nothing at all, but we shouldn't crash! +struct FilesToRemoveCleanup { +  // Not signal-safe. +  ~FilesToRemoveCleanup() { +    FileToRemoveList *Head = FilesToRemove.exchange(nullptr); +    if (Head) +      delete Head; +  } +}; +} // namespace + +static StringRef Argv0; + +/// Signals that represent requested termination. There's no bug or failure, or +/// if there is, it's not our direct responsibility. For whatever reason, our +/// continued execution is no longer desirable. +static const int IntSigs[] = { +  SIGHUP, SIGINT, SIGTERM, SIGUSR2 +}; + +/// Signals that represent that we have a bug, and our prompt termination has +/// been ordered. +static const int KillSigs[] = { +  SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT +#ifdef SIGSYS +  , SIGSYS +#endif +#ifdef SIGXCPU +  , SIGXCPU +#endif +#ifdef SIGXFSZ +  , SIGXFSZ +#endif +#ifdef SIGEMT +  , SIGEMT +#endif +}; + +/// Signals that represent requests for status. +static const int InfoSigs[] = { +  SIGUSR1 +#ifdef SIGINFO +  , SIGINFO +#endif +}; + +static const size_t NumSigs = +    array_lengthof(IntSigs) + array_lengthof(KillSigs) + +    array_lengthof(InfoSigs) + 1 /* SIGPIPE */; + + +static std::atomic<unsigned> NumRegisteredSignals = ATOMIC_VAR_INIT(0); +static struct { +  struct sigaction SA; +  int SigNo; +} RegisteredSignalInfo[NumSigs]; + +#if defined(HAVE_SIGALTSTACK) +// Hold onto both the old and new alternate signal stack so that it's not +// reported as a leak. We don't make any attempt to remove our alt signal +// stack if we remove our signal handlers; that can't be done reliably if +// someone else is also trying to do the same thing. +static stack_t OldAltStack; +static void* NewAltStackPointer; + +static void CreateSigAltStack() { +  const size_t AltStackSize = MINSIGSTKSZ + 64 * 1024; + +  // If we're executing on the alternate stack, or we already have an alternate +  // signal stack that we're happy with, there's nothing for us to do. Don't +  // reduce the size, some other part of the process might need a larger stack +  // than we do. +  if (sigaltstack(nullptr, &OldAltStack) != 0 || +      OldAltStack.ss_flags & SS_ONSTACK || +      (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize)) +    return; + +  stack_t AltStack = {}; +  AltStack.ss_sp = static_cast<char *>(safe_malloc(AltStackSize)); +  NewAltStackPointer = AltStack.ss_sp; // Save to avoid reporting a leak. +  AltStack.ss_size = AltStackSize; +  if (sigaltstack(&AltStack, &OldAltStack) != 0) +    free(AltStack.ss_sp); +} +#else +static void CreateSigAltStack() {} +#endif + +static void RegisterHandlers() { // Not signal-safe. +  // The mutex prevents other threads from registering handlers while we're +  // doing it. We also have to protect the handlers and their count because +  // a signal handler could fire while we're registeting handlers. +  static ManagedStatic<sys::SmartMutex<true>> SignalHandlerRegistrationMutex; +  sys::SmartScopedLock<true> Guard(*SignalHandlerRegistrationMutex); + +  // If the handlers are already registered, we're done. +  if (NumRegisteredSignals.load() != 0) +    return; + +  // Create an alternate stack for signal handling. This is necessary for us to +  // be able to reliably handle signals due to stack overflow. +  CreateSigAltStack(); + +  enum class SignalKind { IsKill, IsInfo }; +  auto registerHandler = [&](int Signal, SignalKind Kind) { +    unsigned Index = NumRegisteredSignals.load(); +    assert(Index < array_lengthof(RegisteredSignalInfo) && +           "Out of space for signal handlers!"); + +    struct sigaction NewHandler; + +    switch (Kind) { +    case SignalKind::IsKill: +      NewHandler.sa_handler = SignalHandler; +      NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK; +      break; +    case SignalKind::IsInfo: +      NewHandler.sa_handler = InfoSignalHandler; +      NewHandler.sa_flags = SA_ONSTACK; +      break; +    } +    sigemptyset(&NewHandler.sa_mask); + +    // Install the new handler, save the old one in RegisteredSignalInfo. +    sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA); +    RegisteredSignalInfo[Index].SigNo = Signal; +    ++NumRegisteredSignals; +  }; + +  for (auto S : IntSigs) +    registerHandler(S, SignalKind::IsKill); +  for (auto S : KillSigs) +    registerHandler(S, SignalKind::IsKill); +  if (OneShotPipeSignalFunction) +    registerHandler(SIGPIPE, SignalKind::IsKill); +  for (auto S : InfoSigs) +    registerHandler(S, SignalKind::IsInfo); +} + +void sys::unregisterHandlers() { +  // Restore all of the signal handlers to how they were before we showed up. +  for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) { +    sigaction(RegisteredSignalInfo[i].SigNo, +              &RegisteredSignalInfo[i].SA, nullptr); +    --NumRegisteredSignals; +  } +} + +/// Process the FilesToRemove list. +static void RemoveFilesToRemove() { +  FileToRemoveList::removeAllFiles(FilesToRemove); +} + +void sys::CleanupOnSignal(uintptr_t Context) { +  int Sig = (int)Context; + +  if (llvm::is_contained(InfoSigs, Sig)) { +    InfoSignalHandler(Sig); +    return; +  } + +  RemoveFilesToRemove(); + +  if (llvm::is_contained(IntSigs, Sig) || Sig == SIGPIPE) +    return; + +  llvm::sys::RunSignalHandlers(); +} + +// The signal handler that runs. +static RETSIGTYPE SignalHandler(int Sig) { +  // Restore the signal behavior to default, so that the program actually +  // crashes when we return and the signal reissues.  This also ensures that if +  // we crash in our signal handler that the program will terminate immediately +  // instead of recursing in the signal handler. +  sys::unregisterHandlers(); + +  // Unmask all potentially blocked kill signals. +  sigset_t SigMask; +  sigfillset(&SigMask); +  sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); + +  { +    RemoveFilesToRemove(); + +    if (Sig == SIGPIPE) +      if (auto OldOneShotPipeFunction = +              OneShotPipeSignalFunction.exchange(nullptr)) +        return OldOneShotPipeFunction(); + +    bool IsIntSig = llvm::is_contained(IntSigs, Sig); +    if (IsIntSig) +      if (auto OldInterruptFunction = InterruptFunction.exchange(nullptr)) +        return OldInterruptFunction(); + +    if (Sig == SIGPIPE || IsIntSig) { +      raise(Sig); // Execute the default handler. +      return; +    } +  } + +  // Otherwise if it is a fault (like SEGV) run any handler. +  llvm::sys::RunSignalHandlers(); + +#ifdef __s390__ +  // On S/390, certain signals are delivered with PSW Address pointing to +  // *after* the faulting instruction.  Simply returning from the signal +  // handler would continue execution after that point, instead of +  // re-raising the signal.  Raise the signal manually in those cases. +  if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP) +    raise(Sig); +#endif +} + +static RETSIGTYPE InfoSignalHandler(int Sig) { +  SaveAndRestore<int> SaveErrnoDuringASignalHandler(errno); +  if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction) +    CurrentInfoFunction(); +} + +void llvm::sys::RunInterruptHandlers() { +  RemoveFilesToRemove(); +} + +void llvm::sys::SetInterruptFunction(void (*IF)()) { +  InterruptFunction.exchange(IF); +  RegisterHandlers(); +} + +void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { +  InfoSignalFunction.exchange(Handler); +  RegisterHandlers(); +} + +void llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) { +  OneShotPipeSignalFunction.exchange(Handler); +  RegisterHandlers(); +} + +void llvm::sys::DefaultOneShotPipeSignalHandler() { +  // Send a special return code that drivers can check for, from sysexits.h. +  exit(EX_IOERR); +} + +// The public API +bool llvm::sys::RemoveFileOnSignal(StringRef Filename, +                                   std::string* ErrMsg) { +  // Ensure that cleanup will occur as soon as one file is added. +  static ManagedStatic<FilesToRemoveCleanup> FilesToRemoveCleanup; +  *FilesToRemoveCleanup; +  FileToRemoveList::insert(FilesToRemove, Filename.str()); +  RegisterHandlers(); +  return false; +} + +// The public API +void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) { +  FileToRemoveList::erase(FilesToRemove, Filename.str()); +} + +/// Add a function to be called when a signal is delivered to the process. The +/// handler can have a cookie passed to it to identify what instance of the +/// handler it is. +void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, +                                 void *Cookie) { // Signal-safe. +  insertSignalHandler(FnPtr, Cookie); +  RegisterHandlers(); +} + +#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && HAVE_LINK_H &&    \ +    (defined(__linux__) || defined(__FreeBSD__) ||                             \ +     defined(__FreeBSD_kernel__) || defined(__NetBSD__)) +struct DlIteratePhdrData { +  void **StackTrace; +  int depth; +  bool first; +  const char **modules; +  intptr_t *offsets; +  const char *main_exec_name; +}; + +static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { +  DlIteratePhdrData *data = (DlIteratePhdrData*)arg; +  const char *name = data->first ? data->main_exec_name : info->dlpi_name; +  data->first = false; +  for (int i = 0; i < info->dlpi_phnum; i++) { +    const auto *phdr = &info->dlpi_phdr[i]; +    if (phdr->p_type != PT_LOAD) +      continue; +    intptr_t beg = info->dlpi_addr + phdr->p_vaddr; +    intptr_t end = beg + phdr->p_memsz; +    for (int j = 0; j < data->depth; j++) { +      if (data->modules[j]) +        continue; +      intptr_t addr = (intptr_t)data->StackTrace[j]; +      if (beg <= addr && addr < end) { +        data->modules[j] = name; +        data->offsets[j] = addr - info->dlpi_addr; +      } +    } +  } +  return 0; +} + +/// If this is an ELF platform, we can find all loaded modules and their virtual +/// addresses with dl_iterate_phdr. +static bool findModulesAndOffsets(void **StackTrace, int Depth, +                                  const char **Modules, intptr_t *Offsets, +                                  const char *MainExecutableName, +                                  StringSaver &StrPool) { +  DlIteratePhdrData data = {StackTrace, Depth,   true, +                            Modules,    Offsets, MainExecutableName}; +  dl_iterate_phdr(dl_iterate_phdr_cb, &data); +  return true; +} +#else +/// This platform does not have dl_iterate_phdr, so we do not yet know how to +/// find all loaded DSOs. +static bool findModulesAndOffsets(void **StackTrace, int Depth, +                                  const char **Modules, intptr_t *Offsets, +                                  const char *MainExecutableName, +                                  StringSaver &StrPool) { +  return false; +} +#endif // defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && ... + +#if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE) +static int unwindBacktrace(void **StackTrace, int MaxEntries) { +  if (MaxEntries < 0) +    return 0; + +  // Skip the first frame ('unwindBacktrace' itself). +  int Entries = -1; + +  auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code { +    // Apparently we need to detect reaching the end of the stack ourselves. +    void *IP = (void *)_Unwind_GetIP(Context); +    if (!IP) +      return _URC_END_OF_STACK; + +    assert(Entries < MaxEntries && "recursively called after END_OF_STACK?"); +    if (Entries >= 0) +      StackTrace[Entries] = IP; + +    if (++Entries == MaxEntries) +      return _URC_END_OF_STACK; +    return _URC_NO_REASON; +  }; + +  _Unwind_Backtrace( +      [](_Unwind_Context *Context, void *Handler) { +        return (*static_cast<decltype(HandleFrame) *>(Handler))(Context); +      }, +      static_cast<void *>(&HandleFrame)); +  return std::max(Entries, 0); +} +#endif + +// In the case of a program crash or fault, print out a stack trace so that the +// user has an indication of why and where we died. +// +// On glibc systems we have the 'backtrace' function, which works nicely, but +// doesn't demangle symbols. +void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) { +#if ENABLE_BACKTRACES +  static void *StackTrace[256]; +  int depth = 0; +#if defined(HAVE_BACKTRACE) +  // Use backtrace() to output a backtrace on Linux systems with glibc. +  if (!depth) +    depth = backtrace(StackTrace, static_cast<int>(array_lengthof(StackTrace))); +#endif +#if defined(HAVE__UNWIND_BACKTRACE) +  // Try _Unwind_Backtrace() if backtrace() failed. +  if (!depth) +    depth = unwindBacktrace(StackTrace, +                        static_cast<int>(array_lengthof(StackTrace))); +#endif +  if (!depth) +    return; +  // If "Depth" is not provided by the caller, use the return value of +  // backtrace() for printing a symbolized stack trace. +  if (!Depth) +    Depth = depth; +  if (printSymbolizedStackTrace(Argv0, StackTrace, Depth, OS)) +    return; +  OS << "Stack dump without symbol names (ensure you have llvm-symbolizer in " +        "your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point " +        "to it):\n"; +#if HAVE_DLFCN_H && HAVE_DLADDR +  int width = 0; +  for (int i = 0; i < depth; ++i) { +    Dl_info dlinfo; +    dladdr(StackTrace[i], &dlinfo); +    const char* name = strrchr(dlinfo.dli_fname, '/'); + +    int nwidth; +    if (!name) nwidth = strlen(dlinfo.dli_fname); +    else       nwidth = strlen(name) - 1; + +    if (nwidth > width) width = nwidth; +  } + +  for (int i = 0; i < depth; ++i) { +    Dl_info dlinfo; +    dladdr(StackTrace[i], &dlinfo); + +    OS << format("%-2d", i); + +    const char* name = strrchr(dlinfo.dli_fname, '/'); +    if (!name) OS << format(" %-*s", width, dlinfo.dli_fname); +    else       OS << format(" %-*s", width, name+1); + +    OS << format(" %#0*lx", (int)(sizeof(void*) * 2) + 2, +                 (unsigned long)StackTrace[i]); + +    if (dlinfo.dli_sname != nullptr) { +      OS << ' '; +      int res; +      char* d = itaniumDemangle(dlinfo.dli_sname, nullptr, nullptr, &res); +      if (!d) OS << dlinfo.dli_sname; +      else    OS << d; +      free(d); + +      OS << format(" + %tu", (static_cast<const char*>(StackTrace[i])- +                              static_cast<const char*>(dlinfo.dli_saddr))); +    } +    OS << '\n'; +  } +#elif defined(HAVE_BACKTRACE) +  backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO); +#endif +#endif +} + +static void PrintStackTraceSignalHandler(void *) { +  sys::PrintStackTrace(llvm::errs()); +} + +void llvm::sys::DisableSystemDialogsOnCrash() {} + +/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the +/// process, print a stack trace and then exit. +void llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0, +                                             bool DisableCrashReporting) { +  ::Argv0 = Argv0; + +  AddSignalHandler(PrintStackTraceSignalHandler, nullptr); + +#if defined(__APPLE__) && ENABLE_CRASH_OVERRIDES +  // Environment variable to disable any kind of crash dialog. +  if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) { +    mach_port_t self = mach_task_self(); + +    exception_mask_t mask = EXC_MASK_CRASH; + +    kern_return_t ret = task_set_exception_ports(self, +                             mask, +                             MACH_PORT_NULL, +                             EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, +                             THREAD_STATE_NONE); +    (void)ret; +  } +#endif +} diff --git a/contrib/libs/llvm12/lib/Support/Unix/ThreadLocal.inc b/contrib/libs/llvm12/lib/Support/Unix/ThreadLocal.inc new file mode 100644 index 00000000000..a402ae98042 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/ThreadLocal.inc @@ -0,0 +1,70 @@ +//=== llvm/Support/Unix/ThreadLocal.inc - Unix Thread Local Data -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//===          is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_GETSPECIFIC) + +#include <cassert> +#include <pthread.h> +#include <stdlib.h> + +namespace llvm { +using namespace sys; + +ThreadLocalImpl::ThreadLocalImpl() : data() { +  static_assert(sizeof(pthread_key_t) <= sizeof(data), "size too big"); +  pthread_key_t* key = reinterpret_cast<pthread_key_t*>(&data); +  int errorcode = pthread_key_create(key, nullptr); +  assert(errorcode == 0); +  (void) errorcode; +} + +ThreadLocalImpl::~ThreadLocalImpl() { +  pthread_key_t* key = reinterpret_cast<pthread_key_t*>(&data); +  int errorcode = pthread_key_delete(*key); +  assert(errorcode == 0); +  (void) errorcode; +} + +void ThreadLocalImpl::setInstance(const void* d) { +  pthread_key_t* key = reinterpret_cast<pthread_key_t*>(&data); +  int errorcode = pthread_setspecific(*key, d); +  assert(errorcode == 0); +  (void) errorcode; +} + +void *ThreadLocalImpl::getInstance() { +  pthread_key_t* key = reinterpret_cast<pthread_key_t*>(&data); +  return pthread_getspecific(*key); +} + +void ThreadLocalImpl::removeInstance() { +  setInstance(nullptr); +} + +} +#else +namespace llvm { +using namespace sys; +ThreadLocalImpl::ThreadLocalImpl() : data() { } +ThreadLocalImpl::~ThreadLocalImpl() { } +void ThreadLocalImpl::setInstance(const void* d) { data = const_cast<void*>(d);} +void *ThreadLocalImpl::getInstance() { return data; } +void ThreadLocalImpl::removeInstance() { setInstance(0); } +} +#endif diff --git a/contrib/libs/llvm12/lib/Support/Unix/Threading.inc b/contrib/libs/llvm12/lib/Support/Unix/Threading.inc new file mode 100644 index 00000000000..a745495d6e8 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/Threading.inc @@ -0,0 +1,311 @@ +//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the Unix specific implementation of Threading functions. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" + +#if defined(__APPLE__) +#include <mach/mach_init.h> +#include <mach/mach_port.h> +#endif + +#include <pthread.h> + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#include <pthread_np.h> // For pthread_getthreadid_np() / pthread_set_name_np() +#endif + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include <errno.h> +#include <sys/cpuset.h> +#include <sys/sysctl.h> +#include <sys/user.h> +#include <unistd.h> +#endif + +#if defined(__NetBSD__) +#error #include <lwp.h> // For _lwp_self() +#endif + +#if defined(__OpenBSD__) +#include <unistd.h> // For getthrid() +#endif + +#if defined(__linux__) +#include <sched.h>       // For sched_getaffinity +#include <sys/syscall.h> // For syscall codes +#include <unistd.h>      // For syscall() +#endif + +static void *threadFuncSync(void *Arg) { +  SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg); +  TI->UserFn(TI->UserData); +  return nullptr; +} + +static void *threadFuncAsync(void *Arg) { +  std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg)); +  (*Info)(); +  return nullptr; +} + +static void +llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg, +                            llvm::Optional<unsigned> StackSizeInBytes, +                            JoiningPolicy JP) { +  int errnum; + +  // Construct the attributes object. +  pthread_attr_t Attr; +  if ((errnum = ::pthread_attr_init(&Attr)) != 0) { +    ReportErrnumFatal("pthread_attr_init failed", errnum); +  } + +  auto AttrGuard = llvm::make_scope_exit([&] { +    if ((errnum = ::pthread_attr_destroy(&Attr)) != 0) { +      ReportErrnumFatal("pthread_attr_destroy failed", errnum); +    } +  }); + +  // Set the requested stack size, if given. +  if (StackSizeInBytes) { +    if ((errnum = ::pthread_attr_setstacksize(&Attr, *StackSizeInBytes)) != 0) { +      ReportErrnumFatal("pthread_attr_setstacksize failed", errnum); +    } +  } + +  // Construct and execute the thread. +  pthread_t Thread; +  if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0) +    ReportErrnumFatal("pthread_create failed", errnum); + +  if (JP == JoiningPolicy::Join) { +    // Wait for the thread +    if ((errnum = ::pthread_join(Thread, nullptr)) != 0) { +      ReportErrnumFatal("pthread_join failed", errnum); +    } +  } else if (JP == JoiningPolicy::Detach) { +    if ((errnum = ::pthread_detach(Thread)) != 0) { +      ReportErrnumFatal("pthread_detach failed", errnum); +    } +  } +} + +uint64_t llvm::get_threadid() { +#if defined(__APPLE__) +  // Calling "mach_thread_self()" bumps the reference count on the thread +  // port, so we need to deallocate it. mach_task_self() doesn't bump the ref +  // count. +  thread_port_t Self = mach_thread_self(); +  mach_port_deallocate(mach_task_self(), Self); +  return Self; +#elif defined(__FreeBSD__) +  return uint64_t(pthread_getthreadid_np()); +#elif defined(__NetBSD__) +  return uint64_t(_lwp_self()); +#elif defined(__OpenBSD__) +  return uint64_t(getthrid()); +#elif defined(__ANDROID__) +  return uint64_t(gettid()); +#elif defined(__linux__) +  return uint64_t(syscall(SYS_gettid)); +#else +  return uint64_t(pthread_self()); +#endif +} + + +static constexpr uint32_t get_max_thread_name_length_impl() { +#if defined(__NetBSD__) +  return PTHREAD_MAX_NAMELEN_NP; +#elif defined(__APPLE__) +  return 64; +#elif defined(__linux__) +#if HAVE_PTHREAD_SETNAME_NP +  return 16; +#else +  return 0; +#endif +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +  return 16; +#elif defined(__OpenBSD__) +  return 32; +#else +  return 0; +#endif +} + +uint32_t llvm::get_max_thread_name_length() { +  return get_max_thread_name_length_impl(); +} + +void llvm::set_thread_name(const Twine &Name) { +  // Make sure the input is null terminated. +  SmallString<64> Storage; +  StringRef NameStr = Name.toNullTerminatedStringRef(Storage); + +  // Truncate from the beginning, not the end, if the specified name is too +  // long.  For one, this ensures that the resulting string is still null +  // terminated, but additionally the end of a long thread name will usually +  // be more unique than the beginning, since a common pattern is for similar +  // threads to share a common prefix. +  // Note that the name length includes the null terminator. +  if (get_max_thread_name_length() > 0) +    NameStr = NameStr.take_back(get_max_thread_name_length() - 1); +  (void)NameStr; +#if defined(__linux__) +#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) +#if HAVE_PTHREAD_SETNAME_NP +  ::pthread_setname_np(::pthread_self(), NameStr.data()); +#endif +#endif +#elif defined(__FreeBSD__) || defined(__OpenBSD__) +  ::pthread_set_name_np(::pthread_self(), NameStr.data()); +#elif defined(__NetBSD__) +  ::pthread_setname_np(::pthread_self(), "%s", +    const_cast<char *>(NameStr.data())); +#elif defined(__APPLE__) +  ::pthread_setname_np(NameStr.data()); +#endif +} + +void llvm::get_thread_name(SmallVectorImpl<char> &Name) { +  Name.clear(); + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +  int pid = ::getpid(); +  uint64_t tid = get_threadid(); + +  struct kinfo_proc *kp = nullptr, *nkp; +  size_t len = 0; +  int error; +  int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, +    (int)pid }; + +  while (1) { +    error = sysctl(ctl, 4, kp, &len, nullptr, 0); +    if (kp == nullptr || (error != 0 && errno == ENOMEM)) { +      // Add extra space in case threads are added before next call. +      len += sizeof(*kp) + len / 10; +      nkp = (struct kinfo_proc *)::realloc(kp, len); +      if (nkp == nullptr) { +        free(kp); +        return; +      } +      kp = nkp; +      continue; +    } +    if (error != 0) +      len = 0; +    break; +  } + +  for (size_t i = 0; i < len / sizeof(*kp); i++) { +    if (kp[i].ki_tid == (lwpid_t)tid) { +      Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname)); +      break; +    } +  } +  free(kp); +  return; +#elif defined(__NetBSD__) +  constexpr uint32_t len = get_max_thread_name_length_impl(); +  char buf[len]; +  ::pthread_getname_np(::pthread_self(), buf, len); + +  Name.append(buf, buf + strlen(buf)); +#elif defined(__OpenBSD__) +  constexpr uint32_t len = get_max_thread_name_length_impl(); +  char buf[len]; +  ::pthread_get_name_np(::pthread_self(), buf, len); + +  Name.append(buf, buf + strlen(buf)); +#elif defined(__linux__) +#if HAVE_PTHREAD_GETNAME_NP +  constexpr uint32_t len = get_max_thread_name_length_impl(); +  char Buffer[len] = {'\0'};  // FIXME: working around MSan false positive. +  if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len)) +    Name.append(Buffer, Buffer + strlen(Buffer)); +#endif +#endif +} + +SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { +#if defined(__linux__) && defined(SCHED_IDLE) +  // Some *really* old glibcs are missing SCHED_IDLE. +  // http://man7.org/linux/man-pages/man3/pthread_setschedparam.3.html +  // http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html +  sched_param priority; +  // For each of the above policies, param->sched_priority must be 0. +  priority.sched_priority = 0; +  // SCHED_IDLE    for running very low priority background jobs. +  // SCHED_OTHER   the standard round-robin time-sharing policy; +  return !pthread_setschedparam( +             pthread_self(), +             Priority == ThreadPriority::Background ? SCHED_IDLE : SCHED_OTHER, +             &priority) +             ? SetThreadPriorityResult::SUCCESS +             : SetThreadPriorityResult::FAILURE; +#elif defined(__APPLE__) +  // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getpriority.2.html +  // When setting a thread into background state the scheduling priority is set +  // to lowest value, disk and network IO are throttled. Network IO will be +  // throttled for any sockets the thread opens after going into background +  // state. Any previously opened sockets are not affected. + +  // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getiopolicy_np.3.html +  // I/Os with THROTTLE policy are called THROTTLE I/Os. If a THROTTLE I/O +  // request occurs within a small time window (usually a fraction of a second) +  // of another NORMAL I/O request, the thread that issues the THROTTLE I/O is +  // forced to sleep for a certain interval. This slows down the thread that +  // issues the THROTTLE I/O so that NORMAL I/Os can utilize most of the disk +  // I/O bandwidth. +  return !setpriority(PRIO_DARWIN_THREAD, 0, +                      Priority == ThreadPriority::Background ? PRIO_DARWIN_BG +                                                             : 0) +             ? SetThreadPriorityResult::SUCCESS +             : SetThreadPriorityResult::FAILURE; +#endif +  return SetThreadPriorityResult::FAILURE; +} + +#include <thread> + +int computeHostNumHardwareThreads() { +#if defined(__FreeBSD__) +  cpuset_t mask; +  CPU_ZERO(&mask); +  if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask), +                         &mask) == 0) +    return CPU_COUNT(&mask); +#elif defined(__linux__) +  cpu_set_t Set; +  if (sched_getaffinity(0, sizeof(Set), &Set) == 0) +    return CPU_COUNT(&Set); +#endif +  // Guard against std::thread::hardware_concurrency() returning 0. +  if (unsigned Val = std::thread::hardware_concurrency()) +    return Val; +  return 1; +} + +void llvm::ThreadPoolStrategy::apply_thread_strategy( +    unsigned ThreadPoolNum) const {} + +llvm::BitVector llvm::get_thread_affinity_mask() { +  // FIXME: Implement +  llvm_unreachable("Not implemented!"); +} + +unsigned llvm::get_cpus() { return 1; } diff --git a/contrib/libs/llvm12/lib/Support/Unix/Unix.h b/contrib/libs/llvm12/lib/Support/Unix/Unix.h new file mode 100644 index 00000000000..60929139598 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/Unix.h @@ -0,0 +1,110 @@ +//===- llvm/Support/Unix/Unix.h - Common Unix Include File -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Unix implementations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_SUPPORT_UNIX_UNIX_H +#define LLVM_LIB_SUPPORT_UNIX_UNIX_H + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//===          is guaranteed to work on all UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <assert.h> +#include <cerrno> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <string> +#include <sys/types.h> +#include <sys/wait.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif +#include <time.h> + +#ifdef HAVE_DLFCN_H +# include <dlfcn.h> +#endif + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif + +/// This function builds an error message into \p ErrMsg using the \p prefix +/// string and the Unix error number given by \p errnum. If errnum is -1, the +/// default then the value of errno is used. +/// Make an error message +/// +/// If the error number can be converted to a string, it will be +/// separated from prefix by ": ". +static inline bool MakeErrMsg( +  std::string* ErrMsg, const std::string& prefix, int errnum = -1) { +  if (!ErrMsg) +    return true; +  if (errnum == -1) +    errnum = errno; +  *ErrMsg = prefix + ": " + llvm::sys::StrError(errnum); +  return true; +} + +// Include StrError(errnum) in a fatal error message. +LLVM_ATTRIBUTE_NORETURN static inline void ReportErrnumFatal(const char *Msg, +                                                             int errnum) { +  std::string ErrMsg; +  MakeErrMsg(&ErrMsg, Msg, errnum); +  llvm::report_fatal_error(ErrMsg); +} + +namespace llvm { +namespace sys { + +/// Convert a struct timeval to a duration. Note that timeval can be used both +/// as a time point and a duration. Be sure to check what the input represents. +inline std::chrono::microseconds toDuration(const struct timeval &TV) { +  return std::chrono::seconds(TV.tv_sec) + +         std::chrono::microseconds(TV.tv_usec); +} + +/// Convert a time point to struct timespec. +inline struct timespec toTimeSpec(TimePoint<> TP) { +  using namespace std::chrono; + +  struct timespec RetVal; +  RetVal.tv_sec = toTimeT(TP); +  RetVal.tv_nsec = (TP.time_since_epoch() % seconds(1)).count(); +  return RetVal; +} + +/// Convert a time point to struct timeval. +inline struct timeval toTimeVal(TimePoint<std::chrono::microseconds> TP) { +  using namespace std::chrono; + +  struct timeval RetVal; +  RetVal.tv_sec = toTimeT(TP); +  RetVal.tv_usec = (TP.time_since_epoch() % seconds(1)).count(); +  return RetVal; +} + +} // namespace sys +} // namespace llvm + +#endif diff --git a/contrib/libs/llvm12/lib/Support/Unix/Watchdog.inc b/contrib/libs/llvm12/lib/Support/Unix/Watchdog.inc new file mode 100644 index 00000000000..b363ef77956 --- /dev/null +++ b/contrib/libs/llvm12/lib/Support/Unix/Watchdog.inc @@ -0,0 +1,33 @@ +//===--- Unix/Watchdog.inc - Unix Watchdog Implementation -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Unix implementation of the Watchdog class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +namespace llvm { +  namespace sys { +    Watchdog::Watchdog(unsigned int seconds) { +#ifdef HAVE_UNISTD_H +      alarm(seconds); +#endif +    } + +    Watchdog::~Watchdog() { +#ifdef HAVE_UNISTD_H +      alarm(0); +#endif +    } +  } +} | 
