diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
commit | 71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch) | |
tree | 5343938942df402b49ec7300a1c25a2d4ccd5821 /lib/Support/Windows | |
parent | 31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff) |
Diffstat (limited to 'lib/Support/Windows')
-rw-r--r-- | lib/Support/Windows/DynamicLibrary.inc | 34 | ||||
-rw-r--r-- | lib/Support/Windows/Mutex.inc | 11 | ||||
-rw-r--r-- | lib/Support/Windows/Path.inc | 306 | ||||
-rw-r--r-- | lib/Support/Windows/Process.inc | 1 | ||||
-rw-r--r-- | lib/Support/Windows/Program.inc | 1 | ||||
-rw-r--r-- | lib/Support/Windows/RWMutex.inc | 13 | ||||
-rw-r--r-- | lib/Support/Windows/Signals.inc | 2 | ||||
-rw-r--r-- | lib/Support/Windows/ThreadLocal.inc | 11 | ||||
-rw-r--r-- | lib/Support/Windows/Threading.inc | 109 |
9 files changed, 412 insertions, 76 deletions
diff --git a/lib/Support/Windows/DynamicLibrary.inc b/lib/Support/Windows/DynamicLibrary.inc index 050689483deb..709499deeafa 100644 --- a/lib/Support/Windows/DynamicLibrary.inc +++ b/lib/Support/Windows/DynamicLibrary.inc @@ -24,7 +24,6 @@ #endif namespace llvm { -using namespace sys; //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code @@ -33,7 +32,7 @@ using namespace sys; typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); static fpEnumerateLoadedModules fEnumerateLoadedModules; -static DenseSet<HMODULE> *OpenedHandles; +static llvm::ManagedStatic<DenseSet<HMODULE> > OpenedHandles; static bool loadDebugHelp(void) { HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); @@ -51,15 +50,13 @@ ELM_Callback(PCSTR ModuleName, DWORD64 ModuleBase, return TRUE; } -DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, - std::string *errMsg) { +sys::DynamicLibrary +sys::DynamicLibrary::getPermanentLibrary(const char *filename, + std::string *errMsg) { SmartScopedLock<true> lock(*SymbolsMutex); 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"); @@ -79,7 +76,7 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16"); return DynamicLibrary(); } - + HMODULE a_handle = LoadLibraryW(filenameUnicode.data()); if (a_handle == 0) { @@ -87,9 +84,6 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, return DynamicLibrary(); } - if (OpenedHandles == 0) - OpenedHandles = new DenseSet<HMODULE>(); - // 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) @@ -98,6 +92,18 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, return DynamicLibrary(a_handle); } +sys::DynamicLibrary +sys::DynamicLibrary::addPermanentLibrary(void *handle, std::string *errMsg) { + SmartScopedLock<true> lock(*SymbolsMutex); + // If we've already loaded this library, tell the caller. + if (!OpenedHandles->insert((HMODULE)handle).second) { + MakeErrMsg(errMsg, "Library already loaded"); + return DynamicLibrary(); + } + + return DynamicLibrary(handle); +} + // 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,7 +129,7 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, #undef INLINE_DEF_SYMBOL1 #undef INLINE_DEF_SYMBOL2 -void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { +void *sys::DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) { SmartScopedLock<true> Lock(*SymbolsMutex); // First check symbols added via AddSymbol(). @@ -135,7 +141,7 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { } // Now search the libraries. - if (OpenedHandles) { + if (OpenedHandles.isConstructed()) { for (DenseSet<HMODULE>::iterator I = OpenedHandles->begin(), E = OpenedHandles->end(); I != E; ++I) { FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName); @@ -171,7 +177,7 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { return 0; } -void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { +void *sys::DynamicLibrary::getAddressOfSymbol(const char *symbolName) { if (!isValid()) return NULL; if (Data == &OpenedHandles) diff --git a/lib/Support/Windows/Mutex.inc b/lib/Support/Windows/Mutex.inc index ab79d079122f..0af145ec9a4e 100644 --- a/lib/Support/Windows/Mutex.inc +++ b/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/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index 27b250b428a5..b00d3905f658 100644 --- a/lib/Support/Windows/Path.inc +++ b/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/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc index 8d646b3217a0..18aef610d54a 100644 --- a/lib/Support/Windows/Process.inc +++ b/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/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index 78fc538bd9bf..721167da5b15 100644 --- a/lib/Support/Windows/Program.inc +++ b/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/lib/Support/Windows/RWMutex.inc b/lib/Support/Windows/RWMutex.inc index 2d1d25f67b8a..ac60c2fc05be 100644 --- a/lib/Support/Windows/RWMutex.inc +++ b/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/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc index f739421eece4..1ef51888baf3 100644 --- a/lib/Support/Windows/Signals.inc +++ b/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/lib/Support/Windows/ThreadLocal.inc b/lib/Support/Windows/ThreadLocal.inc index b9cb8ff9836e..8be1c3ecfbb9 100644 --- a/lib/Support/Windows/ThreadLocal.inc +++ b/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/lib/Support/Windows/Threading.inc b/lib/Support/Windows/Threading.inc new file mode 100644 index 000000000000..decb48887af2 --- /dev/null +++ b/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(); +} |