diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-30 16:33:32 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-30 16:33:32 +0000 | 
| commit | 51315c45ff5643a27f9c84b816db54ee870ba29b (patch) | |
| tree | 1d87443fa0e53d3e6b315ce25787e64be0906bf7 /contrib/llvm/lib/Support/Unix | |
| parent | 6dfd050075216be8538ae375a22d30db72916f7e (diff) | |
| parent | eb11fae6d08f479c0799db45860a98af528fa6e7 (diff) | |
Notes
Diffstat (limited to 'contrib/llvm/lib/Support/Unix')
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/Host.inc | 2 | ||||
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/Memory.inc | 12 | ||||
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/Path.inc | 175 | ||||
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/Process.inc | 31 | ||||
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/Program.inc | 68 | ||||
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/Signals.inc | 302 | ||||
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/ThreadLocal.inc | 2 | ||||
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/Threading.inc | 17 | ||||
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/Unix.h | 2 | ||||
| -rw-r--r-- | contrib/llvm/lib/Support/Unix/Watchdog.inc | 2 | 
10 files changed, 397 insertions, 216 deletions
| diff --git a/contrib/llvm/lib/Support/Unix/Host.inc b/contrib/llvm/lib/Support/Unix/Host.inc index 5580e63893c6..b65f84bf4444 100644 --- a/contrib/llvm/lib/Support/Unix/Host.inc +++ b/contrib/llvm/lib/Support/Unix/Host.inc @@ -64,5 +64,5 @@ std::string sys::getDefaultTargetTriple() {      TargetTripleString = EnvTriple;  #endif -  return Triple::normalize(TargetTripleString); +  return TargetTripleString;  } diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc index 848548d18177..adbfff2f59a5 100644 --- a/contrib/llvm/lib/Support/Unix/Memory.inc +++ b/contrib/llvm/lib/Support/Unix/Memory.inc @@ -12,6 +12,7 @@  //===----------------------------------------------------------------------===//  #include "Unix.h" +#include "llvm/Config/config.h"  #include "llvm/Support/DataTypes.h"  #include "llvm/Support/ErrorHandling.h"  #include "llvm/Support/Process.h" @@ -24,6 +25,10 @@  #include <mach/mach.h>  #endif +#ifdef __Fuchsia__ +#include <zircon/syscalls.h> +#endif +  #if defined(__mips__)  #  if defined(__OpenBSD__)  #    include <mips64/sysarch.h> @@ -32,7 +37,7 @@  #  endif  #endif -#ifdef __APPLE__ +#if defined(__APPLE__)  extern "C" void sys_icache_invalidate(const void *Addr, size_t len);  #else  extern "C" void __clear_cache(void *, void*); @@ -205,6 +210,11 @@ void Memory::InvalidateInstructionCache(const void *Addr,    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__) || \ diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc index 2ecb97316c87..7ad57d892ff1 100644 --- a/contrib/llvm/lib/Support/Unix/Path.inc +++ b/contrib/llvm/lib/Support/Unix/Path.inc @@ -31,23 +31,8 @@  #ifdef HAVE_SYS_MMAN_H  #include <sys/mman.h>  #endif -#if HAVE_DIRENT_H -# include <dirent.h> -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -#  include <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -#  include <sys/dir.h> -# endif -# if HAVE_NDIR_H -#  include <ndir.h> -# endif -#endif +#include <dirent.h>  #include <pwd.h>  #ifdef __APPLE__ @@ -108,6 +93,9 @@ 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) @@ -380,6 +368,12 @@ static bool is_local_impl(struct STATVFS &Vfs) {  #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(__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); @@ -530,7 +524,7 @@ static void expandTildeExpr(SmallVectorImpl<char> &Path) {  }  static std::error_code fillStatus(int StatRet, const struct stat &Status, -                             file_status &Result) { +                                  file_status &Result) {    if (StatRet != 0) {      std::error_code ec(errno, std::generic_category());      if (ec == errc::no_such_file_or_directory) @@ -643,7 +637,8 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset,  mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,                                         uint64_t offset, std::error_code &ec) -    : Size(length), Mapping() { +    : Size(length), Mapping(), Mode(mode) { +  (void)Mode;    ec = init(fd, offset, mode);    if (ec)      Mapping = nullptr; @@ -702,7 +697,7 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {    if (cur_dir == nullptr && errno != 0) {      return std::error_code(errno, std::generic_category());    } else if (cur_dir != nullptr) { -    StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); +    StringRef name(cur_dir->d_name);      if ((name.size() == 1 && name[0] == '.') ||          (name.size() == 2 && name[0] == '.' && name[1] == '.'))        return directory_iterator_increment(it); @@ -729,21 +724,83 @@ static bool hasProcSelfFD() {  }  #endif -std::error_code openFileForRead(const Twine &Name, int &ResultFD, -                                SmallVectorImpl<char> *RealPath) { -  SmallString<128> Storage; -  StringRef P = Name.toNullTerminatedStringRef(Storage); -  int OpenFlags = O_RDONLY; +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 F_Append implied +  // would open an existing file.  See Windows/Path.inc for a longer comment. +  if (Flags & F_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 & F_Append) +    Result |= O_APPEND; +  #ifdef O_CLOEXEC -  OpenFlags |= O_CLOEXEC; +  if (!(Flags & OF_ChildInherit)) +    Result |= O_CLOEXEC;  #endif -  if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags)) < 0) + +  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); +  if ((ResultFD = sys::RetryAfterSignal(-1, ::open, P.begin(), OpenFlags, Mode)) < +      0)      return std::error_code(errno, std::generic_category());  #ifndef O_CLOEXEC -  int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC); -  (void)r; -  assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); +  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(); @@ -763,6 +820,9 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,      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)); @@ -771,41 +831,18 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,    return std::error_code();  } -std::error_code openFileForWrite(const Twine &Name, int &ResultFD, -                            sys::fs::OpenFlags Flags, unsigned Mode) { -  // Verify that we don't have both "append" and "excl". -  assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && -         "Cannot specify both 'excl' and 'append' file creation flags!"); - -  int OpenFlags = O_CREAT; - -#ifdef O_CLOEXEC -  OpenFlags |= O_CLOEXEC; -#endif - -  if (Flags & F_RW) -    OpenFlags |= O_RDWR; -  else -    OpenFlags |= O_WRONLY; - -  if (Flags & F_Append) -    OpenFlags |= O_APPEND; -  else -    OpenFlags |= O_TRUNC; - -  if (Flags & F_Excl) -    OpenFlags |= O_EXCL; +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; +} -  SmallString<128> Storage; -  StringRef P = Name.toNullTerminatedStringRef(Storage); -  if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags, Mode)) < 0) -    return std::error_code(errno, std::generic_category()); -#ifndef O_CLOEXEC -  int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC); -  (void)r; -  assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); -#endif -  return std::error_code(); +void closeFile(file_t &F) { +  ::close(F); +  F = kInvalidFile;  }  template <typename T> @@ -860,12 +897,12 @@ std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,      return real_path(Storage, dest, false);    } -  int fd; -  std::error_code EC = openFileForRead(path, fd, &dest); - -  if (EC) -    return EC; -  ::close(fd); +  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();  } diff --git a/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc index e43650d707e3..fa515d44f3f2 100644 --- a/contrib/llvm/lib/Support/Unix/Process.inc +++ b/contrib/llvm/lib/Support/Unix/Process.inc @@ -14,6 +14,7 @@  #include "Unix.h"  #include "llvm/ADT/Hashing.h"  #include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h"  #include "llvm/Support/ManagedStatic.h"  #include "llvm/Support/Mutex.h"  #include "llvm/Support/MutexGuard.h" @@ -78,7 +79,7 @@ unsigned Process::getPageSize() {  #elif defined(HAVE_SYSCONF)    static long page_size = ::sysconf(_SC_PAGE_SIZE);  #else -#warning Cannot get the page size on this machine +#error Cannot get the page size on this machine  #endif    return static_cast<unsigned>(page_size);  } @@ -172,15 +173,6 @@ Optional<std::string> Process::GetEnv(StringRef Name) {    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: @@ -207,7 +199,7 @@ std::error_code Process::FixupStandardFileDescriptors() {    for (int StandardFD : StandardFDs) {      struct stat st;      errno = 0; -    if (RetryAfterSignal(-1, fstat, StandardFD, &st) < 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) @@ -219,7 +211,7 @@ std::error_code Process::FixupStandardFileDescriptors() {      assert(errno == EBADF && "expected errno to have EBADF at this point!");      if (NullFD < 0) { -      if ((NullFD = RetryAfterSignal(-1, open, "/dev/null", O_RDWR)) < 0) +      if ((NullFD = RetryAfterSignal(-1, ::open, "/dev/null", O_RDWR)) < 0)          return std::error_code(errno, std::generic_category());      } @@ -369,6 +361,21 @@ static bool terminalHasColors(int fd) {    // 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. diff --git a/contrib/llvm/lib/Support/Unix/Program.inc b/contrib/llvm/lib/Support/Unix/Program.inc index 4f791991f3e8..d0abc3763e82 100644 --- a/contrib/llvm/lib/Support/Unix/Program.inc +++ b/contrib/llvm/lib/Support/Unix/Program.inc @@ -23,6 +23,7 @@  #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> @@ -164,8 +165,18 @@ static void SetMemoryLimits(unsigned size) {  } -static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, -                    const char **Envp, ArrayRef<Optional<StringRef>> Redirects, +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) {    if (!llvm::sys::fs::exists(Program)) {      if (ErrMsg) @@ -174,6 +185,18 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,      return false;    } +  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 @@ -227,7 +250,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,      // positive.      pid_t PID = 0;      int Err = posix_spawn(&PID, Program.str().c_str(), FileActions, -                          /*attrp*/nullptr, const_cast<char **>(Args), +                          /*attrp*/ nullptr, const_cast<char **>(Argv),                            const_cast<char **>(Envp));      if (FileActions) @@ -237,6 +260,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,       return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);      PI.Pid = PID; +    PI.Process = PID;      return true;    } @@ -279,12 +303,10 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,        // Execute!        std::string PathStr = Program;        if (Envp != nullptr) -        execve(PathStr.c_str(), -               const_cast<char **>(Args), +        execve(PathStr.c_str(), const_cast<char **>(Argv),                 const_cast<char **>(Envp));        else -        execv(PathStr.c_str(), -              const_cast<char **>(Args)); +        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 @@ -300,6 +322,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,    }    PI.Pid = child; +  PI.Process = child;    return true;  } @@ -404,14 +427,14 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,    return WaitResult;  } -  std::error_code sys::ChangeStdinToBinary(){ +std::error_code sys::ChangeStdinToBinary() {    // Do nothing, as Unix doesn't differentiate between text and binary. -    return std::error_code(); +  return std::error_code();  } -  std::error_code sys::ChangeStdoutToBinary(){ +std::error_code sys::ChangeStdoutToBinary() {    // Do nothing, as Unix doesn't differentiate between text and binary. -    return std::error_code(); +  return std::error_code();  }  std::error_code @@ -432,29 +455,38 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,  }  bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, -                                                  ArrayRef<const char *> Args) { +                                                  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 = ArgMax / 2; +  long HalfArgMax = EffectiveArgMax / 2;    size_t ArgLength = Program.size() + 1; -  for (const char* Arg : Args) { -    size_t length = strlen(Arg); - +  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 (length >= (32 * 4096)) +    if (Arg.size() >= (32 * 4096))        return false; -    ArgLength += length + 1; +    ArgLength += Arg.size() + 1;      if (ArgLength > size_t(HalfArgMax)) {        return false;      } diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc index aaf760c5b616..de26695d64ea 100644 --- a/contrib/llvm/lib/Support/Unix/Signals.inc +++ b/contrib/llvm/lib/Support/Unix/Signals.inc @@ -11,9 +11,31 @@  // 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/FileSystem.h"  #include "llvm/Support/FileUtilities.h" @@ -59,24 +81,133 @@ using namespace llvm;  static RETSIGTYPE SignalHandler(int Sig);  // defined below. -static ManagedStatic<sys::SmartMutex<true> > SignalsMutex; +/// The function to call if ctrl-c is pressed. +using InterruptFunctionType = void (*)(); +static std::atomic<InterruptFunctionType> InterruptFunction = +    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); +      } +    } +  } -/// InterruptFunction - The function to call if ctrl-c is pressed. -static void (*InterruptFunction)() = nullptr; +  // 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); +      } +    } -static ManagedStatic<std::vector<std::string>> FilesToRemove; +    // 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; -// 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. +// 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. +// 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 @@ -93,30 +224,12 @@ static const int KillSigs[] = {  #endif  }; -static unsigned NumRegisteredSignals = 0; +static std::atomic<unsigned> NumRegisteredSignals = ATOMIC_VAR_INIT(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 @@ -138,7 +251,7 @@ static void CreateSigAltStack() {      return;    stack_t AltStack = {}; -  AltStack.ss_sp = reinterpret_cast<char *>(malloc(AltStackSize)); +  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) @@ -148,64 +261,59 @@ static void CreateSigAltStack() {  static void CreateSigAltStack() {}  #endif -static void RegisterHandlers() { -  sys::SmartScopedLock<true> Guard(*SignalsMutex); +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 != 0) return; +  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(); -  for (auto S : IntSigs) RegisterHandler(S); -  for (auto S : KillSigs) RegisterHandler(S); +  auto registerHandler = [&](int Signal) { +    unsigned Index = NumRegisteredSignals.load(); +    assert(Index < 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[Index].SA); +    RegisteredSignalInfo[Index].SigNo = Signal; +    ++NumRegisteredSignals; +  }; + +  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) +  for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) {      sigaction(RegisteredSignalInfo[i].SigNo,                &RegisteredSignalInfo[i].SA, nullptr); -  NumRegisteredSignals = 0; +    --NumRegisteredSignals; +  }  } - -/// 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. +/// Process the FilesToRemove list.  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); -  } +  FileToRemoveList::removeAllFiles(FilesToRemove);  } -// SignalHandler - The signal handler that runs. +// 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 @@ -219,20 +327,13 @@ static RETSIGTYPE SignalHandler(int Sig) {    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; -      } +      if (auto OldInterruptFunction = InterruptFunction.exchange(nullptr)) +        return OldInterruptFunction(); -      Guard.unlock();        raise(Sig);   // Execute the default handler.        return;     } @@ -252,45 +353,36 @@ static RETSIGTYPE SignalHandler(int Sig) {  }  void llvm::sys::RunInterruptHandlers() { -  sys::SmartScopedLock<true> Guard(*SignalsMutex);    RemoveFilesToRemove();  }  void llvm::sys::SetInterruptFunction(void (*IF)()) { -  { -    sys::SmartScopedLock<true> Guard(*SignalsMutex); -    InterruptFunction = IF; -  } +  InterruptFunction.exchange(IF);    RegisterHandlers();  } -// RemoveFileOnSignal - The public API +// The public API  bool llvm::sys::RemoveFileOnSignal(StringRef Filename,                                     std::string* ErrMsg) { -  { -    sys::SmartScopedLock<true> Guard(*SignalsMutex); -    FilesToRemove->push_back(Filename); -  } - +  // 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;  } -// DontRemoveFileOnSignal - The public API +// 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); +  FileToRemoveList::erase(FilesToRemove, Filename.str());  } -/// 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)); +/// 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();  } @@ -383,8 +475,8 @@ static int unwindBacktrace(void **StackTrace, int MaxEntries) {  }  #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. +// 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. @@ -463,8 +555,8 @@ static void PrintStackTraceSignalHandler(void *) {  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. +/// 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; diff --git a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc index 31c3f3835b29..a6564f0fa281 100644 --- a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc +++ b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc @@ -16,6 +16,8 @@  //===          is guaranteed to work on *all* UNIX variants.  //===----------------------------------------------------------------------===// +#include "llvm/Config/config.h" +  #if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_GETSPECIFIC)  #include <cassert> diff --git a/contrib/llvm/lib/Support/Unix/Threading.inc b/contrib/llvm/lib/Support/Unix/Threading.inc index 7369cff8466c..2d49ce1ad747 100644 --- a/contrib/llvm/lib/Support/Unix/Threading.inc +++ b/contrib/llvm/lib/Support/Unix/Threading.inc @@ -21,8 +21,8 @@  #include <pthread.h> -#if defined(__FreeBSD__) -#include <pthread_np.h> // For pthread_getthreadid_np() +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#include <pthread_np.h> // For pthread_getthreadid_np() / pthread_set_name_np()  #endif  #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) @@ -98,8 +98,6 @@ uint64_t llvm::get_threadid() {    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 @@ -119,6 +117,8 @@ static constexpr uint32_t get_max_thread_name_length_impl() {  #endif  #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)    return 16; +#elif defined(__OpenBSD__) +  return 32;  #else    return 0;  #endif @@ -138,8 +138,9 @@ void llvm::set_thread_name(const Twine &Name) {    // 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()); +    NameStr = NameStr.take_back(get_max_thread_name_length() - 1);    (void)NameStr;  #if defined(__linux__)  #if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) @@ -147,7 +148,7 @@ void llvm::set_thread_name(const Twine &Name) {    ::pthread_setname_np(::pthread_self(), NameStr.data());  #endif  #endif -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__OpenBSD__)    ::pthread_set_name_np(::pthread_self(), NameStr.data());  #elif defined(__NetBSD__)    ::pthread_setname_np(::pthread_self(), "%s", @@ -175,7 +176,7 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {      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); +      nkp = (struct kinfo_proc *)::realloc(kp, len);        if (nkp == nullptr) {          free(kp);          return; @@ -203,7 +204,6 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {    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. @@ -211,5 +211,4 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) {      Name.append(Buffer, Buffer + strlen(Buffer));  #endif  #endif -#endif  } diff --git a/contrib/llvm/lib/Support/Unix/Unix.h b/contrib/llvm/lib/Support/Unix/Unix.h index 239a6d60aaef..0c5d4de556d5 100644 --- a/contrib/llvm/lib/Support/Unix/Unix.h +++ b/contrib/llvm/lib/Support/Unix/Unix.h @@ -56,7 +56,7 @@  /// 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 +/// Make an error message  ///  /// If the error number can be converted to a string, it will be  /// separated from prefix by ": ". diff --git a/contrib/llvm/lib/Support/Unix/Watchdog.inc b/contrib/llvm/lib/Support/Unix/Watchdog.inc index 5d89c0e51b11..f4253391d952 100644 --- a/contrib/llvm/lib/Support/Unix/Watchdog.inc +++ b/contrib/llvm/lib/Support/Unix/Watchdog.inc @@ -11,6 +11,8 @@  //  //===----------------------------------------------------------------------===// +#include "llvm/Config/config.h" +  #ifdef HAVE_UNISTD_H  #include <unistd.h>  #endif | 
