diff options
Diffstat (limited to 'lib/System/Win32')
-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 |
7 files changed, 192 insertions, 84 deletions
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 |