diff options
Diffstat (limited to 'lib/System/Unix')
-rw-r--r-- | lib/System/Unix/Alarm.inc | 2 | ||||
-rw-r--r-- | lib/System/Unix/Host.inc | 46 | ||||
-rw-r--r-- | lib/System/Unix/Memory.inc | 7 | ||||
-rw-r--r-- | lib/System/Unix/Path.inc | 73 | ||||
-rw-r--r-- | lib/System/Unix/Process.inc | 29 | ||||
-rw-r--r-- | lib/System/Unix/Program.inc | 131 | ||||
-rw-r--r-- | lib/System/Unix/Signals.inc | 14 | ||||
-rw-r--r-- | lib/System/Unix/TimeValue.inc | 2 |
8 files changed, 204 insertions, 100 deletions
diff --git a/lib/System/Unix/Alarm.inc b/lib/System/Unix/Alarm.inc index 28ff1b8..fb42b6c 100644 --- a/lib/System/Unix/Alarm.inc +++ b/lib/System/Unix/Alarm.inc @@ -67,6 +67,6 @@ int sys::AlarmStatus() { return 0; } -void Sleep(unsigned n) { +void sys::Sleep(unsigned n) { ::sleep(n); } diff --git a/lib/System/Unix/Host.inc b/lib/System/Unix/Host.inc index fb319fd..c76d6a4 100644 --- a/lib/System/Unix/Host.inc +++ b/lib/System/Unix/Host.inc @@ -16,7 +16,8 @@ //=== is guaranteed to work on *all* UNIX variants. //===----------------------------------------------------------------------===// -#include <llvm/Config/config.h> +#include "llvm/Config/config.h" +#include "llvm/ADT/StringRef.h" #include "Unix.h" #include <sys/utsname.h> #include <string> @@ -33,10 +34,47 @@ static std::string getOSVersion() { } std::string sys::getHostTriple() { - // FIXME: Derive more directly instead of relying on the autoconf - // generated variable. + // FIXME: Derive directly instead of relying on the autoconf generated + // variable. - std::string Triple = LLVM_HOSTTRIPLE; + StringRef HostTripleString(LLVM_HOSTTRIPLE); + std::pair<StringRef, StringRef> ArchSplit = HostTripleString.split('-'); + + // Normalize the arch, since the host triple may not actually match the host. + std::string Arch = ArchSplit.first; + + // It would be nice to do this in terms of llvm::Triple, but that is in + // Support which is layered above us. +#if defined(__x86_64__) + Arch = "x86_64"; +#elif defined(__i386__) + Arch = "i386"; +#elif defined(__ppc64__) + Arch = "powerpc64"; +#elif defined(__ppc__) + Arch = "powerpc"; +#elif defined(__arm__) + + // FIXME: We need to pick the right ARM triple (which involves querying the + // chip). However, for now this is most important for LLVM arch selection, so + // we only need to make sure to distinguish ARM and Thumb. +# if defined(__thumb__) + Arch = "thumb"; +# else + Arch = "arm"; +# endif + +#else + + // FIXME: When enough auto-detection is in place, this should just + // #error. Then at least the arch selection is done, and we only need the OS + // etc selection to kill off the use of LLVM_HOSTTRIPLE. + +#endif + + std::string Triple(Arch); + Triple += '-'; + Triple += ArchSplit.second; // Force i<N>86 to i386. if (Triple[0] == 'i' && isdigit(Triple[1]) && diff --git a/lib/System/Unix/Memory.inc b/lib/System/Unix/Memory.inc index b7a7013..a80f56f 100644 --- a/lib/System/Unix/Memory.inc +++ b/lib/System/Unix/Memory.inc @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Unix.h" +#include "llvm/Support/DataTypes.h" #include "llvm/System/Process.h" #ifdef HAVE_SYS_MMAN_H @@ -28,12 +29,12 @@ /// is very OS specific. /// llvm::sys::MemoryBlock -llvm::sys::Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock, +llvm::sys::Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, std::string *ErrMsg) { if (NumBytes == 0) return MemoryBlock(); - unsigned pageSize = Process::GetPageSize(); - unsigned NumPages = (NumBytes+pageSize-1)/pageSize; + size_t pageSize = Process::GetPageSize(); + size_t NumPages = (NumBytes+pageSize-1)/pageSize; int fd = -1; #ifdef NEED_DEV_ZERO_FOR_MMAP diff --git a/lib/System/Unix/Path.inc b/lib/System/Unix/Path.inc index 1f73571..89285b4 100644 --- a/lib/System/Unix/Path.inc +++ b/lib/System/Unix/Path.inc @@ -16,7 +16,7 @@ //=== is guaranteed to work on *all* UNIX variants. //===----------------------------------------------------------------------===// -#include "llvm/Config/alloca.h" +#include "llvm/ADT/SmallVector.h" #include "Unix.h" #if HAVE_SYS_STAT_H #include <sys/stat.h> @@ -57,6 +57,10 @@ #include <dlfcn.h> #endif +#ifdef __APPLE__ +#include <mach-o/dyld.h> +#endif + // Put in a hack for Cygwin which falsely reports that the mkdtemp function // is available when it is not. #ifdef __CYGWIN__ @@ -92,15 +96,7 @@ Path::isValid() const { // Check some obvious things if (path.empty()) return false; - else if (path.length() >= MAXPATHLEN) - return false; - - // Check that the characters are ascii chars - size_t len = path.length(); - unsigned i = 0; - while (i < len && isascii(path[i])) - ++i; - return i >= len; + return path.length() < MAXPATHLEN; } bool @@ -117,6 +113,19 @@ Path::isAbsolute() const { return false; return path[0] == '/'; } + +void Path::makeAbsolute() { + if (isAbsolute()) + return; + + Path CWD = Path::GetCurrentDirectory(); + assert(CWD.isAbsolute() && "GetCurrentDirectory returned relative path!"); + + CWD.appendComponent(path); + + path = CWD.str(); +} + Path Path::GetRootDirectory() { Path result; @@ -331,7 +340,17 @@ getprogpath(char ret[PATH_MAX], const char *bin) /// GetMainExecutable - Return the path to the main executable, given the /// value of argv[0] from program startup. Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { -#if defined(__FreeBSD__) +#if defined(__APPLE__) + // On OS X the executable path is saved to the stack by dyld. Reading it + // from there is much faster than calling dladdr, especially for large + // binaries with symbols. + char exe_path[MAXPATHLEN]; + uint32_t size = sizeof(exe_path); + if (_NSGetExecutablePath(exe_path, &size) == 0) { + char link_path[MAXPATHLEN]; + return Path(std::string(realpath(exe_path, link_path))); + } +#elif defined(__FreeBSD__) char exe_path[PATH_MAX]; if (getprogpath(exe_path, argv0) != NULL) @@ -339,10 +358,8 @@ Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { #elif defined(__linux__) || defined(__CYGWIN__) char exe_path[MAXPATHLEN]; ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); - if (len > 0 && len < MAXPATHLEN - 1) { - exe_path[len] = '\0'; - return Path(std::string(exe_path)); - } + if (len >= 0) + return Path(std::string(exe_path, len)); #elif defined(HAVE_DLFCN_H) // Use dladdr to get executable path if available. Dl_info DLInfo; @@ -397,7 +414,9 @@ Path::getSuffix() const { bool Path::getMagicNumber(std::string& Magic, unsigned len) const { assert(len < 1024 && "Request for magic string too long"); - char* buf = (char*) alloca(1 + len); + SmallVector<char, 128> Buf; + Buf.resize(1 + len); + char* buf = Buf.data(); int fd = ::open(path.c_str(), O_RDONLY); if (fd < 0) return false; @@ -426,12 +445,12 @@ Path::isDirectory() const { bool Path::canRead() const { - return 0 == access(path.c_str(), F_OK | R_OK ); + return 0 == access(path.c_str(), R_OK); } bool Path::canWrite() const { - return 0 == access(path.c_str(), F_OK | W_OK ); + return 0 == access(path.c_str(), W_OK); } bool @@ -499,7 +518,7 @@ static bool AddPermissionBits(const Path &File, int bits) { // Get the file's current mode. struct stat buf; - if (0 != stat(File.toString().c_str(), &buf)) + if (0 != stat(File.c_str(), &buf)) return false; // Change the file to have whichever permissions bits from 'bits' // that the umask would not disable. @@ -631,7 +650,7 @@ Path::eraseSuffix() { static bool createDirectoryHelper(char* beg, char* end, bool create_parents) { - if (access(beg, F_OK | R_OK | W_OK) == 0) + if (access(beg, R_OK | W_OK) == 0) return false; if (create_parents) { @@ -756,7 +775,7 @@ bool Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { if (0 != ::rename(path.c_str(), newName.c_str())) return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" + - newName.toString() + "'"); + newName.str() + "'"); return false; } @@ -778,13 +797,13 @@ sys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){ int outFile = -1; inFile = ::open(Src.c_str(), O_RDONLY); if (inFile == -1) - return MakeErrMsg(ErrMsg, Src.toString() + + return MakeErrMsg(ErrMsg, Src.str() + ": can't open source file to copy"); outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666); if (outFile == -1) { ::close(inFile); - return MakeErrMsg(ErrMsg, Dest.toString() + + return MakeErrMsg(ErrMsg, Dest.str() + ": can't create destination file for copy"); } @@ -794,7 +813,7 @@ sys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){ if (errno != EINTR && errno != EAGAIN) { ::close(inFile); ::close(outFile); - return MakeErrMsg(ErrMsg, Src.toString()+": can't read source file"); + return MakeErrMsg(ErrMsg, Src.str()+": can't read source file"); } } else { char *BufPtr = Buffer; @@ -804,7 +823,7 @@ sys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){ if (errno != EINTR && errno != EAGAIN) { ::close(inFile); ::close(outFile); - return MakeErrMsg(ErrMsg, Dest.toString() + + return MakeErrMsg(ErrMsg, Dest.str() + ": can't write destination file"); } } else { @@ -826,7 +845,9 @@ Path::makeUnique(bool reuse_current, std::string* ErrMsg) { // Append an XXXXXX pattern to the end of the file for use with mkstemp, // mktemp or our own implementation. - char *FNBuffer = (char*) alloca(path.size()+8); + SmallVector<char, 128> Buf; + Buf.resize(path.size()+8); + char *FNBuffer = Buf.data(); path.copy(FNBuffer,path.size()); if (isDirectory()) strcpy(FNBuffer+path.size(), "/XXXXXX"); diff --git a/lib/System/Unix/Process.inc b/lib/System/Unix/Process.inc index 2da31c9..94e4c1b 100644 --- a/lib/System/Unix/Process.inc +++ b/lib/System/Unix/Process.inc @@ -46,11 +46,11 @@ Process::GetPageSize() // 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 - static const int page_size = 0x1000; + const int page_size = 0x1000; #elif defined(HAVE_GETPAGESIZE) - static const int page_size = ::getpagesize(); + const int page_size = ::getpagesize(); #elif defined(HAVE_SYSCONF) - static long page_size = ::sysconf(_SC_PAGE_SIZE); + long page_size = ::sysconf(_SC_PAGE_SIZE); #else #warning Cannot get the page size on this machine #endif @@ -91,7 +91,7 @@ Process::GetTotalMemoryUsage() malloc_statistics_t Stats; malloc_zone_statistics(malloc_default_zone(), &Stats); return Stats.size_allocated; // darwin -#elif defined(HAVE_GETRUSAGE) +#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__) struct rusage usage; ::getrusage(RUSAGE_SELF, &usage); return usage.ru_maxrss; @@ -179,27 +179,24 @@ void Process::PreventCoreFiles() { } bool Process::StandardInIsUserInput() { -#if HAVE_ISATTY - return isatty(0); -#endif - // If we don't have isatty, just return false. - return false; + return FileDescriptorIsDisplayed(STDIN_FILENO); } bool Process::StandardOutIsDisplayed() { -#if HAVE_ISATTY - return isatty(1); -#endif - // If we don't have isatty, just return false. - return false; + return FileDescriptorIsDisplayed(STDOUT_FILENO); } bool Process::StandardErrIsDisplayed() { + return FileDescriptorIsDisplayed(STDERR_FILENO); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { #if HAVE_ISATTY - return isatty(2); -#endif + return isatty(fd); +#else // If we don't have isatty, just return false. return false; +#endif } static unsigned getColumns(int FileID) { diff --git a/lib/System/Unix/Program.inc b/lib/System/Unix/Program.inc index cdc6fee..56dea25 100644 --- a/lib/System/Unix/Program.inc +++ b/lib/System/Unix/Program.inc @@ -1,10 +1,10 @@ //===- llvm/System/Unix/Program.cpp -----------------------------*- C++ -*-===// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. -// +// //===----------------------------------------------------------------------===// // // This file implements the Unix specific portion of the Program class. @@ -18,7 +18,6 @@ #include <llvm/Config/config.h> #include "Unix.h" -#include <iostream> #if HAVE_SYS_STAT_H #include <sys/stat.h> #endif @@ -35,6 +34,15 @@ namespace llvm { using namespace sys; +Program::Program() : Data_(0) {} + +Program::~Program() {} + +unsigned Program::GetPid() const { + uint64_t pid = reinterpret_cast<uint64_t>(Data_); + return static_cast<unsigned>(pid); +} + // This function just uses the PATH environment variable to find the program. Path Program::FindProgramByName(const std::string& progName) { @@ -45,16 +53,17 @@ Program::FindProgramByName(const std::string& progName) { Path temp; if (!temp.set(progName)) // invalid name return Path(); - // FIXME: have to check for absolute filename - we cannot assume anything - // about "." being in $PATH - if (temp.canExecute()) // already executable as is + // 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 its not executable - + // At this point, the file name 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 == 0) + if (PathStr == 0) return Path(); // Now we have a colon separated list of directories to search; try them. @@ -93,7 +102,7 @@ static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { // Redirect empty paths to /dev/null File = "/dev/null"; else - File = Path->toString(); + File = Path->str(); // Open the file int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); @@ -112,11 +121,6 @@ static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { return false; } -static bool Timeout = false; -static void TimeOutHandler(int Sig) { - Timeout = true; -} - static void SetMemoryLimits (unsigned size) { #if HAVE_SYS_RESOURCE_H @@ -142,49 +146,47 @@ static void SetMemoryLimits (unsigned size) #endif } -int -Program::ExecuteAndWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned secondsToWait, - unsigned memoryLimit, - std::string* ErrMsg) +bool +Program::Execute(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { if (!path.canExecute()) { if (ErrMsg) - *ErrMsg = path.toString() + " is not executable"; - return -1; + *ErrMsg = path.str() + " is not executable"; + return false; } -#ifdef HAVE_SYS_WAIT_H // Create a child process. int child = fork(); switch (child) { // An error occured: Return to the caller. case -1: MakeErrMsg(ErrMsg, "Couldn't fork"); - return -1; + return false; // Child process: Execute the program. case 0: { // Redirect file descriptors... if (redirects) { // Redirect stdin - if (RedirectIO(redirects[0], 0, ErrMsg)) { return -1; } + if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; } // Redirect stdout - if (RedirectIO(redirects[1], 1, ErrMsg)) { return -1; } - if (redirects[1] && redirects[2] && + if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; } + if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { // If stdout and stderr should go to the same place, redirect stderr // to the FD already open for stdout. if (-1 == dup2(1,2)) { MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); - return -1; + return false; } } else { // Just redirect stderr - if (RedirectIO(redirects[2], 2, ErrMsg)) { return -1; } + if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; } } } @@ -192,15 +194,19 @@ Program::ExecuteAndWait(const Path& path, if (memoryLimit!=0) { SetMemoryLimits(memoryLimit); } - + // Execute! if (envp != 0) - execve (path.c_str(), (char**)args, (char**)envp); + execve(path.c_str(), (char**)args, (char**)envp); else - execv (path.c_str(), (char**)args); - // If the execve() failed, we should exit and let the parent pick up - // our non-zero exit status. - exit (errno); + execv(path.c_str(), (char**)args); + // If the execve() failed, we should exit. Follow Unix protocol and + // return 127 if the executable was not found, and 126 otherwise. + // Use _exit rather than exit so that atexit functions and static + // object destructors cloned from the parent process aren't + // redundantly run, and so that any data buffered in stdio buffers + // cloned from the parent aren't redundantly written out. + _exit(errno == ENOENT ? 127 : 126); } // Parent process: Break out of the switch to do our processing. @@ -208,32 +214,41 @@ Program::ExecuteAndWait(const Path& path, break; } - // Make sure stderr and stdout have been flushed - std::cerr << std::flush; - std::cout << std::flush; - fsync(1); - fsync(2); + Data_ = reinterpret_cast<void*>(child); + + return true; +} +int +Program::Wait(unsigned secondsToWait, + std::string* ErrMsg) +{ +#ifdef HAVE_SYS_WAIT_H struct sigaction Act, Old; + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + // Install a timeout handler. if (secondsToWait) { - Timeout = false; - Act.sa_sigaction = 0; - Act.sa_handler = TimeOutHandler; + memset(&Act, 0, sizeof(Act)); + Act.sa_handler = SIG_IGN; sigemptyset(&Act.sa_mask); - Act.sa_flags = 0; sigaction(SIGALRM, &Act, &Old); alarm(secondsToWait); } // 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 (wait(&status) != 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); @@ -271,7 +286,25 @@ Program::ExecuteAndWait(const Path& path, #else return -99; #endif - + +} + +bool +Program::Kill(std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return true; + } + + uint64_t pid64 = reinterpret_cast<uint64_t>(Data_); + pid_t pid = static_cast<pid_t>(pid64); + + if (kill(pid, SIGKILL) != 0) { + MakeErrMsg(ErrMsg, "The process couldn't be killed!"); + return true; + } + + return false; } bool Program::ChangeStdinToBinary(){ diff --git a/lib/System/Unix/Signals.inc b/lib/System/Unix/Signals.inc index e385e0c..d39e1e9 100644 --- a/lib/System/Unix/Signals.inc +++ b/lib/System/Unix/Signals.inc @@ -14,6 +14,7 @@ #include "Unix.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/System/Mutex.h" #include <vector> #include <algorithm> #if HAVE_EXECINFO_H @@ -33,6 +34,8 @@ using namespace llvm; static RETSIGTYPE SignalHandler(int Sig); // defined below. +static SmartMutex<true> SignalsMutex; + /// InterruptFunction - The function to call if ctrl-c is pressed. static void (*InterruptFunction)() = 0; @@ -113,6 +116,7 @@ static RETSIGTYPE SignalHandler(int Sig) { sigfillset(&SigMask); sigprocmask(SIG_UNBLOCK, &SigMask, 0); + SignalsMutex.acquire(); if (FilesToRemove != 0) while (!FilesToRemove->empty()) { FilesToRemove->back().eraseFromDisk(true); @@ -122,14 +126,19 @@ static RETSIGTYPE SignalHandler(int Sig) { if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { if (InterruptFunction) { void (*IF)() = InterruptFunction; + SignalsMutex.release(); InterruptFunction = 0; IF(); // run the interrupt function. return; } + + SignalsMutex.release(); raise(Sig); // Execute the default handler. return; } + SignalsMutex.release(); + // Otherwise if it is a fault (like SEGV) run any handler. if (CallBacksToRun) for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) @@ -139,18 +148,23 @@ static RETSIGTYPE SignalHandler(int Sig) { void llvm::sys::SetInterruptFunction(void (*IF)()) { + SignalsMutex.acquire(); InterruptFunction = IF; + SignalsMutex.release(); RegisterHandlers(); } // RemoveFileOnSignal - The public API bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { + SignalsMutex.acquire(); if (FilesToRemove == 0) FilesToRemove = new std::vector<sys::Path>(); FilesToRemove->push_back(Filename); + SignalsMutex.release(); + RegisterHandlers(); return false; } diff --git a/lib/System/Unix/TimeValue.inc b/lib/System/Unix/TimeValue.inc index 8dd30b9..1ae8c71 100644 --- a/lib/System/Unix/TimeValue.inc +++ b/lib/System/Unix/TimeValue.inc @@ -21,7 +21,7 @@ namespace llvm { using namespace sys; -std::string TimeValue::toString() const { +std::string TimeValue::str() const { char buffer[32]; time_t ourTime = time_t(this->toEpochTime()); |