You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.207
Former-commit-id: 3b152f462918d427ce18620a2cbe4f8b79650449
This commit is contained in:
parent
8e12397d70
commit
eb85e2fc17
27
external/llvm/lib/Support/Unix/COM.inc
vendored
27
external/llvm/lib/Support/Unix/COM.inc
vendored
@ -1,27 +0,0 @@
|
||||
//===- llvm/Support/Unix/COM.inc - Unix COM Implementation -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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() {}
|
||||
}
|
||||
}
|
135
external/llvm/lib/Support/Unix/DynamicLibrary.inc
vendored
135
external/llvm/lib/Support/Unix/DynamicLibrary.inc
vendored
@ -1,135 +0,0 @@
|
||||
//===- Unix/DynamicLibrary.cpp - Unix DL Implementation ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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;
|
||||
}
|
68
external/llvm/lib/Support/Unix/Host.inc
vendored
68
external/llvm/lib/Support/Unix/Host.inc
vendored
@ -1,68 +0,0 @@
|
||||
//===- llvm/Support/Unix/Host.inc -------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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();
|
||||
}
|
||||
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 Triple::normalize(TargetTripleString);
|
||||
}
|
239
external/llvm/lib/Support/Unix/Memory.inc
vendored
239
external/llvm/lib/Support/Unix/Memory.inc
vendored
@ -1,239 +0,0 @@
|
||||
//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines some functions for various memory management utilities.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Unix.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
|
||||
|
||||
#if defined(__mips__)
|
||||
# if defined(__OpenBSD__)
|
||||
# include <mips64/sysarch.h>
|
||||
# elif !defined(__FreeBSD__)
|
||||
# include <sys/cachectl.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
|
||||
#else
|
||||
extern "C" void __clear_cache(void *, void*);
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
int getPosixProtectionFlags(unsigned Flags) {
|
||||
switch (Flags) {
|
||||
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__)
|
||||
// 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.
|
||||
// Somehow, this problem is not present on Linux, but it does happen
|
||||
// on FreeBSD.
|
||||
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;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
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();
|
||||
|
||||
static const size_t PageSize = Process::getPageSize();
|
||||
const size_t NumPages = (NumBytes+PageSize-1)/PageSize;
|
||||
|
||||
int fd = -1;
|
||||
|
||||
int MMFlags = MAP_PRIVATE |
|
||||
#ifdef MAP_ANONYMOUS
|
||||
MAP_ANONYMOUS
|
||||
#else
|
||||
MAP_ANON
|
||||
#endif
|
||||
; // Ends statement above
|
||||
|
||||
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->size() : 0;
|
||||
if (Start && Start % PageSize)
|
||||
Start += PageSize - Start % PageSize;
|
||||
|
||||
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
|
||||
return allocateMappedMemory(NumBytes, nullptr, PFlags, EC);
|
||||
|
||||
EC = std::error_code(errno, std::generic_category());
|
||||
return MemoryBlock();
|
||||
}
|
||||
|
||||
MemoryBlock Result;
|
||||
Result.Address = Addr;
|
||||
Result.Size = NumPages*PageSize;
|
||||
|
||||
// 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.Size == 0)
|
||||
return std::error_code();
|
||||
|
||||
if (0 != ::munmap(M.Address, M.Size))
|
||||
return std::error_code(errno, std::generic_category());
|
||||
|
||||
M.Address = nullptr;
|
||||
M.Size = 0;
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code
|
||||
Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) {
|
||||
static const size_t PageSize = Process::getPageSize();
|
||||
if (M.Address == nullptr || M.Size == 0)
|
||||
return std::error_code();
|
||||
|
||||
if (!Flags)
|
||||
return std::error_code(EINVAL, std::generic_category());
|
||||
|
||||
int Protect = getPosixProtectionFlags(Flags);
|
||||
uintptr_t Start = alignAddr((uint8_t *)M.Address - PageSize + 1, PageSize);
|
||||
uintptr_t End = alignAddr((uint8_t *)M.Address + M.Size, 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.Size);
|
||||
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.Size);
|
||||
|
||||
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
|
||||
|
||||
#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
|
43
external/llvm/lib/Support/Unix/Mutex.inc
vendored
43
external/llvm/lib/Support/Unix/Mutex.inc
vendored
@ -1,43 +0,0 @@
|
||||
//===- llvm/Support/Unix/Mutex.inc - Unix Mutex Implementation ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Unix specific (non-pthread) Mutex class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//=== WARNING: Implementation here must contain only generic UNIX code that
|
||||
//=== is guaranteed to work on *all* UNIX variants.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm
|
||||
{
|
||||
using namespace sys;
|
||||
|
||||
MutexImpl::MutexImpl( bool recursive)
|
||||
{
|
||||
}
|
||||
|
||||
MutexImpl::~MutexImpl()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
MutexImpl::release()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MutexImpl::tryacquire( void )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
983
external/llvm/lib/Support/Unix/Path.inc
vendored
983
external/llvm/lib/Support/Unix/Path.inc
vendored
File diff suppressed because it is too large
Load Diff
450
external/llvm/lib/Support/Unix/Process.inc
vendored
450
external/llvm/lib/Support/Unix/Process.inc
vendored
@ -1,450 +0,0 @@
|
||||
//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/MutexGuard.h"
|
||||
#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
|
||||
// DragonFlyBSD, and OpenBSD have deprecated <malloc.h> for
|
||||
// <stdlib.h> instead. Unix.h includes this for us already.
|
||||
#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \
|
||||
!defined(__OpenBSD__)
|
||||
#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
|
||||
}
|
||||
|
||||
// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
|
||||
// offset in mmap(3) should be aligned to the AllocationGranularity.
|
||||
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
|
||||
#warning Cannot get the page size on this machine
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
std::error_code
|
||||
Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut,
|
||||
ArrayRef<const char *> ArgsIn,
|
||||
SpecificBumpPtrAllocator<char> &) {
|
||||
ArgsOut.append(ArgsIn.begin(), ArgsIn.end());
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
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) {
|
||||
if ((NullFD = RetryAfterSignal(-1, open, "/dev/null", O_RDWR)) < 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(int FileID) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
unsigned Columns = 0;
|
||||
|
||||
#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
|
||||
// Try to determine the width of the terminal.
|
||||
struct winsize ws;
|
||||
if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
|
||||
Columns = ws.ws_col;
|
||||
#endif
|
||||
|
||||
return Columns;
|
||||
}
|
||||
|
||||
unsigned Process::StandardOutColumns() {
|
||||
if (!StandardOutIsDisplayed())
|
||||
return 0;
|
||||
|
||||
return getColumns(1);
|
||||
}
|
||||
|
||||
unsigned Process::StandardErrColumns() {
|
||||
if (!StandardErrIsDisplayed())
|
||||
return 0;
|
||||
|
||||
return getColumns(2);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TERMINFO
|
||||
// We manually declare these extern functions because finding the correct
|
||||
// headers from various terminfo, curses, or other sources is harder than
|
||||
// writing their specs down.
|
||||
extern "C" int setupterm(char *term, int filedes, int *errret);
|
||||
extern "C" struct term *set_curterm(struct term *termp);
|
||||
extern "C" int del_curterm(struct term *termp);
|
||||
extern "C" int tigetnum(char *capname);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TERMINFO
|
||||
static ManagedStatic<sys::Mutex> TermColorMutex;
|
||||
#endif
|
||||
|
||||
static bool terminalHasColors(int fd) {
|
||||
#ifdef HAVE_TERMINFO
|
||||
// First, acquire a global lock because these C routines are thread hostile.
|
||||
MutexGuard 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;
|
||||
#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
|
||||
}
|
465
external/llvm/lib/Support/Unix/Program.inc
vendored
465
external/llvm/lib/Support/Unix/Program.inc
vendored
@ -1,465 +0,0 @@
|
||||
//===- llvm/Support/Unix/Program.cpp -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 "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/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
|
||||
|
||||
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 = *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 dup2", 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 bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
|
||||
const char **Envp, ArrayRef<Optional<StringRef>> Redirects,
|
||||
unsigned MemoryLimit, std::string *ErrMsg) {
|
||||
if (!llvm::sys::fs::exists(Program)) {
|
||||
if (ErrMsg)
|
||||
*ErrMsg = std::string("Executable \"") + Program.str() +
|
||||
std::string("\" doesn't exist!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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] = *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
|
||||
|
||||
// Explicitly initialized to prevent what appears to be a valgrind false
|
||||
// positive.
|
||||
pid_t PID = 0;
|
||||
int Err = posix_spawn(&PID, Program.str().c_str(), FileActions,
|
||||
/*attrp*/nullptr, const_cast<char **>(Args),
|
||||
const_cast<char **>(Envp));
|
||||
|
||||
if (FileActions)
|
||||
posix_spawn_file_actions_destroy(FileActions);
|
||||
|
||||
if (Err)
|
||||
return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
|
||||
|
||||
PI.Pid = 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 = Program;
|
||||
if (Envp != nullptr)
|
||||
execve(PathStr.c_str(),
|
||||
const_cast<char **>(Args),
|
||||
const_cast<char **>(Envp));
|
||||
else
|
||||
execv(PathStr.c_str(),
|
||||
const_cast<char **>(Args));
|
||||
// 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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
|
||||
bool WaitUntilTerminates, std::string *ErrMsg) {
|
||||
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);
|
||||
alarm(SecondsToWait);
|
||||
} else if (SecondsToWait == 0)
|
||||
WaitPidOptions = WNOHANG;
|
||||
|
||||
// Parent process: Wait for the child process to terminate.
|
||||
int status;
|
||||
ProcessInfo WaitResult;
|
||||
|
||||
do {
|
||||
WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions);
|
||||
} 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
|
||||
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);
|
||||
}
|
||||
|
||||
// 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 sys::ChangeStdinToBinary(){
|
||||
// Do nothing, as Unix doesn't differentiate between text and binary.
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code 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::F_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<const char *> Args) {
|
||||
static long ArgMax = sysconf(_SC_ARG_MAX);
|
||||
|
||||
// System says no practical limit.
|
||||
if (ArgMax == -1)
|
||||
return true;
|
||||
|
||||
// Conservatively account for space required by environment variables.
|
||||
long HalfArgMax = ArgMax / 2;
|
||||
|
||||
size_t ArgLength = Program.size() + 1;
|
||||
for (const char* Arg : Args) {
|
||||
size_t length = strlen(Arg);
|
||||
|
||||
// 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 (length >= (32 * 4096))
|
||||
return false;
|
||||
|
||||
ArgLength += length + 1;
|
||||
if (ArgLength > size_t(HalfArgMax)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
16
external/llvm/lib/Support/Unix/README.txt
vendored
16
external/llvm/lib/Support/Unix/README.txt
vendored
@ -1,16 +0,0 @@
|
||||
llvm/lib/Support/Unix README
|
||||
===========================
|
||||
|
||||
This directory provides implementations of the lib/System classes that
|
||||
are common to two or more variants of UNIX. For example, the directory
|
||||
structure underneath this directory could look like this:
|
||||
|
||||
Unix - only code that is truly generic to all UNIX platforms
|
||||
Posix - code that is specific to Posix variants of UNIX
|
||||
SUS - code that is specific to the Single Unix Specification
|
||||
SysV - code that is specific to System V variants of UNIX
|
||||
|
||||
As a rule, only those directories actually needing to be created should be
|
||||
created. Also, further subdirectories could be created to reflect versions of
|
||||
the various standards. For example, under SUS there could be v1, v2, and v3
|
||||
subdirectories to reflect the three major versions of SUS.
|
51
external/llvm/lib/Support/Unix/RWMutex.inc
vendored
51
external/llvm/lib/Support/Unix/RWMutex.inc
vendored
@ -1,51 +0,0 @@
|
||||
//= llvm/Support/Unix/RWMutex.inc - Unix Reader/Writer Mutual Exclusion Lock =//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Unix specific (non-pthread) RWMutex class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//=== WARNING: Implementation here must contain only generic UNIX code that
|
||||
//=== is guaranteed to work on *all* UNIX variants.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/Mutex.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
using namespace sys;
|
||||
|
||||
// This naive implementation treats readers the same as writers. This
|
||||
// will therefore deadlock if a thread tries to acquire a read lock
|
||||
// multiple times.
|
||||
|
||||
RWMutexImpl::RWMutexImpl() : data_(new MutexImpl(false)) { }
|
||||
|
||||
RWMutexImpl::~RWMutexImpl() {
|
||||
delete static_cast<MutexImpl *>(data_);
|
||||
}
|
||||
|
||||
bool RWMutexImpl::reader_acquire() {
|
||||
return static_cast<MutexImpl *>(data_)->acquire();
|
||||
}
|
||||
|
||||
bool RWMutexImpl::reader_release() {
|
||||
return static_cast<MutexImpl *>(data_)->release();
|
||||
}
|
||||
|
||||
bool RWMutexImpl::writer_acquire() {
|
||||
return static_cast<MutexImpl *>(data_)->acquire();
|
||||
}
|
||||
|
||||
bool RWMutexImpl::writer_release() {
|
||||
return static_cast<MutexImpl *>(data_)->release();
|
||||
}
|
||||
|
||||
}
|
489
external/llvm/lib/Support/Unix/Signals.inc
vendored
489
external/llvm/lib/Support/Unix/Signals.inc
vendored
@ -1,489 +0,0 @@
|
||||
//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines some helpful functions for dealing with the possibility of
|
||||
// Unix signals occurring while your program is running.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Unix.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Demangle/Demangle.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/UniqueLock.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 ManagedStatic<sys::SmartMutex<true> > SignalsMutex;
|
||||
|
||||
/// InterruptFunction - The function to call if ctrl-c is pressed.
|
||||
static void (*InterruptFunction)() = nullptr;
|
||||
|
||||
static ManagedStatic<std::vector<std::string>> FilesToRemove;
|
||||
|
||||
static StringRef Argv0;
|
||||
|
||||
// IntSigs - 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, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
|
||||
};
|
||||
|
||||
// KillSigs - 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
|
||||
};
|
||||
|
||||
static unsigned NumRegisteredSignals = 0;
|
||||
static struct {
|
||||
struct sigaction SA;
|
||||
int SigNo;
|
||||
} RegisteredSignalInfo[array_lengthof(IntSigs) + array_lengthof(KillSigs)];
|
||||
|
||||
|
||||
static void RegisterHandler(int Signal) {
|
||||
assert(NumRegisteredSignals < array_lengthof(RegisteredSignalInfo) &&
|
||||
"Out of space for signal handlers!");
|
||||
|
||||
struct sigaction NewHandler;
|
||||
|
||||
NewHandler.sa_handler = SignalHandler;
|
||||
NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;
|
||||
sigemptyset(&NewHandler.sa_mask);
|
||||
|
||||
// Install the new handler, save the old one in RegisteredSignalInfo.
|
||||
sigaction(Signal, &NewHandler,
|
||||
&RegisteredSignalInfo[NumRegisteredSignals].SA);
|
||||
RegisteredSignalInfo[NumRegisteredSignals].SigNo = Signal;
|
||||
++NumRegisteredSignals;
|
||||
}
|
||||
|
||||
#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 = reinterpret_cast<char *>(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() {
|
||||
sys::SmartScopedLock<true> Guard(*SignalsMutex);
|
||||
|
||||
// If the handlers are already registered, we're done.
|
||||
if (NumRegisteredSignals != 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();
|
||||
|
||||
for (auto S : IntSigs) RegisterHandler(S);
|
||||
for (auto S : KillSigs) RegisterHandler(S);
|
||||
}
|
||||
|
||||
static void UnregisterHandlers() {
|
||||
// Restore all of the signal handlers to how they were before we showed up.
|
||||
for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i)
|
||||
sigaction(RegisteredSignalInfo[i].SigNo,
|
||||
&RegisteredSignalInfo[i].SA, nullptr);
|
||||
NumRegisteredSignals = 0;
|
||||
}
|
||||
|
||||
|
||||
/// RemoveFilesToRemove - Process the FilesToRemove list. This function
|
||||
/// should be called with the SignalsMutex lock held.
|
||||
/// NB: This must be an async signal safe function. It cannot allocate or free
|
||||
/// memory, even in debug builds.
|
||||
static void RemoveFilesToRemove() {
|
||||
// Avoid constructing ManagedStatic in the signal handler.
|
||||
// If FilesToRemove is not constructed, there are no files to remove.
|
||||
if (!FilesToRemove.isConstructed())
|
||||
return;
|
||||
|
||||
// We avoid iterators in case of debug iterators that allocate or release
|
||||
// memory.
|
||||
std::vector<std::string>& FilesToRemoveRef = *FilesToRemove;
|
||||
for (unsigned i = 0, e = FilesToRemoveRef.size(); i != e; ++i) {
|
||||
const char *path = FilesToRemoveRef[i].c_str();
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// SignalHandler - 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.
|
||||
UnregisterHandlers();
|
||||
|
||||
// Unmask all potentially blocked kill signals.
|
||||
sigset_t SigMask;
|
||||
sigfillset(&SigMask);
|
||||
sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
|
||||
|
||||
{
|
||||
unique_lock<sys::SmartMutex<true>> Guard(*SignalsMutex);
|
||||
RemoveFilesToRemove();
|
||||
|
||||
if (std::find(std::begin(IntSigs), std::end(IntSigs), Sig)
|
||||
!= std::end(IntSigs)) {
|
||||
if (InterruptFunction) {
|
||||
void (*IF)() = InterruptFunction;
|
||||
Guard.unlock();
|
||||
InterruptFunction = nullptr;
|
||||
IF(); // run the interrupt function.
|
||||
return;
|
||||
}
|
||||
|
||||
Guard.unlock();
|
||||
raise(Sig); // Execute the default handler.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise if it is a fault (like SEGV) run any handler.
|
||||
llvm::sys::RunSignalHandlers();
|
||||
|
||||
#ifdef __s390__
|
||||
// On S/390, certain signals are delivered with PSW Address pointing to
|
||||
// *after* the faulting instruction. Simply returning from the signal
|
||||
// handler would continue execution after that point, instead of
|
||||
// re-raising the signal. Raise the signal manually in those cases.
|
||||
if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)
|
||||
raise(Sig);
|
||||
#endif
|
||||
}
|
||||
|
||||
void llvm::sys::RunInterruptHandlers() {
|
||||
sys::SmartScopedLock<true> Guard(*SignalsMutex);
|
||||
RemoveFilesToRemove();
|
||||
}
|
||||
|
||||
void llvm::sys::SetInterruptFunction(void (*IF)()) {
|
||||
{
|
||||
sys::SmartScopedLock<true> Guard(*SignalsMutex);
|
||||
InterruptFunction = IF;
|
||||
}
|
||||
RegisterHandlers();
|
||||
}
|
||||
|
||||
// RemoveFileOnSignal - The public API
|
||||
bool llvm::sys::RemoveFileOnSignal(StringRef Filename,
|
||||
std::string* ErrMsg) {
|
||||
{
|
||||
sys::SmartScopedLock<true> Guard(*SignalsMutex);
|
||||
FilesToRemove->push_back(Filename);
|
||||
}
|
||||
|
||||
RegisterHandlers();
|
||||
return false;
|
||||
}
|
||||
|
||||
// DontRemoveFileOnSignal - The public API
|
||||
void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) {
|
||||
sys::SmartScopedLock<true> Guard(*SignalsMutex);
|
||||
std::vector<std::string>::reverse_iterator RI =
|
||||
find(reverse(*FilesToRemove), Filename);
|
||||
std::vector<std::string>::iterator I = FilesToRemove->end();
|
||||
if (RI != FilesToRemove->rend())
|
||||
I = FilesToRemove->erase(RI.base()-1);
|
||||
}
|
||||
|
||||
/// AddSignalHandler - 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(void (*FnPtr)(void *), void *Cookie) {
|
||||
CallBacksToRun->push_back(std::make_pair(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
|
||||
|
||||
// PrintStackTrace - 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) {
|
||||
#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 (printSymbolizedStackTrace(Argv0, StackTrace, depth, OS))
|
||||
return;
|
||||
#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);
|
||||
|
||||
// FIXME: When we move to C++11, use %t length modifier. It's not in
|
||||
// C++03 and causes gcc to issue warnings. Losing the upper 32 bits of
|
||||
// the stack offset for a stack dump isn't likely to cause any problems.
|
||||
OS << format(" + %u",(unsigned)((char*)StackTrace[i]-
|
||||
(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() {}
|
||||
|
||||
/// PrintStackTraceOnErrorSignal - 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
|
||||
}
|
69
external/llvm/lib/Support/Unix/ThreadLocal.inc
vendored
69
external/llvm/lib/Support/Unix/ThreadLocal.inc
vendored
@ -1,69 +0,0 @@
|
||||
//=== llvm/Support/Unix/ThreadLocal.inc - Unix Thread Local Data -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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
|
215
external/llvm/lib/Support/Unix/Threading.inc
vendored
215
external/llvm/lib/Support/Unix/Threading.inc
vendored
@ -1,215 +0,0 @@
|
||||
//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides the Unix specific implementation of Threading functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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__)
|
||||
#include <pthread_np.h> // For pthread_getthreadid_np()
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <errno.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <lwp.h> // For _lwp_self()
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/syscall.h> // For syscall codes
|
||||
#include <unistd.h> // For syscall()
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
struct ThreadInfo {
|
||||
void(*UserFn)(void *);
|
||||
void *UserData;
|
||||
};
|
||||
}
|
||||
|
||||
static void *ExecuteOnThread_Dispatch(void *Arg) {
|
||||
ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg);
|
||||
TI->UserFn(TI->UserData);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData,
|
||||
unsigned RequestedStackSize) {
|
||||
ThreadInfo Info = { Fn, UserData };
|
||||
pthread_attr_t Attr;
|
||||
pthread_t Thread;
|
||||
|
||||
// Construct the attributes object.
|
||||
if (::pthread_attr_init(&Attr) != 0)
|
||||
return;
|
||||
|
||||
// Set the requested stack size, if given.
|
||||
if (RequestedStackSize != 0) {
|
||||
if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Construct and execute the thread.
|
||||
if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0)
|
||||
goto error;
|
||||
|
||||
// Wait for the thread and clean up.
|
||||
::pthread_join(Thread, nullptr);
|
||||
|
||||
error:
|
||||
::pthread_attr_destroy(&Attr);
|
||||
}
|
||||
|
||||
|
||||
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(__ANDROID__)
|
||||
return uint64_t(gettid());
|
||||
#elif defined(__linux__)
|
||||
return uint64_t(syscall(SYS_gettid));
|
||||
#elif defined(LLVM_ON_WIN32)
|
||||
return uint64_t(::GetCurrentThreadId());
|
||||
#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;
|
||||
#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.
|
||||
if (get_max_thread_name_length() > 0)
|
||||
NameStr = NameStr.take_back(get_max_thread_name_length());
|
||||
(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__)
|
||||
::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(__linux__)
|
||||
#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
|
||||
#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
|
||||
#endif
|
||||
}
|
106
external/llvm/lib/Support/Unix/Unix.h
vendored
106
external/llvm/lib/Support/Unix/Unix.h
vendored
@ -1,106 +0,0 @@
|
||||
//===- llvm/Support/Unix/Unix.h - Common Unix Include File -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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" // Get autoconf configuration settings
|
||||
#include "llvm/Support/Chrono.h"
|
||||
#include "llvm/Support/Errno.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_PARAM_H
|
||||
#include <sys/param.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.
|
||||
/// @brief 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;
|
||||
}
|
||||
|
||||
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
|
32
external/llvm/lib/Support/Unix/Watchdog.inc
vendored
32
external/llvm/lib/Support/Unix/Watchdog.inc
vendored
@ -1,32 +0,0 @@
|
||||
//===--- Unix/Watchdog.inc - Unix Watchdog Implementation -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides the generic Unix implementation of the Watchdog class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user