X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;ds=sidebyside;f=lib%2FSupport%2FUnix%2FProcess.inc;h=df13bd2217390b46c859872aa88b7db2a9f1949f;hb=a983427f67e227649ca3da4cd8f81cc41a56e155;hp=d927bb539ed94158f89e6dd35c9f7c5a05d8814e;hpb=1bab2d53996ca082150f34d8dafc1968fb5ecba9;p=oota-llvm.git diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc index d927bb539ed..df13bd22173 100644 --- a/lib/Support/Unix/Process.inc +++ b/lib/Support/Unix/Process.inc @@ -14,21 +14,34 @@ #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 +#endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SIGNAL_H +#include +#endif // DragonFlyBSD, OpenBSD, and Bitrig have deprecated for // instead. Unix.h includes this for us already. #if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \ !defined(__OpenBSD__) && !defined(__Bitrig__) #include #endif +#if defined(HAVE_MALLCTL) +#include +#endif #ifdef HAVE_MALLOC_MALLOC_H #include #endif @@ -47,11 +60,6 @@ using namespace llvm; using namespace sys; - -process::id_type self_process::get_id() { - return getpid(); -} - static std::pair getRUsageTimes() { #if defined(HAVE_GETRUSAGE) struct rusage RU; @@ -71,43 +79,19 @@ static std::pair 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(TS.tv_sec), - static_cast(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(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; @@ -117,6 +101,12 @@ size_t Process::GetMallocUsage() { 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. @@ -124,8 +114,7 @@ size_t Process::GetMallocUsage() { char *EndOfMemory = (char*)sbrk(0); if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) return EndOfMemory - StartOfMemory; - else - return 0; + return 0; #else #warning Cannot get malloc info on this platform return 0; @@ -190,12 +179,104 @@ Optional Process::GetEnv(StringRef Name) { return std::string(Val); } -error_code Process::GetArgumentVector(SmallVectorImpl &ArgsOut, - ArrayRef ArgsIn, - SpecificBumpPtrAllocator &) { +std::error_code +Process::GetArgumentVector(SmallVectorImpl &ArgsOut, + ArrayRef ArgsIn, + SpecificBumpPtrAllocator &) { ArgsOut.append(ArgsIn.begin(), ArgsIn.end()); - return error_code(); + 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; + 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() { @@ -263,11 +344,14 @@ extern "C" int del_curterm(struct term *termp); extern "C" int tigetnum(char *capname); #endif +#ifdef HAVE_TERMINFO +static ManagedStatic 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)