diff options
author | orivej <[email protected]> | 2022-02-10 16:45:01 +0300 |
---|---|---|
committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:45:01 +0300 |
commit | 2d37894b1b037cf24231090eda8589bbb44fb6fc (patch) | |
tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/llvm12/lib/Support/Unix | |
parent | 718c552901d703c502ccbefdfc3c9028d608b947 (diff) |
Restoring authorship annotation for <[email protected]>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Support/Unix')
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/COM.inc | 52 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/DynamicLibrary.inc | 268 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Host.inc | 168 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Memory.inc | 530 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Path.inc | 2616 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Process.inc | 908 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Program.inc | 1108 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Signals.inc | 1282 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/ThreadLocal.inc | 140 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Threading.inc | 606 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Unix.h | 220 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Unix/Watchdog.inc | 66 |
12 files changed, 3982 insertions, 3982 deletions
diff --git a/contrib/libs/llvm12/lib/Support/Unix/COM.inc b/contrib/libs/llvm12/lib/Support/Unix/COM.inc index b81e5c4c383..03a690ac376 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/COM.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/COM.inc @@ -1,26 +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() {} -} -} +//===- 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 index 0ad4408e81f..a2a379963de 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/DynamicLibrary.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/DynamicLibrary.inc @@ -1,134 +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; -} +//===- 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 index 8e4eb3bc390..dfcfdd0dee6 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/Host.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/Host.inc @@ -1,84 +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; -} +//===- 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 index bd933acbd46..be88e7db140 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/Memory.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/Memory.inc @@ -1,265 +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 +//===- 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 index 4b7b5e63ba2..996b8aebf61 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/Path.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/Path.inc @@ -1,798 +1,798 @@ -//===- 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> +//===- 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) -{ + +#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(); + /* 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)); @@ -803,303 +803,303 @@ std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, 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) { +#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 = + 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 (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 = +#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 = +#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; -} - +#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; @@ -1144,236 +1144,236 @@ std::error_code unlockFile(int FD) { 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 +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 index e7808d95b4d..7425d084da2 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/Process.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/Process.inc @@ -1,457 +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(); -} - +//===- 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 - +// 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) { +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 -} + // 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 index e5a013d3828..fb56fa4b0d1 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/Program.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/Program.inc @@ -1,559 +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, +//===- 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; - } - + 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; -} + 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/Signals.inc b/contrib/libs/llvm12/lib/Support/Unix/Signals.inc index 8452330e028..3d7b5d2fe5a 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/Signals.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/Signals.inc @@ -1,659 +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" +//===- 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); -} - +#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. + // 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(); - + + // 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 (auto OldInterruptFunction = InterruptFunction.exchange(nullptr)) + return OldInterruptFunction(); + if (Sig == SIGPIPE || IsIntSig) { raise(Sig); // Execute the default handler. - return; + 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; + } } - } - - // 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. + } + 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 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; + 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) +#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 -} +#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 index 0936c131ccd..a402ae98042 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/ThreadLocal.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/ThreadLocal.inc @@ -1,70 +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 +//=== 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 index a7c58699ba0..a745495d6e8 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/Threading.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/Threading.inc @@ -1,288 +1,288 @@ -//===- 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> +//===- 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() { +#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); @@ -290,22 +290,22 @@ int computeHostNumHardwareThreads() { &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; } + 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 index d4609f64ad5..60929139598 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/Unix.h +++ b/contrib/libs/llvm12/lib/Support/Unix/Unix.h @@ -1,110 +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 +//===- 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 index 4afce1429d4..b363ef77956 100644 --- a/contrib/libs/llvm12/lib/Support/Unix/Watchdog.inc +++ b/contrib/libs/llvm12/lib/Support/Unix/Watchdog.inc @@ -1,33 +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 - } - } -} +//===--- 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 + } + } +} |