diff options
Diffstat (limited to 'contrib/llvm/lib/Support/Unix')
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Host.inc | 18 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Memory.inc | 4 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Path.inc | 251 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Process.inc | 142 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Program.inc | 82 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/RWMutex.inc | 12 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Signals.inc | 266 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/ThreadLocal.inc | 45 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/TimeValue.inc | 2 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Unix.h | 4 |
10 files changed, 514 insertions, 312 deletions
diff --git a/contrib/llvm/lib/Support/Unix/Host.inc b/contrib/llvm/lib/Support/Unix/Host.inc index 7941166..519f2a1 100644 --- a/contrib/llvm/lib/Support/Unix/Host.inc +++ b/contrib/llvm/lib/Support/Unix/Host.inc @@ -1,4 +1,4 @@ - //===- llvm/Support/Unix/Host.inc -------------------------------*- C++ -*-===// +//===- llvm/Support/Unix/Host.inc -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,21 +16,15 @@ //=== is guaranteed to work on *all* UNIX variants. //===----------------------------------------------------------------------===// -#include "llvm/Config/config.h" -#include "llvm/ADT/StringRef.h" #include "Unix.h" -#include <sys/utsname.h> +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" #include <cctype> #include <string> -#include <cstdlib> // ::getenv +#include <sys/utsname.h> using namespace llvm; -#ifdef __FreeBSD__ -std::string sys::getDefaultTargetTriple() { - return LLVM_DEFAULT_TARGET_TRIPLE; -} -#else // __FreeBSD__ static std::string getOSVersion() { struct utsname info; @@ -44,7 +38,8 @@ std::string sys::getDefaultTargetTriple() { StringRef TargetTripleString(LLVM_DEFAULT_TARGET_TRIPLE); std::pair<StringRef, StringRef> ArchSplit = TargetTripleString.split('-'); - // Normalize the arch, since the target triple may not actually match the target. + // Normalize the arch, since the target triple may not actually match the + // target. std::string Arch = ArchSplit.first; std::string Triple(Arch); @@ -66,4 +61,3 @@ std::string sys::getDefaultTargetTriple() { return Triple::normalize(Triple); } -#endif // __FreeBSD__ diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc index c9d89a8..7ccde46 100644 --- a/contrib/llvm/lib/Support/Unix/Memory.inc +++ b/contrib/llvm/lib/Support/Unix/Memory.inc @@ -88,7 +88,7 @@ Memory::allocateMappedMemory(size_t NumBytes, if (NumBytes == 0) return MemoryBlock(); - static const size_t PageSize = process::get_self()->page_size(); + static const size_t PageSize = Process::getPageSize(); const size_t NumPages = (NumBytes+PageSize-1)/PageSize; int fd = -1; @@ -181,7 +181,7 @@ Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, std::string *ErrMsg) { if (NumBytes == 0) return MemoryBlock(); - size_t PageSize = process::get_self()->page_size(); + size_t PageSize = Process::getPageSize(); size_t NumPages = (NumBytes+PageSize-1)/PageSize; int fd = -1; diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc index 623547a..973d010 100644 --- a/contrib/llvm/lib/Support/Unix/Path.inc +++ b/contrib/llvm/lib/Support/Unix/Path.inc @@ -62,47 +62,6 @@ using namespace llvm; -namespace { - /// This class automatically closes the given file descriptor when it goes out - /// of scope. You can take back explicit ownership of the file descriptor by - /// calling take(). The destructor does not verify that close was successful. - /// Therefore, never allow this class to call close on a file descriptor that - /// has been read from or written to. - struct AutoFD { - int FileDescriptor; - - AutoFD(int fd) : FileDescriptor(fd) {} - ~AutoFD() { - if (FileDescriptor >= 0) - ::close(FileDescriptor); - } - - int take() { - int ret = FileDescriptor; - FileDescriptor = -1; - return ret; - } - - operator int() const {return FileDescriptor;} - }; -} - -static std::error_code TempDir(SmallVectorImpl<char> &result) { - // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. - const char *dir = nullptr; - (dir = std::getenv("TMPDIR")) || (dir = std::getenv("TMP")) || - (dir = std::getenv("TEMP")) || (dir = std::getenv("TEMPDIR")) || -#ifdef P_tmpdir - (dir = P_tmpdir) || -#endif - (dir = "/tmp"); - - result.clear(); - StringRef d(dir); - result.append(d.begin(), d.end()); - return std::error_code(); -} - namespace llvm { namespace sys { namespace fs { @@ -191,7 +150,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { // /proc is not always mounted under Linux (chroot for example). ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path)); if (len >= 0) - return StringRef(exe_path, len); + return std::string(exe_path, len); } else { // Fall back to the classical detection. if (getprogpath(exe_path, argv0) != NULL) @@ -272,19 +231,6 @@ std::error_code create_directory(const Twine &path, bool IgnoreExisting) { return std::error_code(); } -std::error_code normalize_separators(SmallVectorImpl<char> &Path) { - for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) { - if (*PI == '\\') { - auto PN = PI + 1; - if (PN < PE && *PN == '\\') - ++PI; // increment once, the for loop will move over the escaped slash - else - *PI = '/'; - } - } - return std::error_code(); -} - // Note that we are using symbolic link because hard links are not supported by // all filesystems (SMB doesn't). std::error_code create_link(const Twine &to, const Twine &from) { @@ -340,48 +286,42 @@ std::error_code rename(const Twine &from, const Twine &to) { return std::error_code(); } -std::error_code resize_file(const Twine &path, uint64_t size) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - if (::truncate(p.begin(), size) == -1) +std::error_code resize_file(int FD, uint64_t Size) { + if (::ftruncate(FD, Size) == -1) return std::error_code(errno, std::generic_category()); return std::error_code(); } -std::error_code exists(const Twine &path, bool &result) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - if (::access(p.begin(), F_OK) == -1) { - if (errno != ENOENT) - return std::error_code(errno, std::generic_category()); - result = false; - } else - result = true; - - return std::error_code(); +static int convertAccessMode(AccessMode Mode) { + switch (Mode) { + case AccessMode::Exist: + return F_OK; + case AccessMode::Write: + return W_OK; + case AccessMode::Execute: + return R_OK | X_OK; // scripts also need R_OK. + } + llvm_unreachable("invalid enum"); } -bool can_write(const Twine &Path) { +std::error_code access(const Twine &Path, AccessMode Mode) { SmallString<128> PathStorage; StringRef P = Path.toNullTerminatedStringRef(PathStorage); - return 0 == access(P.begin(), W_OK); -} -bool can_execute(const Twine &Path) { - SmallString<128> PathStorage; - StringRef P = Path.toNullTerminatedStringRef(PathStorage); + if (::access(P.begin(), convertAccessMode(Mode)) == -1) + return std::error_code(errno, std::generic_category()); - if (0 != access(P.begin(), R_OK | X_OK)) - return false; - struct stat buf; - if (0 != stat(P.begin(), &buf)) - return false; - if (!S_ISREG(buf.st_mode)) - return false; - return true; + if (Mode == AccessMode::Execute) { + // Don't say that directories are executable. + struct stat buf; + if (0 != stat(P.begin(), &buf)) + return errc::permission_denied; + if (!S_ISREG(buf.st_mode)) + return errc::permission_denied; + } + + return std::error_code(); } bool equivalent(file_status A, file_status B) { @@ -472,80 +412,28 @@ std::error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { #endif } -std::error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { - AutoFD ScopedFD(FD); - if (!CloseFD) - ScopedFD.take(); - - // Figure out how large the file is. - struct stat FileInfo; - if (fstat(FD, &FileInfo) == -1) - return std::error_code(errno, std::generic_category()); - uint64_t FileSize = FileInfo.st_size; - - if (Size == 0) - Size = FileSize; - else if (FileSize < Size) { - // We need to grow the file. - if (ftruncate(FD, Size) == -1) - return std::error_code(errno, std::generic_category()); - } +std::error_code mapped_file_region::init(int FD, uint64_t Offset, + mapmode Mode) { + assert(Size != 0); int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); -#ifdef MAP_FILE - flags |= MAP_FILE; -#endif Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset); if (Mapping == MAP_FAILED) return std::error_code(errno, std::generic_category()); return std::error_code(); } -mapped_file_region::mapped_file_region(const Twine &path, - mapmode mode, - uint64_t length, - uint64_t offset, - std::error_code &ec) - : Mode(mode) - , Size(length) - , Mapping() { +mapped_file_region::mapped_file_region(int fd, mapmode mode, uint64_t length, + uint64_t offset, std::error_code &ec) + : Size(length), Mapping() { // Make sure that the requested size fits within SIZE_T. if (length > std::numeric_limits<size_t>::max()) { ec = make_error_code(errc::invalid_argument); return; } - SmallString<128> path_storage; - StringRef name = path.toNullTerminatedStringRef(path_storage); - int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; - int ofd = ::open(name.begin(), oflags); - if (ofd == -1) { - ec = std::error_code(errno, std::generic_category()); - return; - } - - ec = init(ofd, true, offset); - if (ec) - Mapping = nullptr; -} - -mapped_file_region::mapped_file_region(int fd, - bool closefd, - mapmode mode, - uint64_t length, - uint64_t offset, - std::error_code &ec) - : Mode(mode) - , Size(length) - , Mapping() { - // Make sure that the requested size fits within SIZE_T. - if (length > std::numeric_limits<size_t>::max()) { - ec = make_error_code(errc::invalid_argument); - return; - } - - ec = init(fd, closefd, offset); + ec = init(fd, offset, mode); if (ec) Mapping = nullptr; } @@ -555,16 +443,6 @@ mapped_file_region::~mapped_file_region() { ::munmap(Mapping, Size); } -mapped_file_region::mapped_file_region(mapped_file_region &&other) - : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { - other.Mapping = nullptr; -} - -mapped_file_region::mapmode mapped_file_region::flags() const { - assert(Mapping && "Mapping failed but used anyway!"); - return Mode; -} - uint64_t mapped_file_region::size() const { assert(Mapping && "Mapping failed but used anyway!"); return Size; @@ -572,7 +450,6 @@ uint64_t mapped_file_region::size() const { char *mapped_file_region::data() const { assert(Mapping && "Mapping failed but used anyway!"); - assert(Mode != readonly && "Cannot get non-const data for readonly mapping!"); return reinterpret_cast<char*>(Mapping); } @@ -582,7 +459,7 @@ const char *mapped_file_region::const_data() const { } int mapped_file_region::alignment() { - return process::get_self()->page_size(); + return Process::getPageSize(); } std::error_code detail::directory_iterator_construct(detail::DirIterState &it, @@ -678,6 +555,66 @@ bool home_directory(SmallVectorImpl<char> &result) { return false; } +static const char *getEnvTempDir() { + // Check whether the temporary directory is specified by an environment + // variable. + const char *EnvironmentVariables[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}; + for (const char *Env : EnvironmentVariables) { + if (const char *Dir = std::getenv(Env)) + return Dir; + } + + return nullptr; +} + +static const char *getDefaultTempDir(bool ErasedOnReboot) { +#ifdef P_tmpdir + if ((bool)P_tmpdir) + return P_tmpdir; +#endif + + if (ErasedOnReboot) + return "/tmp"; + return "/var/tmp"; +} + +void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { + Result.clear(); + + if (ErasedOnReboot) { + // There is no env variable for the cache directory. + if (const char *RequestedDir = getEnvTempDir()) { + Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); + return; + } + } + +#if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR) + // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. + // macros defined in <unistd.h> on darwin >= 9 + int ConfName = ErasedOnReboot? _CS_DARWIN_USER_TEMP_DIR + : _CS_DARWIN_USER_CACHE_DIR; + size_t ConfLen = confstr(ConfName, nullptr, 0); + if (ConfLen > 0) { + do { + Result.resize(ConfLen); + ConfLen = confstr(ConfName, Result.data(), Result.size()); + } while (ConfLen > 0 && ConfLen != Result.size()); + + if (ConfLen > 0) { + assert(Result.back() == 0); + Result.pop_back(); + return; + } + + Result.clear(); + } +#endif + + const char *RequestedDir = getDefaultTempDir(ErasedOnReboot); + Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); +} + } // end namespace path } // end namespace sys diff --git a/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc index d2c5dbc..530f86c 100644 --- a/contrib/llvm/lib/Support/Unix/Process.inc +++ b/contrib/llvm/lib/Support/Unix/Process.inc @@ -14,15 +14,25 @@ #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" #include "llvm/Support/TimeValue.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, OpenBSD, and Bitrig have deprecated <malloc.h> for // <stdlib.h> instead. Unix.h includes this for us already. #if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \ @@ -47,10 +57,6 @@ using namespace llvm; using namespace sys; -process::id_type self_process::get_id() { - return getpid(); -} - static std::pair<TimeValue, TimeValue> getRUsageTimes() { #if defined(HAVE_GETRUSAGE) struct rusage RU; @@ -70,43 +76,19 @@ static std::pair<TimeValue, TimeValue> getRUsageTimes() { #endif } -TimeValue self_process::get_user_time() const { -#if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0 - // Try to get a high resolution CPU timer. - struct timespec TS; - if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0) - return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec), - static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec)); -#endif - - // Otherwise fall back to rusage based timing. - return getRUsageTimes().first; -} - -TimeValue self_process::get_system_time() const { - // We can only collect system time by inspecting the results of getrusage. - return getRUsageTimes().second; -} - // On Cygwin, getpagesize() returns 64k(AllocationGranularity) and // offset in mmap(3) should be aligned to the AllocationGranularity. -static unsigned getPageSize() { +unsigned Process::getPageSize() { #if defined(HAVE_GETPAGESIZE) - const int page_size = ::getpagesize(); + static const int page_size = ::getpagesize(); #elif defined(HAVE_SYSCONF) - long page_size = ::sysconf(_SC_PAGE_SIZE); + 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); } -// This constructor guaranteed to be run exactly once on a single thread, and -// sets up various process invariants that can be queried cheaply from then on. -self_process::self_process() : PageSize(getPageSize()) { -} - - size_t Process::GetMallocUsage() { #if defined(HAVE_MALLINFO) struct mallinfo mi; @@ -198,6 +180,97 @@ Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut, 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 &) LLVM_DELETED_FUNCTION; + void operator=(const FDCloser &) LLVM_DELETED_FUNCTION; + + 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; + while (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) + break; + // retry fstat if we got EINTR, otherwise bubble up the failure. + if (errno != EINTR) + 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) { + while ((NullFD = open("/dev/null", O_RDWR)) < 0) { + if (errno == EINTR) + continue; + 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); } @@ -263,11 +336,14 @@ 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. - static sys::Mutex M; - MutexGuard G(M); + MutexGuard G(*TermColorMutex); int errret = 0; if (setupterm((char *)nullptr, fd, &errret) != 0) diff --git a/contrib/llvm/lib/Support/Unix/Program.inc b/contrib/llvm/lib/Support/Unix/Program.inc index 06a33cd..0f45df1 100644 --- a/contrib/llvm/lib/Support/Unix/Program.inc +++ b/contrib/llvm/lib/Support/Unix/Program.inc @@ -17,8 +17,10 @@ //===----------------------------------------------------------------------===// #include "Unix.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" #include <llvm/Config/config.h> #if HAVE_SYS_STAT_H #include <sys/stat.h> @@ -53,50 +55,32 @@ using namespace sys; ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {} -// This function just uses the PATH environment variable to find the program. -std::string -sys::FindProgramByName(const std::string& progName) { - - // Check some degenerate cases - if (progName.length() == 0) // no program - return ""; - std::string temp = progName; +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 (progName.find('/') != std::string::npos) - return temp; - - // At this point, the file name is valid and does not contain slashes. Search - // for it through the directories specified in the PATH environment variable. - - // Get the path. If its empty, we can't do anything to find it. - const char *PathStr = getenv("PATH"); - if (!PathStr) - return ""; + 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; + } - // Now we have a colon separated list of directories to search; try them. - size_t PathLen = strlen(PathStr); - while (PathLen) { - // Find the first colon... - const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); + for (auto Path : Paths) { + if (Path.empty()) + continue; // Check to see if this first directory contains the executable... - SmallString<128> FilePath(PathStr,Colon); - sys::path::append(FilePath, progName); - if (sys::fs::can_execute(Twine(FilePath))) - return FilePath.str(); // Found the executable! - - // Nope it wasn't in this directory, check the next path in the list! - PathLen -= Colon-PathStr; - PathStr = Colon; - - // Advance past duplicate colons - while (*PathStr == ':') { - PathStr++; - PathLen--; - } + 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 ""; + return std::errc::no_such_file_or_directory; } static bool RedirectIO(const StringRef *Path, int FD, std::string* ErrMsg) { @@ -334,7 +318,6 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, pid_t ChildPid = PI.Pid; if (WaitUntilTerminates) { SecondsToWait = 0; - ChildPid = -1; // mimic a wait() using waitpid() } 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 @@ -440,6 +423,23 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, 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 std::make_error_code(std::errc::io_error); + + return EC; +} + bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { static long ArgMax = sysconf(_SC_ARG_MAX); @@ -448,13 +448,13 @@ bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { return true; // Conservatively account for space required by environment variables. - ArgMax /= 2; + long HalfArgMax = ArgMax / 2; size_t ArgLength = 0; for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); I != E; ++I) { ArgLength += strlen(*I) + 1; - if (ArgLength > size_t(ArgMax)) { + if (ArgLength > size_t(HalfArgMax)) { return false; } } diff --git a/contrib/llvm/lib/Support/Unix/RWMutex.inc b/contrib/llvm/lib/Support/Unix/RWMutex.inc index edcbd52..85a1043 100644 --- a/contrib/llvm/lib/Support/Unix/RWMutex.inc +++ b/contrib/llvm/lib/Support/Unix/RWMutex.inc @@ -26,26 +26,26 @@ using namespace sys; // will therefore deadlock if a thread tries to acquire a read lock // multiple times. -RWMutexImpl::RWMutexImpl() : data_(new Mutex(false)) { } +RWMutexImpl::RWMutexImpl() : data_(new MutexImpl(false)) { } RWMutexImpl::~RWMutexImpl() { - delete static_cast<Mutex *>(data_); + delete static_cast<MutexImpl *>(data_); } bool RWMutexImpl::reader_acquire() { - return static_cast<Mutex *>(data_)->acquire(); + return static_cast<MutexImpl *>(data_)->acquire(); } bool RWMutexImpl::reader_release() { - return static_cast<Mutex *>(data_)->release(); + return static_cast<MutexImpl *>(data_)->release(); } bool RWMutexImpl::writer_acquire() { - return static_cast<Mutex *>(data_)->acquire(); + return static_cast<MutexImpl *>(data_)->acquire(); } bool RWMutexImpl::writer_release() { - return static_cast<Mutex *>(data_)->release(); + return static_cast<MutexImpl *>(data_)->release(); } } diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc index 1841fea..e8f4643 100644 --- a/contrib/llvm/lib/Support/Unix/Signals.inc +++ b/contrib/llvm/lib/Support/Unix/Signals.inc @@ -14,7 +14,14 @@ #include "Unix.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/ManagedStatic.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> #include <vector> @@ -36,18 +43,22 @@ #if HAVE_MACH_MACH_H #include <mach/mach.h> #endif +#if HAVE_LINK_H +#include <link.h> +#endif using namespace llvm; static RETSIGTYPE SignalHandler(int Sig); // defined below. -static SmartMutex<true> SignalsMutex; +static ManagedStatic<SmartMutex<true> > SignalsMutex; /// InterruptFunction - The function to call if ctrl-c is pressed. static void (*InterruptFunction)() = nullptr; -static std::vector<std::string> FilesToRemove; -static std::vector<std::pair<void(*)(void*), void*> > CallBacksToRun; +static ManagedStatic<std::vector<std::string>> FilesToRemove; +static ManagedStatic<std::vector<std::pair<void (*)(void *), void *>>> + CallBacksToRun; // IntSigs - Signals that represent requested termination. There's no bug // or failure, or if there is, it's not our direct responsibility. For whatever @@ -55,7 +66,6 @@ static std::vector<std::pair<void(*)(void*), void*> > CallBacksToRun; static const int IntSigs[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 }; -static const int *const IntSigsEnd = std::end(IntSigs); // KillSigs - Signals that represent that we have a bug, and our prompt // termination has been ordered. @@ -74,7 +84,6 @@ static const int KillSigs[] = { , SIGEMT #endif }; -static const int *const KillSigsEnd = std::end(KillSigs); static unsigned NumRegisteredSignals = 0; static struct { @@ -105,8 +114,8 @@ static void RegisterHandlers() { // If the handlers are already registered, we're done. if (NumRegisteredSignals != 0) return; - std::for_each(IntSigs, IntSigsEnd, RegisterHandler); - std::for_each(KillSigs, KillSigsEnd, RegisterHandler); + for (auto S : IntSigs) RegisterHandler(S); + for (auto S : KillSigs) RegisterHandler(S); } static void UnregisterHandlers() { @@ -125,11 +134,12 @@ static void UnregisterHandlers() { static void RemoveFilesToRemove() { // We avoid iterators in case of debug iterators that allocate or release // memory. - for (unsigned i = 0, e = FilesToRemove.size(); i != e; ++i) { + std::vector<std::string>& FilesToRemoveRef = *FilesToRemove; + for (unsigned i = 0, e = FilesToRemoveRef.size(); i != e; ++i) { // We rely on a std::string implementation for which repeated calls to // 'c_str()' don't allocate memory. We pre-call 'c_str()' on all of these // strings to try to ensure this is safe. - const char *path = FilesToRemove[i].c_str(); + 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. @@ -162,28 +172,31 @@ static RETSIGTYPE SignalHandler(int Sig) { sigfillset(&SigMask); sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); - SignalsMutex.acquire(); - RemoveFilesToRemove(); - - if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { - if (InterruptFunction) { - void (*IF)() = InterruptFunction; - SignalsMutex.release(); - InterruptFunction = nullptr; - IF(); // run the interrupt function. + { + unique_lock<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; - } - - SignalsMutex.release(); - raise(Sig); // Execute the default handler. - return; + } } - SignalsMutex.release(); - // Otherwise if it is a fault (like SEGV) run any handler. - for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i) - CallBacksToRun[i].first(CallBacksToRun[i].second); + std::vector<std::pair<void (*)(void *), void *>>& CallBacksToRunRef = + *CallBacksToRun; + for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) + CallBacksToRunRef[i].first(CallBacksToRunRef[i].second); #ifdef __s390__ // On S/390, certain signals are delivered with PSW Address pointing to @@ -196,37 +209,39 @@ static RETSIGTYPE SignalHandler(int Sig) { } void llvm::sys::RunInterruptHandlers() { - SignalsMutex.acquire(); + sys::SmartScopedLock<true> Guard(*SignalsMutex); RemoveFilesToRemove(); - SignalsMutex.release(); } void llvm::sys::SetInterruptFunction(void (*IF)()) { - SignalsMutex.acquire(); - InterruptFunction = IF; - SignalsMutex.release(); + { + sys::SmartScopedLock<true> Guard(*SignalsMutex); + InterruptFunction = IF; + } RegisterHandlers(); } // RemoveFileOnSignal - The public API bool llvm::sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { - SignalsMutex.acquire(); - std::string *OldPtr = FilesToRemove.empty() ? nullptr : &FilesToRemove[0]; - FilesToRemove.push_back(Filename); - - // We want to call 'c_str()' on every std::string in this vector so that if - // the underlying implementation requires a re-allocation, it happens here - // rather than inside of the signal handler. If we see the vector grow, we - // have to call it on every entry. If it remains in place, we only need to - // call it on the latest one. - if (OldPtr == &FilesToRemove[0]) - FilesToRemove.back().c_str(); - else - for (unsigned i = 0, e = FilesToRemove.size(); i != e; ++i) - FilesToRemove[i].c_str(); - - SignalsMutex.release(); + { + sys::SmartScopedLock<true> Guard(*SignalsMutex); + std::vector<std::string>& FilesToRemoveRef = *FilesToRemove; + std::string *OldPtr = + FilesToRemoveRef.empty() ? nullptr : &FilesToRemoveRef[0]; + FilesToRemoveRef.push_back(Filename); + + // We want to call 'c_str()' on every std::string in this vector so that if + // the underlying implementation requires a re-allocation, it happens here + // rather than inside of the signal handler. If we see the vector grow, we + // have to call it on every entry. If it remains in place, we only need to + // call it on the latest one. + if (OldPtr == &FilesToRemoveRef[0]) + FilesToRemoveRef.back().c_str(); + else + for (unsigned i = 0, e = FilesToRemoveRef.size(); i != e; ++i) + FilesToRemoveRef[i].c_str(); + } RegisterHandlers(); return false; @@ -234,31 +249,166 @@ bool llvm::sys::RemoveFileOnSignal(StringRef Filename, // DontRemoveFileOnSignal - The public API void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) { - SignalsMutex.acquire(); + sys::SmartScopedLock<true> Guard(*SignalsMutex); std::vector<std::string>::reverse_iterator RI = - std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename); - std::vector<std::string>::iterator I = FilesToRemove.end(); - if (RI != FilesToRemove.rend()) - I = FilesToRemove.erase(RI.base()-1); + std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); + std::vector<std::string>::iterator I = FilesToRemove->end(); + if (RI != FilesToRemove->rend()) + I = FilesToRemove->erase(RI.base()-1); // We need to call c_str() on every element which would have been moved by // the erase. These elements, in a C++98 implementation where c_str() // requires a reallocation on the first call may have had the call to c_str() // made on insertion become invalid by being copied down an element. - for (std::vector<std::string>::iterator E = FilesToRemove.end(); I != E; ++I) + for (std::vector<std::string>::iterator E = FilesToRemove->end(); I != E; ++I) I->c_str(); - - SignalsMutex.release(); } /// 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)); + CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); RegisterHandlers(); } +#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) + +#if 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; +} + +static bool findModulesAndOffsets(void **StackTrace, int Depth, + const char **Modules, intptr_t *Offsets, + const char *MainExecutableName) { + DlIteratePhdrData data = {StackTrace, Depth, true, + Modules, Offsets, MainExecutableName}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); + return true; +} +#else +static bool findModulesAndOffsets(void **StackTrace, int Depth, + const char **Modules, intptr_t *Offsets, + const char *MainExecutableName) { + return false; +} +#endif + +static bool printSymbolizedStackTrace(void **StackTrace, int Depth, FILE *FD) { + // FIXME: Subtract necessary number from StackTrace entries to turn return addresses + // into actual instruction addresses. + // Use llvm-symbolizer tool to symbolize the stack traces. + ErrorOr<std::string> LLVMSymbolizerPathOrErr = + sys::findProgramByName("llvm-symbolizer"); + if (!LLVMSymbolizerPathOrErr) + return false; + const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr; + // We don't know argv0 or the address of main() at this point, but try + // to guess it anyway (it's possible on some platforms). + std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr); + if (MainExecutableName.empty() || + MainExecutableName.find("llvm-symbolizer") != std::string::npos) + return false; + + std::vector<const char *> Modules(Depth, nullptr); + std::vector<intptr_t> Offsets(Depth, 0); + if (!findModulesAndOffsets(StackTrace, Depth, Modules.data(), Offsets.data(), + MainExecutableName.c_str())) + return false; + int InputFD; + SmallString<32> InputFile, OutputFile; + sys::fs::createTemporaryFile("symbolizer-input", "", InputFD, InputFile); + sys::fs::createTemporaryFile("symbolizer-output", "", OutputFile); + FileRemover InputRemover(InputFile.c_str()); + FileRemover OutputRemover(OutputFile.c_str()); + + { + raw_fd_ostream Input(InputFD, true); + for (int i = 0; i < Depth; i++) { + if (Modules[i]) + Input << Modules[i] << " " << (void*)Offsets[i] << "\n"; + } + } + + StringRef InputFileStr(InputFile); + StringRef OutputFileStr(OutputFile); + StringRef StderrFileStr; + const StringRef *Redirects[] = {&InputFileStr, &OutputFileStr, + &StderrFileStr}; + const char *Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining", + "--demangle", nullptr}; + int RunResult = + sys::ExecuteAndWait(LLVMSymbolizerPath, Args, nullptr, Redirects); + if (RunResult != 0) + return false; + + auto OutputBuf = MemoryBuffer::getFile(OutputFile.c_str()); + if (!OutputBuf) + return false; + StringRef Output = OutputBuf.get()->getBuffer(); + SmallVector<StringRef, 32> Lines; + Output.split(Lines, "\n"); + auto CurLine = Lines.begin(); + int frame_no = 0; + for (int i = 0; i < Depth; i++) { + if (!Modules[i]) { + fprintf(FD, "#%d %p\n", frame_no++, StackTrace[i]); + continue; + } + // Read pairs of lines (function name and file/line info) until we + // encounter empty line. + for (;;) { + if (CurLine == Lines.end()) + return false; + StringRef FunctionName = *CurLine++; + if (FunctionName.empty()) + break; + fprintf(FD, "#%d %p ", frame_no++, StackTrace[i]); + if (!FunctionName.startswith("??")) + fprintf(FD, "%s ", FunctionName.str().c_str()); + if (CurLine == Lines.end()) + return false; + StringRef FileLineInfo = *CurLine++; + if (!FileLineInfo.startswith("??")) + fprintf(FD, "%s", FileLineInfo.str().c_str()); + else + fprintf(FD, "(%s+%p)", Modules[i], (void *)Offsets[i]); + fprintf(FD, "\n"); + } + } + return true; +} +#endif // defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) // 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. @@ -271,6 +421,8 @@ void llvm::sys::PrintStackTrace(FILE *FD) { // Use backtrace() to output a backtrace on Linux systems with glibc. int depth = backtrace(StackTrace, static_cast<int>(array_lengthof(StackTrace))); + if (printSymbolizedStackTrace(StackTrace, depth, FD)) + return; #if HAVE_DLFCN_H && __GNUG__ int width = 0; for (int i = 0; i < depth; ++i) { diff --git a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc index f14d0fa..31c3f38 100644 --- a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc +++ b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc @@ -16,11 +16,54 @@ //=== 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);} -const void* ThreadLocalImpl::getInstance() { return data; } +void *ThreadLocalImpl::getInstance() { return data; } void ThreadLocalImpl::removeInstance() { setInstance(0); } } +#endif diff --git a/contrib/llvm/lib/Support/Unix/TimeValue.inc b/contrib/llvm/lib/Support/Unix/TimeValue.inc index 7d4acf7..042e0da 100644 --- a/contrib/llvm/lib/Support/Unix/TimeValue.inc +++ b/contrib/llvm/lib/Support/Unix/TimeValue.inc @@ -41,7 +41,7 @@ TimeValue TimeValue::now() { // errors concern the timezone parameter which we're passing in as 0. // In the unlikely case it does happen, just return MinTime, no error // message needed. - return MinTime; + return MinTime(); } return TimeValue( diff --git a/contrib/llvm/lib/Support/Unix/Unix.h b/contrib/llvm/lib/Support/Unix/Unix.h index ba688e3..e16a226 100644 --- a/contrib/llvm/lib/Support/Unix/Unix.h +++ b/contrib/llvm/lib/Support/Unix/Unix.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_SYSTEM_UNIX_UNIX_H -#define LLVM_SYSTEM_UNIX_UNIX_H +#ifndef LLVM_LIB_SUPPORT_UNIX_UNIX_H +#define LLVM_LIB_SUPPORT_UNIX_UNIX_H //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only generic UNIX code that |