summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/thread/src/win32/thread_primitives.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/thread/src/win32/thread_primitives.cpp')
-rw-r--r--src/boost/libs/thread/src/win32/thread_primitives.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/boost/libs/thread/src/win32/thread_primitives.cpp b/src/boost/libs/thread/src/win32/thread_primitives.cpp
new file mode 100644
index 000000000..5f6e6f03a
--- /dev/null
+++ b/src/boost/libs/thread/src/win32/thread_primitives.cpp
@@ -0,0 +1,156 @@
+// thread_primitives.cpp
+//
+// (C) Copyright 2018 Andrey Semashev
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/winapi/config.hpp>
+#include <boost/winapi/dll.hpp>
+#include <boost/winapi/time.hpp>
+#include <boost/winapi/event.hpp>
+#include <boost/winapi/handles.hpp>
+#include <boost/winapi/thread_pool.hpp>
+#include <cstdlib>
+#include <boost/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/thread/win32/interlocked_read.hpp>
+#include <boost/thread/win32/thread_primitives.hpp>
+
+namespace boost {
+namespace detail {
+namespace win32 {
+
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+// Directly use API from Vista and later
+BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &::boost::winapi::GetTickCount64;
+
+#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+namespace {
+
+enum init_state
+{
+ uninitialized = 0,
+ in_progress,
+ initialized
+};
+
+struct get_tick_count64_state
+{
+ boost::atomic< uint64_t > ticks;
+ boost::atomic< init_state > init;
+ boost::winapi::HANDLE_ wait_event;
+ boost::winapi::HANDLE_ wait_handle;
+};
+
+// Zero-initialized initially
+BOOST_ALIGNMENT(64) static get_tick_count64_state g_state;
+
+//! Artifical implementation of GetTickCount64
+ticks_type WINAPI get_tick_count64()
+{
+ uint64_t old_state = g_state.ticks.load(boost::memory_order_acquire);
+
+ uint32_t new_ticks = boost::winapi::GetTickCount();
+
+ uint32_t old_ticks = static_cast< uint32_t >(old_state & UINT64_C(0x00000000ffffffff));
+ uint64_t new_state = ((old_state & UINT64_C(0xffffffff00000000)) + (static_cast< uint64_t >(new_ticks < old_ticks) << 32)) | static_cast< uint64_t >(new_ticks);
+
+ g_state.ticks.store(new_state, boost::memory_order_release);
+
+ return new_state;
+}
+
+//! The function is called periodically in the system thread pool to make sure g_state.ticks is timely updated
+void NTAPI refresh_get_tick_count64(boost::winapi::PVOID_, boost::winapi::BOOLEAN_)
+{
+ get_tick_count64();
+}
+
+//! Cleanup function to stop get_tick_count64 refreshes
+void cleanup_get_tick_count64()
+{
+ if (g_state.wait_handle)
+ {
+ boost::winapi::UnregisterWait(g_state.wait_handle);
+ g_state.wait_handle = NULL;
+ }
+
+ if (g_state.wait_event)
+ {
+ boost::winapi::CloseHandle(g_state.wait_event);
+ g_state.wait_event = NULL;
+ }
+}
+
+ticks_type WINAPI get_tick_count_init()
+{
+ boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
+ if (hKernel32)
+ {
+ // GetProcAddress returns a pointer to some function. It can return
+ // pointers to different functions, so it has to return something that is
+ // suitable to store any pointer to function. Microsoft chose FARPROC,
+ // which is int (WINAPI *)() on 32-bit Windows. The user is supposed to
+ // know the signature of the function he requests and perform a cast
+ // (which is a nop on this platform). The result is a pointer to function
+ // with the required signature, which is bitwise equal to what
+ // GetProcAddress returned.
+ // However, gcc >= 8 warns about that.
+#if defined(BOOST_GCC) && BOOST_GCC >= 80000
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+ boost::detail::win32::detail::gettickcount64_t p =
+ (boost::detail::win32::detail::gettickcount64_t)boost::winapi::get_proc_address(hKernel32, "GetTickCount64");
+#if defined(BOOST_GCC) && BOOST_GCC >= 80000
+#pragma GCC diagnostic pop
+#endif
+ if (p)
+ {
+ // Use native API
+ boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)p);
+ return p();
+ }
+ }
+
+ // No native API available. Use emulation with periodic refreshes to make sure the GetTickCount wrap arounds are properly counted.
+ init_state old_init = uninitialized;
+ if (g_state.init.compare_exchange_strong(old_init, in_progress, boost::memory_order_acq_rel, boost::memory_order_relaxed))
+ {
+ if (!g_state.wait_event)
+ g_state.wait_event = boost::winapi::create_anonymous_event(NULL, false, false);
+ if (g_state.wait_event)
+ {
+ boost::winapi::BOOL_ res = boost::winapi::RegisterWaitForSingleObject(&g_state.wait_handle, g_state.wait_event, &refresh_get_tick_count64, NULL, 0x7fffffff, boost::winapi::WT_EXECUTEINWAITTHREAD_);
+ if (res)
+ {
+ std::atexit(&cleanup_get_tick_count64);
+
+ boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)&get_tick_count64);
+ g_state.init.store(initialized, boost::memory_order_release);
+ goto finish;
+ }
+ }
+
+ g_state.init.store(uninitialized, boost::memory_order_release);
+ }
+
+finish:
+ return get_tick_count64();
+}
+
+} // namespace
+
+BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &get_tick_count_init;
+
+#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+} // namespace win32
+} // namespace detail
+} // namespace boost