diff options
Diffstat (limited to 'lib/System')
-rw-r--r-- | lib/System/CMakeLists.txt | 25 | ||||
-rw-r--r-- | lib/System/Disassembler.cpp | 2 | ||||
-rw-r--r-- | lib/System/DynamicLibrary.cpp | 79 | ||||
-rw-r--r-- | lib/System/Errno.cpp | 5 | ||||
-rw-r--r-- | lib/System/Makefile | 6 | ||||
-rw-r--r-- | lib/System/Memory.cpp | 19 | ||||
-rw-r--r-- | lib/System/Mutex.cpp | 9 | ||||
-rw-r--r-- | lib/System/Path.cpp | 22 | ||||
-rw-r--r-- | lib/System/Program.cpp | 27 | ||||
-rw-r--r-- | lib/System/RWMutex.cpp | 12 | ||||
-rw-r--r-- | lib/System/Threading.cpp | 1 | ||||
-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 | ||||
-rw-r--r-- | lib/System/Win32/DynamicLibrary.inc | 44 | ||||
-rw-r--r-- | lib/System/Win32/Memory.inc | 7 | ||||
-rw-r--r-- | lib/System/Win32/Path.inc | 30 | ||||
-rw-r--r-- | lib/System/Win32/Process.inc | 10 | ||||
-rw-r--r-- | lib/System/Win32/Program.inc | 130 | ||||
-rw-r--r-- | lib/System/Win32/Signals.inc | 53 | ||||
-rw-r--r-- | lib/System/Win32/TimeValue.inc | 2 |
26 files changed, 515 insertions, 272 deletions
diff --git a/lib/System/CMakeLists.txt b/lib/System/CMakeLists.txt index bf7a0c6..2945e33 100644 --- a/lib/System/CMakeLists.txt +++ b/lib/System/CMakeLists.txt @@ -13,9 +13,32 @@ add_llvm_library(LLVMSystem Program.cpp RWMutex.cpp Signals.cpp + ThreadLocal.cpp Threading.cpp TimeValue.cpp - ThreadLocal.cpp + Unix/Alarm.inc + Unix/Host.inc + Unix/Memory.inc + Unix/Mutex.inc + Unix/Path.inc + Unix/Process.inc + Unix/Program.inc + Unix/RWMutex.inc + Unix/Signals.inc + Unix/ThreadLocal.inc + Unix/TimeValue.inc + Win32/Alarm.inc + Win32/DynamicLibrary.inc + Win32/Host.inc + Win32/Memory.inc + Win32/Mutex.inc + Win32/Path.inc + Win32/Process.inc + Win32/Program.inc + Win32/RWMutex.inc + Win32/Signals.inc + Win32/ThreadLocal.inc + Win32/TimeValue.inc ) if( BUILD_SHARED_LIBS AND NOT WIN32 ) diff --git a/lib/System/Disassembler.cpp b/lib/System/Disassembler.cpp index 378fe26..bad427a 100644 --- a/lib/System/Disassembler.cpp +++ b/lib/System/Disassembler.cpp @@ -26,7 +26,7 @@ using namespace llvm; -bool llvm::sys::hasDisassembler(void) +bool llvm::sys::hasDisassembler() { #if defined (__i386__) || defined (__amd64__) || defined (__x86_64__) // We have option to enable udis86 library. diff --git a/lib/System/DynamicLibrary.cpp b/lib/System/DynamicLibrary.cpp index ef5c9e6..6efab94 100644 --- a/lib/System/DynamicLibrary.cpp +++ b/lib/System/DynamicLibrary.cpp @@ -9,42 +9,43 @@ // // This header file implements the operating system DynamicLibrary concept. // +// FIXME: This file leaks the ExplicitSymbols and OpenedHandles vector, and is +// not thread safe! +// //===----------------------------------------------------------------------===// #include "llvm/System/DynamicLibrary.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/System/RWMutex.h" #include "llvm/Config/config.h" #include <cstdio> #include <cstring> #include <map> +#include <vector> // Collection of symbol name/value pairs to be searched prior to any libraries. -static std::map<std::string, void*> symbols; -static llvm::sys::SmartRWMutex<true> SymbolsLock; +static std::map<std::string, void*> *ExplicitSymbols = 0; +static struct ExplicitSymbolsDeleter { + ~ExplicitSymbolsDeleter() { + if (ExplicitSymbols) + delete ExplicitSymbols; + } +} Dummy; void llvm::sys::DynamicLibrary::AddSymbol(const char* symbolName, void *symbolValue) { - llvm::sys::SmartScopedWriter<true> Writer(&SymbolsLock); - symbols[symbolName] = symbolValue; + if (ExplicitSymbols == 0) + ExplicitSymbols = new std::map<std::string, void*>(); + (*ExplicitSymbols)[symbolName] = symbolValue; } -// It is not possible to use ltdl.c on VC++ builds as the terms of its LGPL -// license and special exception would cause all of LLVM to be placed under -// the LGPL. This is because the exception applies only when libtool is -// used, and obviously libtool is not used with Visual Studio. An entirely -// separate implementation is provided in win32/DynamicLibrary.cpp. - #ifdef LLVM_ON_WIN32 #include "Win32/DynamicLibrary.inc" #else -//#include "ltdl.h" #include <dlfcn.h> -#include <cassert> using namespace llvm; using namespace llvm::sys; @@ -53,56 +54,44 @@ using namespace llvm::sys; //=== independent code. //===----------------------------------------------------------------------===// -//static std::vector<lt_dlhandle> OpenedHandles; -static std::vector<void *> OpenedHandles; - -DynamicLibrary::DynamicLibrary() {} +static std::vector<void *> *OpenedHandles = 0; -DynamicLibrary::~DynamicLibrary() { - SmartScopedWriter<true> Writer(&SymbolsLock); - while(!OpenedHandles.empty()) { - void *H = OpenedHandles.back(); OpenedHandles.pop_back(); - dlclose(H); - } -} bool DynamicLibrary::LoadLibraryPermanently(const char *Filename, std::string *ErrMsg) { - SmartScopedWriter<true> Writer(&SymbolsLock); void *H = dlopen(Filename, RTLD_LAZY|RTLD_GLOBAL); if (H == 0) { - if (ErrMsg) - *ErrMsg = dlerror(); + if (ErrMsg) *ErrMsg = dlerror(); return true; } - OpenedHandles.push_back(H); + if (OpenedHandles == 0) + OpenedHandles = new std::vector<void *>(); + OpenedHandles->push_back(H); return false; } void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { - // check_ltdl_initialization(); - // First check symbols added via AddSymbol(). - SymbolsLock.reader_acquire(); - std::map<std::string, void *>::iterator I = symbols.find(symbolName); - std::map<std::string, void *>::iterator E = symbols.end(); - SymbolsLock.reader_release(); + if (ExplicitSymbols) { + std::map<std::string, void *>::iterator I = + ExplicitSymbols->find(symbolName); + std::map<std::string, void *>::iterator E = ExplicitSymbols->end(); - if (I != E) - return I->second; + if (I != E) + return I->second; + } - SymbolsLock.writer_acquire(); // Now search the libraries. - for (std::vector<void *>::iterator I = OpenedHandles.begin(), - E = OpenedHandles.end(); I != E; ++I) { - //lt_ptr ptr = lt_dlsym(*I, symbolName); - void *ptr = dlsym(*I, symbolName); - if (ptr) { - SymbolsLock.writer_release(); - return ptr; + if (OpenedHandles) { + for (std::vector<void *>::iterator I = OpenedHandles->begin(), + E = OpenedHandles->end(); I != E; ++I) { + //lt_ptr ptr = lt_dlsym(*I, symbolName); + void *ptr = dlsym(*I, symbolName); + if (ptr) { + return ptr; + } } } - SymbolsLock.writer_release(); #define EXPLICIT_SYMBOL(SYM) \ extern void *SYM; if (!strcmp(symbolName, #SYM)) return &SYM diff --git a/lib/System/Errno.cpp b/lib/System/Errno.cpp index d046aba..68f66f6 100644 --- a/lib/System/Errno.cpp +++ b/lib/System/Errno.cpp @@ -17,6 +17,10 @@ #if HAVE_STRING_H #include <string.h> +#if HAVE_ERRNO_H +#include <errno.h> +#endif + //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only TRULY operating system //=== independent code. @@ -26,7 +30,6 @@ namespace llvm { namespace sys { #if HAVE_ERRNO_H -#include <errno.h> std::string StrError() { return StrError(errno); } diff --git a/lib/System/Makefile b/lib/System/Makefile index 49704c3..d4fd60e 100644 --- a/lib/System/Makefile +++ b/lib/System/Makefile @@ -11,6 +11,12 @@ LEVEL = ../.. LIBRARYNAME = LLVMSystem BUILD_ARCHIVE = 1 +include $(LEVEL)/Makefile.config + +ifeq ($(HOST_OS),MingW) + REQUIRES_EH := 1 +endif + EXTRA_DIST = Unix Win32 README.txt include $(LEVEL)/Makefile.common diff --git a/lib/System/Memory.cpp b/lib/System/Memory.cpp index 375c73c..e2d838d 100644 --- a/lib/System/Memory.cpp +++ b/lib/System/Memory.cpp @@ -37,13 +37,16 @@ void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr, // icache invalidation for PPC and ARM. #if defined(__APPLE__) -#if (defined(__POWERPC__) || defined (__ppc__) || \ + +# if (defined(__POWERPC__) || defined (__ppc__) || \ defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) sys_icache_invalidate(Addr, Len); -#endif +# endif + #else -#if (defined(__POWERPC__) || defined (__ppc__) || \ - defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) const size_t LineSize = 32; const intptr_t Mask = ~(LineSize - 1); @@ -57,6 +60,12 @@ void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr, for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) asm volatile("icbi 0, %0" : : "r"(Line)); asm volatile("isync"); -#endif +# elif defined(__arm__) && defined(__GNUC__) + // FIXME: Can we safely always call this for __GNUC__ everywhere? + char *Start = (char*) Addr; + char *End = Start + Len; + __clear_cache(Start, End); +# endif + #endif // end apple } diff --git a/lib/System/Mutex.cpp b/lib/System/Mutex.cpp index a5e9920..8ccd6e5 100644 --- a/lib/System/Mutex.cpp +++ b/lib/System/Mutex.cpp @@ -115,8 +115,7 @@ MutexImpl::acquire() int errorcode = pthread_mutex_lock(mutex); return errorcode == 0; - } - return false; + } else return false; } bool @@ -129,8 +128,7 @@ MutexImpl::release() int errorcode = pthread_mutex_unlock(mutex); return errorcode == 0; - } - return false; + } else return false; } bool @@ -143,8 +141,7 @@ MutexImpl::tryacquire() int errorcode = pthread_mutex_trylock(mutex); return errorcode == 0; - } - return false; + } else return false; } } diff --git a/lib/System/Path.cpp b/lib/System/Path.cpp index 72bd7ad..df33574 100644 --- a/lib/System/Path.cpp +++ b/lib/System/Path.cpp @@ -13,6 +13,7 @@ #include "llvm/System/Path.h" #include "llvm/Config/config.h" +#include "llvm/Support/ErrorHandling.h" #include <cassert> #include <cstring> #include <ostream> @@ -28,19 +29,10 @@ bool Path::operator==(const Path &that) const { return path == that.path; } -bool Path::operator!=(const Path &that) const { - return path != that.path; -} - bool Path::operator<(const Path& that) const { return path < that.path; } -std::ostream& llvm::operator<<(std::ostream &strm, const sys::Path &aPath) { - strm << aPath.toString(); - return strm; -} - Path Path::GetLLVMConfigDir() { Path result; @@ -207,18 +199,6 @@ bool Path::hasMagicNumber(const std::string &Magic) const { return false; } -void Path::makeAbsolute() { - if (isAbsolute()) - return; - - Path CWD = Path::GetCurrentDirectory(); - assert(CWD.isAbsolute() && "GetCurrentDirectory returned relative path!"); - - CWD.appendComponent(path); - - path = CWD.toString(); -} - static void getPathList(const char*path, std::vector<Path>& Paths) { const char* at = path; const char* delim = strchr(at, PathSeparator); diff --git a/lib/System/Program.cpp b/lib/System/Program.cpp index eb289d8..a3049d4 100644 --- a/lib/System/Program.cpp +++ b/lib/System/Program.cpp @@ -22,6 +22,33 @@ using namespace sys; //=== independent code. //===----------------------------------------------------------------------===// +int +Program::ExecuteAndWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned secondsToWait, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) + return prg.Wait(secondsToWait, ErrMsg); + else + return -1; +} + +void +Program::ExecuteNoWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg); +} + + } // Include the platform-specific parts of this class. diff --git a/lib/System/RWMutex.cpp b/lib/System/RWMutex.cpp index 15d98cb..5faf220 100644 --- a/lib/System/RWMutex.cpp +++ b/lib/System/RWMutex.cpp @@ -117,8 +117,7 @@ RWMutexImpl::reader_acquire() int errorcode = pthread_rwlock_rdlock(rwlock); return errorcode == 0; - } - return false; + } else return false; } bool @@ -131,8 +130,7 @@ RWMutexImpl::reader_release() int errorcode = pthread_rwlock_unlock(rwlock); return errorcode == 0; - } - return false; + } else return false; } bool @@ -145,8 +143,7 @@ RWMutexImpl::writer_acquire() int errorcode = pthread_rwlock_wrlock(rwlock); return errorcode == 0; - } - return false; + } else return false; } bool @@ -159,8 +156,7 @@ RWMutexImpl::writer_release() int errorcode = pthread_rwlock_unlock(rwlock); return errorcode == 0; - } - return false; + } else return false; } } diff --git a/lib/System/Threading.cpp b/lib/System/Threading.cpp index a2d7f82..466c468 100644 --- a/lib/System/Threading.cpp +++ b/lib/System/Threading.cpp @@ -14,6 +14,7 @@ #include "llvm/System/Threading.h" #include "llvm/System/Atomic.h" #include "llvm/System/Mutex.h" +#include "llvm/Config/config.h" #include <cassert> using namespace llvm; 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()); diff --git a/lib/System/Win32/DynamicLibrary.inc b/lib/System/Win32/DynamicLibrary.inc index aa04268..10e64aa 100644 --- a/lib/System/Win32/DynamicLibrary.inc +++ b/lib/System/Win32/DynamicLibrary.inc @@ -67,7 +67,6 @@ extern "C" { PVOID UserContext) #endif { - llvm::sys::SmartScopedWriter<true> Writer(&SymbolsLock); // Ignore VC++ runtimes prior to 7.1. Somehow some of them get loaded // into the process. if (stricmp(ModuleName, "msvci70") != 0 && @@ -89,36 +88,9 @@ extern "C" { } } -DynamicLibrary::DynamicLibrary() : handle(0) { - SmartScopedWriter<true> Writer(&SymbolsLock); - handle = GetModuleHandle(NULL); - OpenedHandles.push_back((HMODULE)handle); -} - -DynamicLibrary::~DynamicLibrary() { - llvm::sys::SmartScopedWriter<true> Writer(&SymbolsLock); - if (handle == 0) - return; - - // GetModuleHandle() does not increment the ref count, so we must not free - // the handle to the executable. - if (handle != GetModuleHandle(NULL)) - FreeLibrary((HMODULE)handle); - handle = 0; - - for (std::vector<HMODULE>::iterator I = OpenedHandles.begin(), - E = OpenedHandles.end(); I != E; ++I) { - if (*I == handle) { - // Note: don't use the swap/pop_back trick here. Order is important. - OpenedHandles.erase(I); - } - } -} - bool DynamicLibrary::LoadLibraryPermanently(const char *filename, std::string *ErrMsg) { if (filename) { - llvm::sys::SmartScopedWriter<true> Writer(&SymbolsLock); HMODULE a_handle = LoadLibrary(filename); if (a_handle == 0) @@ -170,24 +142,22 @@ bool DynamicLibrary::LoadLibraryPermanently(const char *filename, void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { // First check symbols added via AddSymbol(). - SymbolsLock.reader_acquire(); - std::map<std::string, void *>::iterator I = symbols.find(symbolName); - std::map<std::string, void *>::iterator E = symbols.end(); - SymbolsLock.reader_release(); - if (I != E) - return I->second; + if (ExplicitSymbols) { + std::map<std::string, void *>::iterator I = + ExplicitSymbols->find(symbolName); + std::map<std::string, void *>::iterator E = ExplicitSymbols->end(); + if (I != E) + return I->second; + } // Now search the libraries. - SymbolsLock.writer_acquire(); for (std::vector<HMODULE>::iterator I = OpenedHandles.begin(), E = OpenedHandles.end(); I != E; ++I) { FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName); if (ptr) { - SymbolsLock.writer_release(); return (void *) ptr; } } - SymbolsLock.writer_release(); #if defined(__MINGW32__) { diff --git a/lib/System/Win32/Memory.inc b/lib/System/Win32/Memory.inc index 5e5cf7a..7611ecd 100644 --- a/lib/System/Win32/Memory.inc +++ b/lib/System/Win32/Memory.inc @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "Win32.h" +#include "llvm/Support/DataTypes.h" #include "llvm/System/Process.h" namespace llvm { @@ -23,13 +24,13 @@ using namespace sys; //=== and must not be UNIX code //===----------------------------------------------------------------------===// -MemoryBlock Memory::AllocateRWX(unsigned NumBytes, +MemoryBlock Memory::AllocateRWX(size_t NumBytes, const MemoryBlock *NearBlock, std::string *ErrMsg) { if (NumBytes == 0) return MemoryBlock(); - static const long pageSize = Process::GetPageSize(); - unsigned NumPages = (NumBytes+pageSize-1)/pageSize; + static const size_t pageSize = Process::GetPageSize(); + size_t NumPages = (NumBytes+pageSize-1)/pageSize; //FIXME: support NearBlock if ever needed on Win64. diff --git a/lib/System/Win32/Path.inc b/lib/System/Win32/Path.inc index 683c94b..46b965f 100644 --- a/lib/System/Win32/Path.inc +++ b/lib/System/Win32/Path.inc @@ -125,9 +125,30 @@ Path::isValid() const { return true; } +void Path::makeAbsolute() { + TCHAR FullPath[MAX_PATH + 1] = {0}; + LPTSTR FilePart = NULL; + + DWORD RetLength = ::GetFullPathNameA(path.c_str(), + sizeof(FullPath)/sizeof(FullPath[0]), + FullPath, &FilePart); + + if (0 == RetLength) { + // FIXME: Report the error GetLastError() + assert(0 && "Unable to make absolute path!"); + } else if (RetLength > MAX_PATH) { + // FIXME: Report too small buffer (needed RetLength bytes). + assert(0 && "Unable to make absolute path!"); + } else { + path = FullPath; + } +} + bool Path::isAbsolute(const char *NameStart, unsigned NameLen) { assert(NameStart); + // FIXME: This does not handle correctly an absolute path starting from + // a drive letter or in UNC format. switch (NameLen) { case 0: return false; @@ -135,12 +156,15 @@ Path::isAbsolute(const char *NameStart, unsigned NameLen) { case 2: return NameStart[0] == '/'; default: - return NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/'); + return (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) || + (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\')); } } bool Path::isAbsolute() const { + // FIXME: This does not handle correctly an absolute path starting from + // a drive letter or in UNC format. switch (path.length()) { case 0: return false; @@ -784,8 +808,8 @@ CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) { // Can't use CopyFile macro defined in Windows.h because it would mess up the // above line. We use the expansion it would have in a non-UNICODE build. if (!::CopyFileA(Src.c_str(), Dest.c_str(), false)) - return MakeErrMsg(ErrMsg, "Can't copy '" + Src.toString() + - "' to '" + Dest.toString() + "': "); + return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() + + "' to '" + Dest.str() + "': "); return false; } diff --git a/lib/System/Win32/Process.inc b/lib/System/Win32/Process.inc index cfbe33c..feb0806 100644 --- a/lib/System/Win32/Process.inc +++ b/lib/System/Win32/Process.inc @@ -120,15 +120,19 @@ void Process::PreventCoreFiles() { } bool Process::StandardInIsUserInput() { - return GetFileType((HANDLE)_get_osfhandle(0)) == FILE_TYPE_CHAR; + return FileDescriptorIsDisplayed(0); } bool Process::StandardOutIsDisplayed() { - return GetFileType((HANDLE)_get_osfhandle(1)) == FILE_TYPE_CHAR; + return FileDescriptorIsDisplayed(1); } bool Process::StandardErrIsDisplayed() { - return GetFileType((HANDLE)_get_osfhandle(2)) == FILE_TYPE_CHAR; + return FileDescriptorIsDisplayed(2); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { + return GetFileType((HANDLE)_get_osfhandle(fd)) == FILE_TYPE_CHAR; } unsigned Process::StandardOutColumns() { diff --git a/lib/System/Win32/Program.inc b/lib/System/Win32/Program.inc index 49086b8..a69826f 100644 --- a/lib/System/Win32/Program.inc +++ b/lib/System/Win32/Program.inc @@ -22,9 +22,32 @@ //=== and must not be UNIX code //===----------------------------------------------------------------------===// +namespace { + struct Win32ProcessInfo { + HANDLE hProcess; + DWORD dwProcessId; + }; +} + namespace llvm { using namespace sys; +Program::Program() : Data_(0) {} + +Program::~Program() { + if (Data_) { + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + CloseHandle(wpi->hProcess); + delete wpi; + Data_ = 0; + } +} + +unsigned Program::GetPid() const { + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + return wpi->dwProcessId; +} + // This function just uses the PATH environment variable to find the program. Path Program::FindProgramByName(const std::string& progName) { @@ -82,7 +105,7 @@ static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { if (path->isEmpty()) fname = "NUL"; else - fname = path->toString().c_str(); + fname = path->c_str(); SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); @@ -109,29 +132,41 @@ static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { DWORD cbJobObjectInfoLength); #endif -int -Program::ExecuteAndWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned secondsToWait, - unsigned memoryLimit, - std::string* ErrMsg) { +/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling +/// CreateProcess. +static bool ArgNeedsQuotes(const char *Str) { + return Str[0] == '\0' || strchr(Str, ' ') != 0; +} + +bool +Program::Execute(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { + if (Data_) { + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + CloseHandle(wpi->hProcess); + delete wpi; + Data_ = 0; + } + if (!path.canExecute()) { if (ErrMsg) *ErrMsg = "program not executable"; - return -1; + return false; } // Windows wants a command line, not an array of args, to pass to the new // process. We have to concatenate them all, while quoting the args that - // have embedded spaces. + // have embedded spaces (or are empty). // First, determine the length of the command line. unsigned len = 0; for (unsigned i = 0; args[i]; i++) { len += strlen(args[i]) + 1; - if (strchr(args[i], ' ')) + if (ArgNeedsQuotes(args[i])) len += 2; } @@ -142,7 +177,7 @@ Program::ExecuteAndWait(const Path& path, for (unsigned i = 0; args[i]; i++) { const char *arg = args[i]; size_t len = strlen(arg); - bool needsQuoting = strchr(arg, ' ') != 0; + bool needsQuoting = ArgNeedsQuotes(arg); if (needsQuoting) *p++ = '"'; memcpy(p, arg, len); @@ -195,13 +230,13 @@ Program::ExecuteAndWait(const Path& path, si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); if (si.hStdInput == INVALID_HANDLE_VALUE) { MakeErrMsg(ErrMsg, "can't redirect stdin"); - return -1; + return false; } si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); if (si.hStdOutput == INVALID_HANDLE_VALUE) { CloseHandle(si.hStdInput); MakeErrMsg(ErrMsg, "can't redirect stdout"); - return -1; + return false; } if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { // If stdout and stderr should go to the same place, redirect stderr @@ -216,7 +251,7 @@ Program::ExecuteAndWait(const Path& path, CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); MakeErrMsg(ErrMsg, "can't redirect stderr"); - return -1; + return false; } } } @@ -237,16 +272,18 @@ Program::ExecuteAndWait(const Path& path, CloseHandle(si.hStdError); // Now return an error if the process didn't get created. - if (!rc) - { + if (!rc) { SetLastError(err); MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - path.toString() + "'"); - return -1; + path.str() + "'"); + return false; } + Win32ProcessInfo* wpi = new Win32ProcessInfo; + wpi->hProcess = pi.hProcess; + wpi->dwProcessId = pi.dwProcessId; + Data_ = wpi; // Make sure these get closed no matter what. - AutoHandle hProcess(pi.hProcess); AutoHandle hThread(pi.hThread); // Assign the process to a job if a memory limit is defined. @@ -270,39 +307,68 @@ Program::ExecuteAndWait(const Path& path, MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); TerminateProcess(pi.hProcess, 1); WaitForSingleObject(pi.hProcess, INFINITE); - return -1; + return false; } } - // Wait for it to terminate. + return true; +} + +int +Program::Wait(unsigned secondsToWait, + std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + HANDLE hProcess = wpi->hProcess; + + // Wait for the process to terminate. DWORD millisecondsToWait = INFINITE; if (secondsToWait > 0) millisecondsToWait = secondsToWait * 1000; - if (WaitForSingleObject(pi.hProcess, millisecondsToWait) == WAIT_TIMEOUT) { - if (!TerminateProcess(pi.hProcess, 1)) { - MakeErrMsg(ErrMsg, std::string("Failed to terminate timed-out program '") - + path.toString() + "'"); + if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { + if (!TerminateProcess(hProcess, 1)) { + MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); return -1; } - WaitForSingleObject(pi.hProcess, INFINITE); + WaitForSingleObject(hProcess, INFINITE); } // Get its exit status. DWORD status; - rc = GetExitCodeProcess(pi.hProcess, &status); - err = GetLastError(); + BOOL rc = GetExitCodeProcess(hProcess, &status); + DWORD err = GetLastError(); if (!rc) { SetLastError(err); - MakeErrMsg(ErrMsg, std::string("Failed getting status for program '") + - path.toString() + "'"); + MakeErrMsg(ErrMsg, "Failed getting status for program."); return -1; } return status; } +bool +Program::Kill(std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return true; + } + + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + HANDLE hProcess = wpi->hProcess; + if (TerminateProcess(hProcess, 1) == 0) { + MakeErrMsg(ErrMsg, "The process couldn't be killed!"); + return true; + } + + return false; +} + bool Program::ChangeStdinToBinary(){ int result = _setmode( _fileno(stdin), _O_BINARY ); return result == -1; diff --git a/lib/System/Win32/Signals.inc b/lib/System/Win32/Signals.inc index 3a8f77e..dba2218 100644 --- a/lib/System/Win32/Signals.inc +++ b/lib/System/Win32/Signals.inc @@ -43,6 +43,9 @@ static std::vector<llvm::sys::Path> *FilesToRemove = NULL; static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0; static bool RegisteredUnhandledExceptionFilter = false; static bool CleanupExecuted = false; +#ifdef _MSC_VER +static bool ExitOnUnhandledExceptions = false; +#endif static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; // Windows creates a new thread to execute the console handler when an event @@ -57,8 +60,38 @@ namespace llvm { //=== and must not be UNIX code //===----------------------------------------------------------------------===// +#ifdef _MSC_VER +/// CRTReportHook - Function called on a CRT debugging event. +static int CRTReportHook(int ReportType, char *Message, int *Return) { + // Don't cause a DebugBreak() on return. + if (Return) + *Return = 0; + + switch (ReportType) { + default: + case _CRT_ASSERT: + fprintf(stderr, "CRT assert: %s\n", Message); + // FIXME: Is there a way to just crash? Perhaps throw to the unhandled + // exception code? Perhaps SetErrorMode() handles this. + _exit(3); + break; + case _CRT_ERROR: + fprintf(stderr, "CRT error: %s\n", Message); + // FIXME: Is there a way to just crash? Perhaps throw to the unhandled + // exception code? Perhaps SetErrorMode() handles this. + _exit(3); + break; + case _CRT_WARN: + fprintf(stderr, "CRT warn: %s\n", Message); + break; + } + + // Don't call _CrtDbgReport. + return TRUE; +} +#endif -static void RegisterHandler() { +static void RegisterHandler() { if (RegisteredUnhandledExceptionFilter) { EnterCriticalSection(&CriticalSection); return; @@ -76,6 +109,14 @@ static void RegisterHandler() { OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); + // Environment variable to disable any kind of crash dialog. +#ifdef _MSC_VER + if (getenv("LLVM_DISABLE_CRT_DEBUG")) { + _CrtSetReportHook(CRTReportHook); + ExitOnUnhandledExceptions = true; + } +#endif + // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or // else multi-threading problems will ensue. } @@ -136,10 +177,7 @@ static void Cleanup() { if (FilesToRemove != NULL) while (!FilesToRemove->empty()) { - try { - FilesToRemove->back().eraseFromDisk(); - } catch (...) { - } + FilesToRemove->back().eraseFromDisk(); FilesToRemove->pop_back(); } @@ -238,6 +276,11 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { assert(0 && "Crashed in LLVMUnhandledExceptionFilter"); } +#ifdef _MSC_VER + if (ExitOnUnhandledExceptions) + _exit(-3); +#endif + // Allow dialog box to pop up allowing choice to start debugger. if (OldFilter) return (*OldFilter)(ep); diff --git a/lib/System/Win32/TimeValue.inc b/lib/System/Win32/TimeValue.inc index 0ca87d4..e37f111 100644 --- a/lib/System/Win32/TimeValue.inc +++ b/lib/System/Win32/TimeValue.inc @@ -30,7 +30,7 @@ TimeValue TimeValue::now() { return t; } -std::string TimeValue::toString() const { +std::string TimeValue::str() const { #ifdef __MINGW32__ // This ban may be lifted by either: // (i) a future MinGW version other than 1.0 inherents the __time64_t type, or |