diff options
Diffstat (limited to 'contrib/llvm/lib/Support/Windows')
-rw-r--r-- | contrib/llvm/lib/Support/Windows/DynamicLibrary.inc | 220 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Host.inc | 14 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Mutex.inc | 11 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Path.inc | 306 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Process.inc | 1 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Program.inc | 1 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/RWMutex.inc | 13 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Signals.inc | 2 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/ThreadLocal.inc | 11 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/Threading.inc | 109 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Windows/WindowsSupport.h | 4 |
11 files changed, 528 insertions, 164 deletions
diff --git a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc index 0506894..083ea90 100644 --- a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc +++ b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc @@ -12,92 +12,142 @@ //===----------------------------------------------------------------------===// #include "WindowsSupport.h" +#include "llvm/Support/raw_ostream.h" -#ifdef __MINGW32__ - #include <imagehlp.h> -#else - #include <dbghelp.h> -#endif - -#ifdef _MSC_VER - #include <ntverp.h> -#endif - -namespace llvm { -using namespace sys; +#include <psapi.h> //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code. //===----------------------------------------------------------------------===// -typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); -static fpEnumerateLoadedModules fEnumerateLoadedModules; -static DenseSet<HMODULE> *OpenedHandles; -static bool loadDebugHelp(void) { - HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); - if (hLib) { - fEnumerateLoadedModules = (fpEnumerateLoadedModules) - ::GetProcAddress(hLib, "EnumerateLoadedModules64"); - } - return fEnumerateLoadedModules != 0; -} +DynamicLibrary::HandleSet::~HandleSet() { + for (void *Handle : llvm::reverse(Handles)) + FreeLibrary(HMODULE(Handle)); -static BOOL CALLBACK -ELM_Callback(PCSTR ModuleName, DWORD64 ModuleBase, - ULONG ModuleSize, PVOID UserContext) { - OpenedHandles->insert((HMODULE)ModuleBase); - return TRUE; + // 'Process' should not be released on Windows. + assert((!Process || Process==this) && "Bad Handle"); + // llvm_shutdown called, Return to default + DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; } -DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, - std::string *errMsg) { - SmartScopedLock<true> lock(*SymbolsMutex); +void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { + // Create the instance and return it to be the *Process* handle + // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL) + if (!File) + return &(*OpenedHandles); - if (!filename) { - // When no file is specified, enumerate all DLLs and EXEs in the process. - if (OpenedHandles == 0) - OpenedHandles = new DenseSet<HMODULE>(); - - if (!fEnumerateLoadedModules) { - if (!loadDebugHelp()) { - assert(false && "These APIs should always be available"); - return DynamicLibrary(); - } - } - - fEnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0); - // Dummy library that represents "search all handles". - // This is mostly to ensure that the return value still shows up as "valid". - return DynamicLibrary(&OpenedHandles); - } - - SmallVector<wchar_t, MAX_PATH> filenameUnicode; - if (std::error_code ec = windows::UTF8ToUTF16(filename, filenameUnicode)) { + SmallVector<wchar_t, MAX_PATH> FileUnicode; + if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) { SetLastError(ec.value()); - MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16"); - return DynamicLibrary(); + MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16"); + return &DynamicLibrary::Invalid; } - - HMODULE a_handle = LoadLibraryW(filenameUnicode.data()); - if (a_handle == 0) { - MakeErrMsg(errMsg, std::string(filename) + ": Can't open"); - return DynamicLibrary(); + HMODULE Handle = LoadLibraryW(FileUnicode.data()); + if (Handle == NULL) { + MakeErrMsg(Err, std::string(File) + ": Can't open"); + return &DynamicLibrary::Invalid; } - if (OpenedHandles == 0) - OpenedHandles = new DenseSet<HMODULE>(); + return reinterpret_cast<void*>(Handle); +} + +static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) { + if (!OpenedHandles.isConstructed()) + return nullptr; + DynamicLibrary::HandleSet &Inst = *OpenedHandles; + return Handle == &Inst ? &Inst : nullptr; +} + +void DynamicLibrary::HandleSet::DLClose(void *Handle) { + if (HandleSet* HS = IsOpenedHandlesInstance(Handle)) + HS->Process = nullptr; // Just drop the *Process* handle. + else + FreeLibrary((HMODULE)Handle); +} - // If we've already loaded this library, FreeLibrary() the handle in order to - // keep the internal refcount at +1. - if (!OpenedHandles->insert(a_handle).second) - FreeLibrary(a_handle); +static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) { + // EnumProcessModules will fail on Windows 64 while some versions of + // MingW-32 don't have EnumProcessModulesEx. + if ( +#ifdef _WIN64 + !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT) +#else + !EnumProcessModules(H, Data, Bytes, &Bytes) +#endif + ) { + std::string Err; + if (MakeErrMsg(&Err, "EnumProcessModules failure")) + llvm::errs() << Err << "\n"; + return false; + } + return true; +} - return DynamicLibrary(a_handle); +void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { + HandleSet* HS = IsOpenedHandlesInstance(Handle); + if (!HS) + return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol)); + + // Could have done a dlclose on the *Process* handle + if (!HS->Process) + return nullptr; + + // Trials indicate EnumProcessModulesEx is consistantly faster than using + // EnumerateLoadedModules64 or CreateToolhelp32Snapshot. + // + // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx + // |=========|=============|======================================== + // | 37 | 0.0000585 * | 0.0003031 | 0.0000152 + // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683 + // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610 + // + // * Not including the load time of Dbghelp.dll (~.005 sec) + // + // There's still a case to somehow cache the result of EnumProcessModulesEx + // across invocations, but the complication of doing that properly... + // Possibly using LdrRegisterDllNotification to invalidate the cache? + + DWORD Bytes = 0; + HMODULE Self = HMODULE(GetCurrentProcess()); + if (!GetProcessModules(Self, Bytes)) + return nullptr; + + // Get the most recent list in case any modules added/removed between calls + // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES. + // MSDN is pretty clear that if the module list changes during the call to + // EnumProcessModulesEx the results should not be used. + std::vector<HMODULE> Handles; + do { + assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) && + "Should have at least one module and be aligned"); + Handles.resize(Bytes / sizeof(HMODULE)); + if (!GetProcessModules(Self, Bytes, Handles.data())) + return nullptr; + } while (Bytes != (Handles.size() * sizeof(HMODULE))); + + // Try EXE first, mirroring what dlsym(dlopen(NULL)) does. + if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol)) + return (void *) uintptr_t(Ptr); + + if (Handles.size() > 1) { + // This is different behaviour than what Posix dlsym(dlopen(NULL)) does. + // Doing that here is causing real problems for the JIT where msvc.dll + // and ucrt.dll can define the same symbols. The runtime linker will choose + // symbols from ucrt.dll first, but iterating NOT in reverse here would + // mean that the msvc.dll versions would be returned. + + for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) { + if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol)) + return (void *) uintptr_t(Ptr); + } + } + return nullptr; } + // Stack probing routines are in the support library (e.g. libgcc), but we don't // have dynamic linking on windows. Provide a hook. #define EXPLICIT_SYMBOL(SYM) \ @@ -123,38 +173,18 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, #undef INLINE_DEF_SYMBOL1 #undef INLINE_DEF_SYMBOL2 -void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { - SmartScopedLock<true> Lock(*SymbolsMutex); - - // First check symbols added via AddSymbol(). - if (ExplicitSymbols.isConstructed()) { - StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName); - - if (i != ExplicitSymbols->end()) - return i->second; - } - - // Now search the libraries. - if (OpenedHandles) { - for (DenseSet<HMODULE>::iterator I = OpenedHandles->begin(), - E = OpenedHandles->end(); I != E; ++I) { - FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName); - if (ptr) { - return (void *)(intptr_t)ptr; - } - } - } +static void *DoSearch(const char *SymbolName) { #define EXPLICIT_SYMBOL(SYM) \ - if (!strcmp(symbolName, #SYM)) \ + if (!strcmp(SymbolName, #SYM)) \ return (void *)&SYM; #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ - if (!strcmp(symbolName, #SYMFROM)) \ + if (!strcmp(SymbolName, #SYMFROM)) \ return (void *)&SYMTO; #ifdef _M_IX86 #define INLINE_DEF_SYMBOL1(TYP, SYM) \ - if (!strcmp(symbolName, #SYM)) \ + if (!strcmp(SymbolName, #SYM)) \ return (void *)&inline_##SYM; #define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM) #endif @@ -168,15 +198,5 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { #undef INLINE_DEF_SYMBOL1 #undef INLINE_DEF_SYMBOL2 - return 0; -} - -void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { - if (!isValid()) - return NULL; - if (Data == &OpenedHandles) - return SearchForAddressOfSymbol(symbolName); - return (void *)(intptr_t)GetProcAddress((HMODULE)Data, symbolName); -} - + return nullptr; } diff --git a/contrib/llvm/lib/Support/Windows/Host.inc b/contrib/llvm/lib/Support/Windows/Host.inc index fe89fe0..90a6fb3 100644 --- a/contrib/llvm/lib/Support/Windows/Host.inc +++ b/contrib/llvm/lib/Support/Windows/Host.inc @@ -17,6 +17,18 @@ using namespace llvm; +static std::string updateTripleOSVersion(std::string Triple) { + return Triple; +} + std::string sys::getDefaultTargetTriple() { - return Triple::normalize(LLVM_DEFAULT_TARGET_TRIPLE); + const char *Triple = LLVM_DEFAULT_TARGET_TRIPLE; + + // Override the default target with an environment variable named by LLVM_TARGET_TRIPLE_ENV. +#if defined(LLVM_TARGET_TRIPLE_ENV) + if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) + Triple = EnvTriple; +#endif + + return Triple::normalize(Triple); } diff --git a/contrib/llvm/lib/Support/Windows/Mutex.inc b/contrib/llvm/lib/Support/Windows/Mutex.inc index ab79d07..0af145e 100644 --- a/contrib/llvm/lib/Support/Windows/Mutex.inc +++ b/contrib/llvm/lib/Support/Windows/Mutex.inc @@ -20,15 +20,14 @@ #include "llvm/Support/Mutex.h" namespace llvm { -using namespace sys; -MutexImpl::MutexImpl(bool /*recursive*/) +sys::MutexImpl::MutexImpl(bool /*recursive*/) { data_ = new CRITICAL_SECTION; InitializeCriticalSection((LPCRITICAL_SECTION)data_); } -MutexImpl::~MutexImpl() +sys::MutexImpl::~MutexImpl() { DeleteCriticalSection((LPCRITICAL_SECTION)data_); delete (LPCRITICAL_SECTION)data_; @@ -36,21 +35,21 @@ MutexImpl::~MutexImpl() } bool -MutexImpl::acquire() +sys::MutexImpl::acquire() { EnterCriticalSection((LPCRITICAL_SECTION)data_); return true; } bool -MutexImpl::release() +sys::MutexImpl::release() { LeaveCriticalSection((LPCRITICAL_SECTION)data_); return true; } bool -MutexImpl::tryacquire() +sys::MutexImpl::tryacquire() { return TryEnterCriticalSection((LPCRITICAL_SECTION)data_); } diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc index 27b250b..b00d390 100644 --- a/contrib/llvm/lib/Support/Windows/Path.inc +++ b/contrib/llvm/lib/Support/Windows/Path.inc @@ -26,6 +26,7 @@ // These two headers must be included last, and make sure shlobj is required // after Windows.h to make sure it picks up our definition of _WIN32_WINNT #include "WindowsSupport.h" +#include <shellapi.h> #include <shlobj.h> #undef max @@ -178,6 +179,10 @@ TimePoint<> file_status::getLastModificationTime() const { return toTimePoint(Time); } +uint32_t file_status::getLinkCount() const { + return NumLinks; +} + std::error_code current_path(SmallVectorImpl<char> &result) { SmallVector<wchar_t, MAX_PATH> cur_path; DWORD len = MAX_PATH; @@ -200,6 +205,18 @@ std::error_code current_path(SmallVectorImpl<char> &result) { return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } +std::error_code set_current_path(const Twine &path) { + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_path; + if (std::error_code ec = widenPath(path, wide_path)) + return ec; + + if (!::SetCurrentDirectoryW(wide_path.begin())) + return mapWindowsError(::GetLastError()); + + return std::error_code(); +} + std::error_code create_directory(const Twine &path, bool IgnoreExisting, perms Perms) { SmallVector<wchar_t, 128> path_utf16; @@ -265,6 +282,80 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { return std::error_code(); } +static std::error_code is_local_internal(SmallVectorImpl<wchar_t> &Path, + bool &Result) { + SmallVector<wchar_t, 128> VolumePath; + size_t Len = 128; + while (true) { + VolumePath.resize(Len); + BOOL Success = + ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size()); + + if (Success) + break; + + DWORD Err = ::GetLastError(); + if (Err != ERROR_INSUFFICIENT_BUFFER) + return mapWindowsError(Err); + + Len *= 2; + } + // If the output buffer has exactly enough space for the path name, but not + // the null terminator, it will leave the output unterminated. Push a null + // terminator onto the end to ensure that this never happens. + VolumePath.push_back(L'\0'); + VolumePath.set_size(wcslen(VolumePath.data())); + const wchar_t *P = VolumePath.data(); + + UINT Type = ::GetDriveTypeW(P); + switch (Type) { + case DRIVE_FIXED: + Result = true; + return std::error_code(); + case DRIVE_REMOTE: + case DRIVE_CDROM: + case DRIVE_RAMDISK: + case DRIVE_REMOVABLE: + Result = false; + return std::error_code(); + default: + return make_error_code(errc::no_such_file_or_directory); + } + llvm_unreachable("Unreachable!"); +} + +std::error_code is_local(const Twine &path, bool &result) { + if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path)) + return make_error_code(errc::no_such_file_or_directory); + + SmallString<128> Storage; + StringRef P = path.toStringRef(Storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> WidePath; + if (std::error_code ec = widenPath(P, WidePath)) + return ec; + return is_local_internal(WidePath, result); +} + +std::error_code is_local(int FD, bool &Result) { + SmallVector<wchar_t, 128> FinalPath; + HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + + size_t Len = 128; + do { + FinalPath.reserve(Len); + Len = ::GetFinalPathNameByHandleW(Handle, FinalPath.data(), + FinalPath.capacity() - 1, VOLUME_NAME_NT); + if (Len == 0) + return mapWindowsError(::GetLastError()); + } while (Len > FinalPath.capacity()); + + FinalPath.set_size(Len); + + return is_local_internal(FinalPath, Result); +} + std::error_code rename(const Twine &from, const Twine &to) { // Convert to utf-16. SmallVector<wchar_t, 128> wide_from; @@ -443,13 +534,16 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file : file_type::regular_file; - Result = - file_status(Type, Info.ftLastAccessTime.dwHighDateTime, - Info.ftLastAccessTime.dwLowDateTime, - Info.ftLastWriteTime.dwHighDateTime, - Info.ftLastWriteTime.dwLowDateTime, - Info.dwVolumeSerialNumber, Info.nFileSizeHigh, - Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); + perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + ? (all_read | all_exe) + : all_all; + Result = file_status( + Type, Permissions, Info.nNumberOfLinks, + Info.ftLastAccessTime.dwHighDateTime, + Info.ftLastAccessTime.dwLowDateTime, + Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, + Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, + Info.nFileIndexHigh, Info.nFileIndexLow); return std::error_code(); } @@ -465,7 +559,7 @@ handle_status_error: return mapWindowsError(LastError); } -std::error_code status(const Twine &path, file_status &result) { +std::error_code status(const Twine &path, file_status &result, bool Follow) { SmallString<128> path_storage; SmallVector<wchar_t, 128> path_utf16; @@ -482,28 +576,19 @@ std::error_code status(const Twine &path, file_status &result) { if (attr == INVALID_FILE_ATTRIBUTES) return getStatus(INVALID_HANDLE_VALUE, result); + DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS; // Handle reparse points. - if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { - ScopedFileHandle h( - ::CreateFileW(path_utf16.begin(), - 0, // Attributes only. - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); - if (!h) - return getStatus(INVALID_HANDLE_VALUE, result); - } + if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) + Flags |= FILE_FLAG_OPEN_REPARSE_POINT; ScopedFileHandle h( ::CreateFileW(path_utf16.begin(), 0, // Attributes only. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); - if (!h) - return getStatus(INVALID_HANDLE_VALUE, result); + NULL, OPEN_EXISTING, Flags, 0)); + if (!h) + return getStatus(INVALID_HANDLE_VALUE, result); - return getStatus(h, result); + return getStatus(h, result); } std::error_code status(int FD, file_status &Result) { @@ -511,6 +596,37 @@ std::error_code status(int FD, file_status &Result) { return getStatus(FileHandle, Result); } +std::error_code setPermissions(const Twine &Path, perms Permissions) { + SmallVector<wchar_t, 128> PathUTF16; + if (std::error_code EC = widenPath(Path, PathUTF16)) + return EC; + + DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin()); + if (Attributes == INVALID_FILE_ATTRIBUTES) + return mapWindowsError(GetLastError()); + + // There are many Windows file attributes that are not to do with the file + // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve + // them. + if (Permissions & all_write) { + Attributes &= ~FILE_ATTRIBUTE_READONLY; + if (Attributes == 0) + // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set. + Attributes |= FILE_ATTRIBUTE_NORMAL; + } + else { + Attributes |= FILE_ATTRIBUTE_READONLY; + // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so + // remove it, if it is present. + Attributes &= ~FILE_ATTRIBUTE_NORMAL; + } + + if (!::SetFileAttributesW(PathUTF16.begin(), Attributes)) + return mapWindowsError(GetLastError()); + + return std::error_code(); +} + std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) { FILETIME FT = toFILETIME(Time); HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); @@ -616,7 +732,8 @@ int mapped_file_region::alignment() { } std::error_code detail::directory_iterator_construct(detail::DirIterState &it, - StringRef path){ + StringRef path, + bool follow_symlinks) { SmallVector<wchar_t, 128> path_utf16; if (std::error_code ec = widenPath(path, path_utf16)) @@ -661,7 +778,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it, it.IterationHandle = intptr_t(FindHandle.take()); SmallString<128> directory_entry_path(path); path::append(directory_entry_path, directory_entry_name_utf8); - it.CurrentEntry = directory_entry(directory_entry_path); + it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks); return std::error_code(); } @@ -701,6 +818,52 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { return std::error_code(); } +static std::error_code realPathFromHandle(HANDLE H, + SmallVectorImpl<char> &RealPath) { + RealPath.clear(); + llvm::SmallVector<wchar_t, MAX_PATH> Buffer; + DWORD CountChars = ::GetFinalPathNameByHandleW( + H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); + if (CountChars > Buffer.capacity()) { + // The buffer wasn't big enough, try again. In this case the return value + // *does* indicate the size of the null terminator. + Buffer.reserve(CountChars); + CountChars = ::GetFinalPathNameByHandleW( + H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); + } + if (CountChars == 0) + return mapWindowsError(GetLastError()); + + const wchar_t *Data = Buffer.data(); + if (CountChars >= 4) { + if (0 == ::memcmp(Data, L"\\\\?\\", 8)) { + CountChars -= 4; + Data += 4; + } + } + + // Convert the result from UTF-16 to UTF-8. + return UTF16ToUTF8(Data, CountChars, RealPath); +} + +static std::error_code directoryRealPath(const Twine &Name, + SmallVectorImpl<char> &RealPath) { + SmallVector<wchar_t, 128> PathUTF16; + + if (std::error_code EC = widenPath(Name, PathUTF16)) + return EC; + + HANDLE H = + ::CreateFileW(PathUTF16.begin(), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (H == INVALID_HANDLE_VALUE) + return mapWindowsError(GetLastError()); + std::error_code EC = realPathFromHandle(H, RealPath); + ::CloseHandle(H); + return EC; +} + std::error_code openFileForRead(const Twine &Name, int &ResultFD, SmallVectorImpl<char> *RealPath) { SmallVector<wchar_t, 128> PathUTF16; @@ -732,20 +895,8 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD, } // Fetch the real name of the file, if the user asked - if (RealPath) { - RealPath->clear(); - wchar_t RealPathUTF16[MAX_PATH]; - DWORD CountChars = - ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH, - FILE_NAME_NORMALIZED); - if (CountChars > 0 && CountChars < MAX_PATH) { - // Convert the result from UTF-16 to UTF-8. - SmallString<MAX_PATH> RealPathUTF8; - if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8)) - RealPath->append(RealPathUTF8.data(), - RealPathUTF8.data() + strlen(RealPathUTF8.data())); - } - } + if (RealPath) + realPathFromHandle(H, *RealPath); ResultFD = FD; return std::error_code(); @@ -843,6 +994,81 @@ std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) { return windows::UTF16ToUTF8(TempPath.data(), CharCount, ResultPath); } + +std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { + // Convert to utf-16. + SmallVector<wchar_t, 128> Path16; + std::error_code EC = widenPath(path, Path16); + if (EC && !IgnoreErrors) + return EC; + + // SHFileOperation() accepts a list of paths, and so must be double null- + // terminated to indicate the end of the list. The buffer is already null + // terminated, but since that null character is not considered part of the + // vector's size, pushing another one will just consume that byte. So we + // need to push 2 null terminators. + Path16.push_back(0); + Path16.push_back(0); + + SHFILEOPSTRUCTW shfos = {}; + shfos.wFunc = FO_DELETE; + shfos.pFrom = Path16.data(); + shfos.fFlags = FOF_NO_UI; + + int result = ::SHFileOperationW(&shfos); + if (result != 0 && !IgnoreErrors) + return mapWindowsError(result); + return std::error_code(); +} + +static void expandTildeExpr(SmallVectorImpl<char> &Path) { + // Path does not begin with a tilde expression. + if (Path.empty() || Path[0] != '~') + return; + + StringRef PathStr(Path.begin(), Path.size()); + PathStr = PathStr.drop_front(); + StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); }); + + if (!Expr.empty()) { + // This is probably a ~username/ expression. Don't support this on Windows. + return; + } + + SmallString<128> HomeDir; + if (!path::home_directory(HomeDir)) { + // For some reason we couldn't get the home directory. Just exit. + return; + } + + // Overwrite the first character and insert the rest. + Path[0] = HomeDir[0]; + Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end()); +} + +std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, + bool expand_tilde) { + dest.clear(); + if (path.isTriviallyEmpty()) + return std::error_code(); + + if (expand_tilde) { + SmallString<128> Storage; + path.toVector(Storage); + expandTildeExpr(Storage); + return real_path(Storage, dest, false); + } + + if (is_directory(path)) + return directoryRealPath(path, dest); + + int fd; + if (std::error_code EC = llvm::sys::fs::openFileForRead(path, fd, &dest)) + return EC; + ::close(fd); + return std::error_code(); +} + } // end namespace fs namespace path { diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc index 8d646b3..18aef61 100644 --- a/contrib/llvm/lib/Support/Windows/Process.inc +++ b/contrib/llvm/lib/Support/Windows/Process.inc @@ -47,7 +47,6 @@ #endif using namespace llvm; -using namespace sys; // This function retrieves the page size using GetNativeSystemInfo() and is // present solely so it can be called once to initialize the self_process member diff --git a/contrib/llvm/lib/Support/Windows/Program.inc b/contrib/llvm/lib/Support/Windows/Program.inc index 78fc538..721167d 100644 --- a/contrib/llvm/lib/Support/Windows/Program.inc +++ b/contrib/llvm/lib/Support/Windows/Program.inc @@ -29,7 +29,6 @@ //===----------------------------------------------------------------------===// namespace llvm { -using namespace sys; ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {} diff --git a/contrib/llvm/lib/Support/Windows/RWMutex.inc b/contrib/llvm/lib/Support/Windows/RWMutex.inc index 2d1d25f..ac60c2f 100644 --- a/contrib/llvm/lib/Support/Windows/RWMutex.inc +++ b/contrib/llvm/lib/Support/Windows/RWMutex.inc @@ -19,7 +19,6 @@ #include "WindowsSupport.h" namespace llvm { -using namespace sys; // Windows has slim read-writer lock support on Vista and higher, so we // will attempt to load the APIs. If they exist, we will use them, and @@ -73,7 +72,7 @@ static bool loadSRW() { return sHasSRW; } -RWMutexImpl::RWMutexImpl() { +sys::RWMutexImpl::RWMutexImpl() { if (loadSRW()) { data_ = calloc(1, sizeof(SRWLOCK)); fpInitializeSRWLock(static_cast<PSRWLOCK>(data_)); @@ -83,14 +82,14 @@ RWMutexImpl::RWMutexImpl() { } } -RWMutexImpl::~RWMutexImpl() { +sys::RWMutexImpl::~RWMutexImpl() { if (!sHasSRW) DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); // Nothing to do in the case of slim reader/writers except free the memory. free(data_); } -bool RWMutexImpl::reader_acquire() { +bool sys::RWMutexImpl::reader_acquire() { if (sHasSRW) { fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_)); } else { @@ -99,7 +98,7 @@ bool RWMutexImpl::reader_acquire() { return true; } -bool RWMutexImpl::reader_release() { +bool sys::RWMutexImpl::reader_release() { if (sHasSRW) { fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_)); } else { @@ -108,7 +107,7 @@ bool RWMutexImpl::reader_release() { return true; } -bool RWMutexImpl::writer_acquire() { +bool sys::RWMutexImpl::writer_acquire() { if (sHasSRW) { fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_)); } else { @@ -117,7 +116,7 @@ bool RWMutexImpl::writer_acquire() { return true; } -bool RWMutexImpl::writer_release() { +bool sys::RWMutexImpl::writer_release() { if (sHasSRW) { fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_)); } else { diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc index f739421..1ef5188 100644 --- a/contrib/llvm/lib/Support/Windows/Signals.inc +++ b/contrib/llvm/lib/Support/Windows/Signals.inc @@ -776,7 +776,7 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { // the nasty sorts of crashes that aren't 100% reproducible from a set of // inputs (or in the event that the user is unable or unwilling to provide a // reproducible case). - if (!llvm::Process::AreCoreFilesPrevented()) { + if (!llvm::sys::Process::AreCoreFilesPrevented()) { MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; ExceptionInfo.ThreadId = ::GetCurrentThreadId(); ExceptionInfo.ExceptionPointers = ep; diff --git a/contrib/llvm/lib/Support/Windows/ThreadLocal.inc b/contrib/llvm/lib/Support/Windows/ThreadLocal.inc index b9cb8ff..8be1c3e 100644 --- a/contrib/llvm/lib/Support/Windows/ThreadLocal.inc +++ b/contrib/llvm/lib/Support/Windows/ThreadLocal.inc @@ -20,33 +20,32 @@ #include "llvm/Support/ThreadLocal.h" namespace llvm { -using namespace sys; -ThreadLocalImpl::ThreadLocalImpl() : data() { +sys::ThreadLocalImpl::ThreadLocalImpl() : data() { static_assert(sizeof(DWORD) <= sizeof(data), "size too big"); DWORD* tls = reinterpret_cast<DWORD*>(&data); *tls = TlsAlloc(); assert(*tls != TLS_OUT_OF_INDEXES); } -ThreadLocalImpl::~ThreadLocalImpl() { +sys::ThreadLocalImpl::~ThreadLocalImpl() { DWORD* tls = reinterpret_cast<DWORD*>(&data); TlsFree(*tls); } -void *ThreadLocalImpl::getInstance() { +void *sys::ThreadLocalImpl::getInstance() { DWORD* tls = reinterpret_cast<DWORD*>(&data); return TlsGetValue(*tls); } -void ThreadLocalImpl::setInstance(const void* d){ +void sys::ThreadLocalImpl::setInstance(const void* d){ DWORD* tls = reinterpret_cast<DWORD*>(&data); int errorcode = TlsSetValue(*tls, const_cast<void*>(d)); assert(errorcode != 0); (void)errorcode; } -void ThreadLocalImpl::removeInstance() { +void sys::ThreadLocalImpl::removeInstance() { setInstance(0); } diff --git a/contrib/llvm/lib/Support/Windows/Threading.inc b/contrib/llvm/lib/Support/Windows/Threading.inc new file mode 100644 index 0000000..decb488 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Threading.inc @@ -0,0 +1,109 @@ +//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of Threading functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" + +#include "Windows/WindowsSupport.h" +#include <process.h> + +// Windows will at times define MemoryFence. +#ifdef MemoryFence +#undef MemoryFence +#endif + +namespace { + struct ThreadInfo { + void(*func)(void*); + void *param; + }; +} + +static unsigned __stdcall ThreadCallback(void *param) { + struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param); + info->func(info->param); + + return 0; +} + +void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + struct ThreadInfo param = { Fn, UserData }; + + HANDLE hThread = (HANDLE)::_beginthreadex(NULL, + RequestedStackSize, ThreadCallback, + ¶m, 0, NULL); + + if (hThread) { + // We actually don't care whether the wait succeeds or fails, in + // the same way we don't care whether the pthread_join call succeeds + // or fails. There's not much we could do if this were to fail. But + // on success, this call will wait until the thread finishes executing + // before returning. + (void)::WaitForSingleObject(hThread, INFINITE); + ::CloseHandle(hThread); + } +} + +uint64_t llvm::get_threadid() { + return uint64_t(::GetCurrentThreadId()); +} + +uint32_t llvm::get_max_thread_name_length() { return 0; } + +#if defined(_MSC_VER) +static void SetThreadName(DWORD Id, LPCSTR Name) { + constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; + +#pragma pack(push, 8) + struct THREADNAME_INFO { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to thread name + DWORD dwThreadId; // Thread ID (-1 == current thread) + DWORD dwFlags; // Reserved. Do not use. + }; +#pragma pack(pop) + + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = Name; + info.dwThreadId = Id; + info.dwFlags = 0; + + __try { + ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), + (ULONG_PTR *)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + } +} +#endif + +void llvm::set_thread_name(const Twine &Name) { +#if defined(_MSC_VER) + // Make sure the input is null terminated. + SmallString<64> Storage; + StringRef NameStr = Name.toNullTerminatedStringRef(Storage); + SetThreadName(::GetCurrentThreadId(), NameStr.data()); +#endif +} + +void llvm::get_thread_name(SmallVectorImpl<char> &Name) { + // "Name" is not an inherent property of a thread on Windows. In fact, when + // you "set" the name, you are only firing a one-time message to a debugger + // which it interprets as a program setting its threads' name. We may be + // able to get fancy by creating a TLS entry when someone calls + // set_thread_name so that subsequent calls to get_thread_name return this + // value. + Name.clear(); +} diff --git a/contrib/llvm/lib/Support/Windows/WindowsSupport.h b/contrib/llvm/lib/Support/Windows/WindowsSupport.h index c358b99..d4599dc 100644 --- a/contrib/llvm/lib/Support/Windows/WindowsSupport.h +++ b/contrib/llvm/lib/Support/Windows/WindowsSupport.h @@ -45,7 +45,9 @@ #include <string> #include <system_error> #include <windows.h> -#include <wincrypt.h> // Must be included after windows.h + +// Must be included after windows.h +#include <wincrypt.h> /// Determines if the program is running on Windows 8 or newer. This /// reimplements one of the helpers in the Windows 8.1 SDK, which are intended |