diff options
Diffstat (limited to 'lib/Support/Unix')
-rw-r--r-- | lib/Support/Unix/Path.inc | 17 | ||||
-rw-r--r-- | lib/Support/Unix/Process.inc | 116 | ||||
-rw-r--r-- | lib/Support/Unix/Program.inc | 127 | ||||
-rw-r--r-- | lib/Support/Unix/Signals.inc | 4 | ||||
-rw-r--r-- | lib/Support/Unix/ThreadLocal.inc | 2 | ||||
-rw-r--r-- | lib/Support/Unix/Unix.h | 4 |
6 files changed, 154 insertions, 116 deletions
diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc index 4dcfa09..c9dc871 100644 --- a/lib/Support/Unix/Path.inc +++ b/lib/Support/Unix/Path.inc @@ -182,7 +182,7 @@ namespace sys { namespace fs { #if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \ - defined(__linux__) || defined(__CYGWIN__) + defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__) static int test_dir(char buf[PATH_MAX], char ret[PATH_MAX], const char *dir, const char *bin) @@ -251,7 +251,8 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { return link_path; } #elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ - defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) + defined(__OpenBSD__) || defined(__minix) || defined(__DragonFly__) || \ + defined(__FreeBSD_kernel__) char exe_path[PATH_MAX]; if (getprogpath(exe_path, argv0) != NULL) @@ -298,6 +299,18 @@ UniqueID file_status::getUniqueID() const { } error_code current_path(SmallVectorImpl<char> &result) { + result.clear(); + + const char *pwd = ::getenv("PWD"); + llvm::sys::fs::file_status PWDStatus, DotStatus; + if (pwd && llvm::sys::path::is_absolute(pwd) && + !llvm::sys::fs::status(pwd, PWDStatus) && + !llvm::sys::fs::status(".", DotStatus) && + PWDStatus.getUniqueID() == DotStatus.getUniqueID()) { + result.append(pwd, pwd + strlen(pwd)); + return error_code::success(); + } + #ifdef MAXPATHLEN result.reserve(MAXPATHLEN); #else diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc index 0a797f6..c5778e7 100644 --- a/lib/Support/Unix/Process.inc +++ b/lib/Support/Unix/Process.inc @@ -13,6 +13,7 @@ #include "Unix.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" #include "llvm/Support/TimeValue.h" @@ -38,25 +39,6 @@ # include <termios.h> #endif -// See if we can use curses to detect information about a terminal when -// connected to one. -#ifdef HAVE_CURSES -# if defined(HAVE_CURSES_H) -# include <curses.h> -# elif defined(HAVE_NCURSES_H) -# include <ncurses.h> -# elif defined(HAVE_NCURSESW_H) -# include <ncursesw.h> -# elif defined(HAVE_NCURSES_CURSES_H) -# include <ncurses/curses.h> -# elif defined(HAVE_NCURSESW_CURSES_H) -# include <ncursesw/curses.h> -# else -# error Have a curses library but unable to find a curses header! -# endif -# include <term.h> -#endif - //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only generic UNIX code that //=== is guaranteed to work on *all* UNIX variants. @@ -107,13 +89,10 @@ TimeValue self_process::get_system_time() const { return getRUsageTimes().second; } +// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and +// offset in mmap(3) should be aligned to the AllocationGranularity. static unsigned getPageSize() { -#if defined(__CYGWIN__) - // On Cygwin, getpagesize() returns 64k but the page size for the purposes of - // memory protection and mmap() is 4k. - // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 - const int page_size = 0x1000; -#elif defined(HAVE_GETPAGESIZE) +#if defined(HAVE_GETPAGESIZE) const int page_size = ::getpagesize(); #elif defined(HAVE_SYSCONF) long page_size = ::sysconf(_SC_PAGE_SIZE); @@ -159,14 +138,6 @@ void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, llvm::tie(user_time, sys_time) = getRUsageTimes(); } -int Process::GetCurrentUserId() { - return getuid(); -} - -int Process::GetCurrentGroupId() { - return getgid(); -} - #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) #include <mach/mach.h> #endif @@ -211,6 +182,22 @@ void Process::PreventCoreFiles() { #endif } +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); +} + +error_code Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut, + ArrayRef<const char *> ArgsIn, + SpecificBumpPtrAllocator<char> &) { + ArgsOut.append(ArgsIn.begin(), ArgsIn.end()); + + return error_code::success(); +} + bool Process::StandardInIsUserInput() { return FileDescriptorIsDisplayed(STDIN_FILENO); } @@ -266,21 +253,50 @@ unsigned Process::StandardErrColumns() { 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 + static bool terminalHasColors(int fd) { -#ifdef HAVE_CURSES - // First, acquire a global lock because the curses C routines are thread - // hostile. +#ifdef HAVE_TERMINFO + // First, acquire a global lock because these C routines are thread hostile. static sys::Mutex M; MutexGuard G(M); int errret = 0; - if (setupterm((char *)0, fd, &errret) != OK) + if (setupterm((char *)0, 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. - if (has_colors() == TRUE) + // 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((struct term *)0); + (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 @@ -302,29 +318,15 @@ 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; } -#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" - -#define ALLCOLORS(FGBG,BOLD) {\ - COLOR(FGBG, "0", BOLD),\ - COLOR(FGBG, "1", BOLD),\ - COLOR(FGBG, "2", BOLD),\ - COLOR(FGBG, "3", BOLD),\ - COLOR(FGBG, "4", BOLD),\ - COLOR(FGBG, "5", BOLD),\ - COLOR(FGBG, "6", BOLD),\ - COLOR(FGBG, "7", BOLD)\ - } - -static const char colorcodes[2][2][8][10] = { - { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, - { ALLCOLORS("4",""), ALLCOLORS("4","1;") } -}; - const char *Process::OutputColor(char code, bool bold, bool bg) { return colorcodes[bg?1:0][bold?1:0][code&7]; } diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index a93a912..78b2971 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -36,6 +36,9 @@ #include <unistd.h> #endif #ifdef HAVE_POSIX_SPAWN +#ifdef __sun__ +#define _RESTRICT_KYWD +#endif #include <spawn.h> #if !defined(__APPLE__) extern char **environ; @@ -47,6 +50,8 @@ namespace llvm { 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) { @@ -175,9 +180,16 @@ static void SetMemoryLimits (unsigned size) } -static bool Execute(void **Data, StringRef Program, const char **args, +static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, const char **envp, const 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 @@ -239,8 +251,8 @@ static bool Execute(void **Data, StringRef Program, const char **args, if (Err) return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); - if (Data) - *Data = reinterpret_cast<void*>(PID); + PI.Pid = PID; + return true; } #endif @@ -303,56 +315,71 @@ static bool Execute(void **Data, StringRef Program, const char **args, break; } - if (Data) - *Data = reinterpret_cast<void*>(child); + PI.Pid = child; return true; } -static int Wait(void *&Data, StringRef Program, unsigned secondsToWait, - std::string *ErrMsg) { +namespace llvm { + +ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, + bool WaitUntilTerminates, std::string *ErrMsg) { #ifdef HAVE_SYS_WAIT_H struct sigaction Act, Old; - assert(Data && "invalid pid to wait on, process not started?"); - - // 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. - if (secondsToWait) { + assert(PI.Pid && "invalid pid to wait on, process not started?"); + + int WaitPidOptions = 0; + 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 + // 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); - } + alarm(SecondsToWait); + } else if (SecondsToWait == 0) + WaitPidOptions = WNOHANG; // Parent process: Wait for the child process to terminate. int status; - uint64_t pid = reinterpret_cast<uint64_t>(Data); - pid_t child = static_cast<pid_t>(pid); - while (waitpid(pid, &status, 0) != child) - if (secondsToWait && errno == EINTR) { - // Kill the child. - kill(child, SIGKILL); - - // Turn off the alarm and restore the signal handler - alarm(0); - sigaction(SIGALRM, &Old, 0); - - // Wait for child to die - if (wait(&status) != child) - MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); - else - MakeErrMsg(ErrMsg, "Child timed out", 0); - - return -2; // Timeout detected - } else if (errno != EINTR) { - MakeErrMsg(ErrMsg, "Error waiting for child process"); - return -1; + ProcessInfo WaitResult; + WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions); + 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, 0); + + // 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) { + if (SecondsToWait && !WaitUntilTerminates) { alarm(0); sigaction(SIGALRM, &Old, 0); } @@ -362,24 +389,19 @@ static int Wait(void *&Data, StringRef Program, unsigned secondsToWait, int result = 0; if (WIFEXITED(status)) { result = WEXITSTATUS(status); -#ifdef HAVE_POSIX_SPAWN - // The posix_spawn child process returns 127 on any kind of error. - // Following the POSIX convention for command-line tools (which posix_spawn - // itself apparently does not), check to see if the failure was due to some - // reason other than the file not existing, and return 126 in this case. - bool Exists; - if (result == 127 && !llvm::sys::fs::exists(Program, Exists) && Exists) - result = 126; -#endif + WaitResult.ReturnCode = result; + if (result == 127) { if (ErrMsg) *ErrMsg = llvm::sys::StrError(ENOENT); - return -1; + WaitResult.ReturnCode = -1; + return WaitResult; } if (result == 126) { if (ErrMsg) *ErrMsg = "Program could not be executed"; - return -1; + WaitResult.ReturnCode = -1; + return WaitResult; } } else if (WIFSIGNALED(status)) { if (ErrMsg) { @@ -391,18 +413,16 @@ static int Wait(void *&Data, StringRef Program, unsigned secondsToWait, } // Return a special value to indicate that the process received an unhandled // signal during execution as opposed to failing to execute. - return -2; + WaitResult.ReturnCode = -2; } - return result; #else if (ErrMsg) *ErrMsg = "Program::Wait is not implemented on this platform yet!"; - return -1; + WaitResult.ReturnCode = -2; #endif + return WaitResult; } -namespace llvm { - error_code sys::ChangeStdinToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. return make_error_code(errc::success); @@ -438,5 +458,4 @@ bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { } return true; } - } diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc index 800a6a7..13ae862 100644 --- a/lib/Support/Unix/Signals.inc +++ b/lib/Support/Unix/Signals.inc @@ -333,7 +333,7 @@ static void PrintStackTraceSignalHandler(void *) { void llvm::sys::PrintStackTraceOnErrorSignal() { AddSignalHandler(PrintStackTraceSignalHandler, 0); -#if defined(__APPLE__) && !defined(ANDROID) +#if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) // Environment variable to disable any kind of crash dialog. if (getenv("LLVM_DISABLE_CRASH_REPORT")) { mach_port_t self = mach_task_self(); @@ -359,7 +359,7 @@ void llvm::sys::PrintStackTraceOnErrorSignal() { // the same linkage unit by just defining our own versions of the assert handler // and abort. -#if defined(__APPLE__) && !defined(ANDROID) +#if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) #include <signal.h> #include <pthread.h> diff --git a/lib/Support/Unix/ThreadLocal.inc b/lib/Support/Unix/ThreadLocal.inc index 2b4c901..f14d0fa 100644 --- a/lib/Support/Unix/ThreadLocal.inc +++ b/lib/Support/Unix/ThreadLocal.inc @@ -18,7 +18,7 @@ namespace llvm { using namespace sys; -ThreadLocalImpl::ThreadLocalImpl() { } +ThreadLocalImpl::ThreadLocalImpl() : data() { } ThreadLocalImpl::~ThreadLocalImpl() { } void ThreadLocalImpl::setInstance(const void* d) { data = const_cast<void*>(d);} const void* ThreadLocalImpl::getInstance() { return data; } diff --git a/lib/Support/Unix/Unix.h b/lib/Support/Unix/Unix.h index dd11c04..ba688e3 100644 --- a/lib/Support/Unix/Unix.h +++ b/lib/Support/Unix/Unix.h @@ -47,6 +47,10 @@ # include <sys/wait.h> #endif +#ifdef HAVE_DLFCN_H +# include <dlfcn.h> +#endif + #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif |