aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/cxxsupp
diff options
context:
space:
mode:
authoralexv-smirnov <alex@ydb.tech>2022-12-20 00:50:48 +0300
committeralexv-smirnov <alex@ydb.tech>2022-12-20 00:50:48 +0300
commit84f2cfa253cc618438ed6e9d68b33fa7c0d88cb9 (patch)
treef0cf2236e0aafb3e437199f1ac7b559e7fad554a /contrib/libs/cxxsupp
parentbde6febc1ad3b826e72746de21d7250803e8e0b5 (diff)
downloadydb-84f2cfa253cc618438ed6e9d68b33fa7c0d88cb9.tar.gz
add windows platform to ydb github export
Diffstat (limited to 'contrib/libs/cxxsupp')
-rw-r--r--contrib/libs/cxxsupp/libcxx/src/support/win32/atomic_win32.cpp31
-rw-r--r--contrib/libs/cxxsupp/libcxx/src/support/win32/locale_win32.cpp141
-rw-r--r--contrib/libs/cxxsupp/libcxx/src/support/win32/new_win32.cpp28
-rw-r--r--contrib/libs/cxxsupp/libcxx/src/support/win32/support.cpp172
-rw-r--r--contrib/libs/cxxsupp/libcxx/src/support/win32/thread_win32.cpp274
5 files changed, 646 insertions, 0 deletions
diff --git a/contrib/libs/cxxsupp/libcxx/src/support/win32/atomic_win32.cpp b/contrib/libs/cxxsupp/libcxx/src/support/win32/atomic_win32.cpp
new file mode 100644
index 0000000000..28cb0722ce
--- /dev/null
+++ b/contrib/libs/cxxsupp/libcxx/src/support/win32/atomic_win32.cpp
@@ -0,0 +1,31 @@
+#include <intrin.h>
+#include <cstdint>
+
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace {
+static const int __msvc_locks_size = 1024;
+volatile long __msvc_locks[__msvc_locks_size];
+
+size_t __msvc_lock_hash(void* __p) {
+ uintptr_t __num = reinterpret_cast<uintptr_t>(__p);
+ return (__num ^ (__num >> 10)) & (__msvc_locks_size - 1);
+}
+}
+
+void __msvc_lock(void* __p) {
+ volatile long& __lock = __msvc_locks[__msvc_lock_hash(__p)];
+ while (_InterlockedExchange(&__lock, 1) == 0) {
+#if defined(_M_ARM) || defined(_M_ARM64)
+ __yield();
+#endif
+ }
+}
+
+void __msvc_unlock(void* __p) {
+ volatile long& __lock = __msvc_locks[__msvc_lock_hash(__p)];
+ _InterlockedExchange(&__lock, 0);
+}
+
+_LIBCPP_END_NAMESPACE_STD \ No newline at end of file
diff --git a/contrib/libs/cxxsupp/libcxx/src/support/win32/locale_win32.cpp b/contrib/libs/cxxsupp/libcxx/src/support/win32/locale_win32.cpp
new file mode 100644
index 0000000000..67f4d1341a
--- /dev/null
+++ b/contrib/libs/cxxsupp/libcxx/src/support/win32/locale_win32.cpp
@@ -0,0 +1,141 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <locale>
+#include <cstdarg> // va_start, va_end
+#include <memory>
+#include <type_traits>
+
+int __libcpp_vasprintf(char **sptr, const char *__restrict fmt, va_list ap);
+
+using std::__libcpp_locale_guard;
+
+// FIXME: base currently unused. Needs manual work to construct the new locale
+locale_t newlocale( int mask, const char * locale, locale_t /*base*/ )
+{
+ return {_create_locale( LC_ALL, locale ), locale};
+}
+
+decltype(MB_CUR_MAX) MB_CUR_MAX_L( locale_t __l )
+{
+#if defined(_LIBCPP_MSVCRT)
+ return ___mb_cur_max_l_func(__l);
+#else
+ __libcpp_locale_guard __current(__l);
+ return MB_CUR_MAX;
+#endif
+}
+
+lconv *localeconv_l( locale_t &loc )
+{
+ __libcpp_locale_guard __current(loc);
+ lconv *lc = localeconv();
+ if (!lc)
+ return lc;
+ return loc.__store_lconv(lc);
+}
+size_t mbrlen_l( const char *__restrict s, size_t n,
+ mbstate_t *__restrict ps, locale_t loc )
+{
+ __libcpp_locale_guard __current(loc);
+ return mbrlen( s, n, ps );
+}
+size_t mbsrtowcs_l( wchar_t *__restrict dst, const char **__restrict src,
+ size_t len, mbstate_t *__restrict ps, locale_t loc )
+{
+ __libcpp_locale_guard __current(loc);
+ return mbsrtowcs( dst, src, len, ps );
+}
+size_t wcrtomb_l( char *__restrict s, wchar_t wc, mbstate_t *__restrict ps,
+ locale_t loc )
+{
+ __libcpp_locale_guard __current(loc);
+ return wcrtomb( s, wc, ps );
+}
+size_t mbrtowc_l( wchar_t *__restrict pwc, const char *__restrict s,
+ size_t n, mbstate_t *__restrict ps, locale_t loc )
+{
+ __libcpp_locale_guard __current(loc);
+ return mbrtowc( pwc, s, n, ps );
+}
+size_t mbsnrtowcs_l( wchar_t *__restrict dst, const char **__restrict src,
+ size_t nms, size_t len, mbstate_t *__restrict ps, locale_t loc )
+{
+ __libcpp_locale_guard __current(loc);
+ return mbsnrtowcs( dst, src, nms, len, ps );
+}
+size_t wcsnrtombs_l( char *__restrict dst, const wchar_t **__restrict src,
+ size_t nwc, size_t len, mbstate_t *__restrict ps, locale_t loc )
+{
+ __libcpp_locale_guard __current(loc);
+ return wcsnrtombs( dst, src, nwc, len, ps );
+}
+wint_t btowc_l( int c, locale_t loc )
+{
+ __libcpp_locale_guard __current(loc);
+ return btowc( c );
+}
+int wctob_l( wint_t c, locale_t loc )
+{
+ __libcpp_locale_guard __current(loc);
+ return wctob( c );
+}
+
+int snprintf_l(char *ret, size_t n, locale_t loc, const char *format, ...)
+{
+ va_list ap;
+ va_start( ap, format );
+#if defined(_LIBCPP_MSVCRT)
+ // FIXME: Remove usage of internal CRT function and globals.
+ int result = __stdio_common_vsprintf(
+ _CRT_INTERNAL_LOCAL_PRINTF_OPTIONS | _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR,
+ ret, n, format, loc, ap);
+#else
+ __libcpp_locale_guard __current(loc);
+ _LIBCPP_DIAGNOSTIC_PUSH
+ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
+ int result = vsnprintf( ret, n, format, ap );
+ _LIBCPP_DIAGNOSTIC_POP
+#endif
+ va_end(ap);
+ return result;
+}
+
+int asprintf_l( char **ret, locale_t loc, const char *format, ... )
+{
+ va_list ap;
+ va_start( ap, format );
+ int result = vasprintf_l( ret, loc, format, ap );
+ va_end(ap);
+ return result;
+}
+int vasprintf_l( char **ret, locale_t loc, const char *format, va_list ap )
+{
+ __libcpp_locale_guard __current(loc);
+ return __libcpp_vasprintf( ret, format, ap );
+}
+
+#if !defined(_LIBCPP_MSVCRT)
+float strtof_l(const char* nptr, char** endptr, locale_t loc) {
+ __libcpp_locale_guard __current(loc);
+ return strtof(nptr, endptr);
+}
+
+long double strtold_l(const char* nptr, char** endptr, locale_t loc) {
+ __libcpp_locale_guard __current(loc);
+ return strtold(nptr, endptr);
+}
+#endif
+
+#if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0800
+size_t strftime_l(char *ret, size_t n, const char *format, const struct tm *tm,
+ locale_t loc) {
+ __libcpp_locale_guard __current(loc);
+ return strftime(ret, n, format, tm);
+}
+#endif
diff --git a/contrib/libs/cxxsupp/libcxx/src/support/win32/new_win32.cpp b/contrib/libs/cxxsupp/libcxx/src/support/win32/new_win32.cpp
new file mode 100644
index 0000000000..00eff4abf9
--- /dev/null
+++ b/contrib/libs/cxxsupp/libcxx/src/support/win32/new_win32.cpp
@@ -0,0 +1,28 @@
+#include <atomic>
+#include <new>
+
+namespace std {
+
+void
+__throw_bad_alloc()
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ throw bad_alloc();
+#endif
+}
+
+static std::atomic<std::new_handler> __new_handler;
+
+new_handler
+set_new_handler(new_handler handler) _NOEXCEPT
+{
+ return __new_handler.exchange(handler);
+}
+
+new_handler
+get_new_handler() _NOEXCEPT
+{
+ return __new_handler.load();
+}
+
+} \ No newline at end of file
diff --git a/contrib/libs/cxxsupp/libcxx/src/support/win32/support.cpp b/contrib/libs/cxxsupp/libcxx/src/support/win32/support.cpp
new file mode 100644
index 0000000000..dbec4083cb
--- /dev/null
+++ b/contrib/libs/cxxsupp/libcxx/src/support/win32/support.cpp
@@ -0,0 +1,172 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdarg> // va_start, va_end
+#include <cstddef> // size_t
+#include <cstdlib> // malloc
+#include <cstdio> // vsprintf, vsnprintf
+#include <cstring> // strcpy, wcsncpy
+#include <cwchar> // mbstate_t
+
+
+// Like sprintf, but when return value >= 0 it returns
+// a pointer to a malloc'd string in *sptr.
+// If return >= 0, use free to delete *sptr.
+int __libcpp_vasprintf( char **sptr, const char *__restrict format, va_list ap )
+{
+ *sptr = NULL;
+ // Query the count required.
+ va_list ap_copy;
+ va_copy(ap_copy, ap);
+ _LIBCPP_DIAGNOSTIC_PUSH
+ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
+ int count = vsnprintf( NULL, 0, format, ap_copy );
+ _LIBCPP_DIAGNOSTIC_POP
+ va_end(ap_copy);
+ if (count < 0)
+ return count;
+ size_t buffer_size = static_cast<size_t>(count) + 1;
+ char* p = static_cast<char*>(malloc(buffer_size));
+ if ( ! p )
+ return -1;
+ // If we haven't used exactly what was required, something is wrong.
+ // Maybe bug in vsnprintf. Report the error and return.
+ _LIBCPP_DIAGNOSTIC_PUSH
+ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
+ if (vsnprintf(p, buffer_size, format, ap) != count) {
+ _LIBCPP_DIAGNOSTIC_POP
+ free(p);
+ return -1;
+ }
+ // All good. This is returning memory to the caller not freeing it.
+ *sptr = p;
+ return count;
+}
+
+// Returns >= 0: the number of wide characters found in the
+// multi byte sequence src (of src_size_bytes), that fit in the buffer dst
+// (of max_dest_chars elements size). The count returned excludes the
+// null terminator. When dst is NULL, no characters are copied
+// and no "out" parameters are updated.
+// Returns (size_t) -1: an incomplete sequence encountered.
+// Leaves *src pointing the next character to convert or NULL
+// if a null character was converted from *src.
+size_t mbsnrtowcs( wchar_t *__restrict dst, const char **__restrict src,
+ size_t src_size_bytes, size_t max_dest_chars, mbstate_t *__restrict ps )
+{
+ const size_t terminated_sequence = static_cast<size_t>(0);
+ //const size_t invalid_sequence = static_cast<size_t>(-1);
+ const size_t incomplete_sequence = static_cast< size_t>(-2);
+
+ size_t dest_converted = 0;
+ size_t source_converted = 0;
+ size_t source_remaining = src_size_bytes;
+ size_t result = 0;
+ bool have_result = false;
+
+ // If dst is null then max_dest_chars should be ignored according to the
+ // standard. Setting max_dest_chars to a large value has this effect.
+ if (!dst)
+ max_dest_chars = static_cast<size_t>(-1);
+
+ while ( source_remaining ) {
+ if ( dst && dest_converted >= max_dest_chars )
+ break;
+ // Converts one multi byte character.
+ // if result > 0, it's the size in bytes of that character.
+ // othewise if result is zero it indicates the null character has been found.
+ // otherwise it's an error and errno may be set.
+ size_t char_size = mbrtowc( dst ? dst + dest_converted : NULL, *src + source_converted, source_remaining, ps );
+ // Don't do anything to change errno from here on.
+ if ( char_size > 0 ) {
+ source_remaining -= char_size;
+ source_converted += char_size;
+ ++dest_converted;
+ continue;
+ }
+ result = char_size;
+ have_result = true;
+ break;
+ }
+ if ( dst ) {
+ if ( have_result && result == terminated_sequence )
+ *src = NULL;
+ else
+ *src += source_converted;
+ }
+ if ( have_result && result != terminated_sequence && result != incomplete_sequence )
+ return static_cast<size_t>(-1);
+
+ return dest_converted;
+}
+
+// Converts max_source_chars from the wide character buffer pointer to by *src,
+// into the multi byte character sequence buffer stored at dst which must be
+// dst_size_bytes bytes in size.
+// Returns >= 0: the number of bytes in the sequence
+// converted from *src, excluding the null terminator.
+// Returns size_t(-1) if an error occurs, also sets errno.
+// If dst is NULL dst_size_bytes is ignored and no bytes are copied to dst
+// and no "out" parameters are updated.
+size_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src,
+ size_t max_source_chars, size_t dst_size_bytes, mbstate_t *__restrict ps )
+{
+ //const size_t invalid_sequence = static_cast<size_t>(-1);
+
+ size_t source_converted = 0;
+ size_t dest_converted = 0;
+ size_t dest_remaining = dst_size_bytes;
+ size_t char_size = 0;
+ const errno_t no_error = ( errno_t) 0;
+ errno_t result = ( errno_t ) 0;
+ bool have_result = false;
+ bool terminator_found = false;
+
+ // If dst is null then dst_size_bytes should be ignored according to the
+ // standard. Setting dest_remaining to a large value has this effect.
+ if (!dst)
+ dest_remaining = static_cast<size_t>(-1);
+
+ while ( source_converted != max_source_chars ) {
+ if ( ! dest_remaining )
+ break;
+ wchar_t c = (*src)[source_converted];
+ if ( dst )
+ result = wcrtomb_s( &char_size, dst + dest_converted, dest_remaining, c, ps);
+ else
+ result = wcrtomb_s( &char_size, NULL, 0, c, ps);
+ // If result is zero there is no error and char_size contains the
+ // size of the multi-byte-sequence converted.
+ // Otherwise result indicates an errno type error.
+ if ( result == no_error ) {
+ if ( c == L'\0' ) {
+ terminator_found = true;
+ break;
+ }
+ ++source_converted;
+ if ( dst )
+ dest_remaining -= char_size;
+ dest_converted += char_size;
+ continue;
+ }
+ have_result = true;
+ break;
+ }
+ if ( dst ) {
+ if ( terminator_found )
+ *src = NULL;
+ else
+ *src = *src + source_converted;
+ }
+ if ( have_result && result != no_error ) {
+ errno = result;
+ return static_cast<size_t>(-1);
+ }
+
+ return dest_converted;
+}
diff --git a/contrib/libs/cxxsupp/libcxx/src/support/win32/thread_win32.cpp b/contrib/libs/cxxsupp/libcxx/src/support/win32/thread_win32.cpp
new file mode 100644
index 0000000000..f2072b1435
--- /dev/null
+++ b/contrib/libs/cxxsupp/libcxx/src/support/win32/thread_win32.cpp
@@ -0,0 +1,274 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <__threading_support>
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+#include <fibersapi.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+static_assert(sizeof(__libcpp_mutex_t) == sizeof(SRWLOCK), "");
+static_assert(alignof(__libcpp_mutex_t) == alignof(SRWLOCK), "");
+
+static_assert(sizeof(__libcpp_recursive_mutex_t) == sizeof(CRITICAL_SECTION),
+ "");
+static_assert(alignof(__libcpp_recursive_mutex_t) == alignof(CRITICAL_SECTION),
+ "");
+
+static_assert(sizeof(__libcpp_condvar_t) == sizeof(CONDITION_VARIABLE), "");
+static_assert(alignof(__libcpp_condvar_t) == alignof(CONDITION_VARIABLE), "");
+
+static_assert(sizeof(__libcpp_exec_once_flag) == sizeof(INIT_ONCE), "");
+static_assert(alignof(__libcpp_exec_once_flag) == alignof(INIT_ONCE), "");
+
+static_assert(sizeof(__libcpp_thread_id) == sizeof(DWORD), "");
+static_assert(alignof(__libcpp_thread_id) == alignof(DWORD), "");
+
+static_assert(sizeof(__libcpp_thread_t) == sizeof(HANDLE), "");
+static_assert(alignof(__libcpp_thread_t) == alignof(HANDLE), "");
+
+static_assert(sizeof(__libcpp_tls_key) == sizeof(DWORD), "");
+static_assert(alignof(__libcpp_tls_key) == alignof(DWORD), "");
+
+// Mutex
+int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
+{
+ InitializeCriticalSection((LPCRITICAL_SECTION)__m);
+ return 0;
+}
+
+int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
+{
+ EnterCriticalSection((LPCRITICAL_SECTION)__m);
+ return 0;
+}
+
+bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
+{
+ return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0;
+}
+
+int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
+{
+ LeaveCriticalSection((LPCRITICAL_SECTION)__m);
+ return 0;
+}
+
+int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
+{
+ DeleteCriticalSection((LPCRITICAL_SECTION)__m);
+ return 0;
+}
+
+int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
+{
+ AcquireSRWLockExclusive((PSRWLOCK)__m);
+ return 0;
+}
+
+bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
+{
+ return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0;
+}
+
+int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
+{
+ ReleaseSRWLockExclusive((PSRWLOCK)__m);
+ return 0;
+}
+
+int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
+{
+ static_cast<void>(__m);
+ return 0;
+}
+
+// Condition Variable
+int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
+{
+ WakeConditionVariable((PCONDITION_VARIABLE)__cv);
+ return 0;
+}
+
+int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
+{
+ WakeAllConditionVariable((PCONDITION_VARIABLE)__cv);
+ return 0;
+}
+
+int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
+{
+ SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, INFINITE, 0);
+ return 0;
+}
+
+int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
+ __libcpp_timespec_t *__ts)
+{
+ using namespace _VSTD::chrono;
+
+ auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
+ auto abstime =
+ system_clock::time_point(duration_cast<system_clock::duration>(duration));
+ auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
+
+ if (!SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m,
+ timeout_ms.count() > 0 ? timeout_ms.count()
+ : 0,
+ 0))
+ {
+ auto __ec = GetLastError();
+ return __ec == ERROR_TIMEOUT ? ETIMEDOUT : __ec;
+ }
+ return 0;
+}
+
+int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
+{
+ static_cast<void>(__cv);
+ return 0;
+}
+
+// Execute Once
+static inline _LIBCPP_INLINE_VISIBILITY BOOL CALLBACK
+__libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
+ PVOID *__context)
+{
+ static_cast<void>(__init_once);
+ static_cast<void>(__context);
+
+ void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
+ init_routine();
+ return TRUE;
+}
+
+int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
+ void (*__init_routine)(void))
+{
+ if (!InitOnceExecuteOnce((PINIT_ONCE)__flag, __libcpp_init_once_execute_once_thunk,
+ reinterpret_cast<void *>(__init_routine), NULL))
+ return GetLastError();
+ return 0;
+}
+
+// Thread ID
+bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
+ __libcpp_thread_id __rhs)
+{
+ return __lhs == __rhs;
+}
+
+bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
+{
+ return __lhs < __rhs;
+}
+
+// Thread
+struct __libcpp_beginthreadex_thunk_data
+{
+ void *(*__func)(void *);
+ void *__arg;
+};
+
+static inline _LIBCPP_INLINE_VISIBILITY unsigned WINAPI
+__libcpp_beginthreadex_thunk(void *__raw_data)
+{
+ auto *__data =
+ static_cast<__libcpp_beginthreadex_thunk_data *>(__raw_data);
+ auto *__func = __data->__func;
+ void *__arg = __data->__arg;
+ delete __data;
+ return static_cast<unsigned>(reinterpret_cast<uintptr_t>(__func(__arg)));
+}
+
+bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
+ return *__t == 0;
+}
+
+int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
+ void *__arg)
+{
+ auto *__data = new __libcpp_beginthreadex_thunk_data;
+ __data->__func = __func;
+ __data->__arg = __arg;
+
+ *__t = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0,
+ __libcpp_beginthreadex_thunk,
+ __data, 0, nullptr));
+
+ if (*__t)
+ return 0;
+ return GetLastError();
+}
+
+__libcpp_thread_id __libcpp_thread_get_current_id()
+{
+ return GetCurrentThreadId();
+}
+
+__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
+{
+ return GetThreadId(*__t);
+}
+
+int __libcpp_thread_join(__libcpp_thread_t *__t)
+{
+ if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED)
+ return GetLastError();
+ if (!CloseHandle(*__t))
+ return GetLastError();
+ return 0;
+}
+
+int __libcpp_thread_detach(__libcpp_thread_t *__t)
+{
+ if (!CloseHandle(*__t))
+ return GetLastError();
+ return 0;
+}
+
+void __libcpp_thread_yield()
+{
+ SwitchToThread();
+}
+
+void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
+{
+ // round-up to the nearest millisecond
+ chrono::milliseconds __ms = chrono::ceil<chrono::milliseconds>(__ns);
+ // FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx)
+ Sleep(__ms.count());
+}
+
+// Thread Local Storage
+int __libcpp_tls_create(__libcpp_tls_key* __key,
+ void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
+{
+ DWORD index = FlsAlloc(__at_exit);
+ if (index == FLS_OUT_OF_INDEXES)
+ return GetLastError();
+ *__key = index;
+ return 0;
+}
+
+void *__libcpp_tls_get(__libcpp_tls_key __key)
+{
+ return FlsGetValue(__key);
+}
+
+int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
+{
+ if (!FlsSetValue(__key, __p))
+ return GetLastError();
+ return 0;
+}
+
+_LIBCPP_END_NAMESPACE_STD