1 // thread_primitives.cpp
3 // (C) Copyright 2018 Andrey Semashev
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 #include <boost/winapi/config.hpp>
10 #include <boost/winapi/dll.hpp>
11 #include <boost/winapi/time.hpp>
12 #include <boost/winapi/event.hpp>
13 #include <boost/winapi/handles.hpp>
14 #include <boost/winapi/thread_pool.hpp>
16 #include <boost/config.hpp>
17 #include <boost/cstdint.hpp>
18 #include <boost/memory_order.hpp>
19 #include <boost/atomic/atomic.hpp>
20 #include <boost/thread/win32/interlocked_read.hpp>
21 #include <boost/thread/win32/thread_primitives.hpp>
27 #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
29 // Directly use API from Vista and later
30 BOOST_THREAD_DECL
boost::detail::win32::detail::gettickcount64_t gettickcount64
= &::boost::winapi::GetTickCount64
;
32 #else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
43 struct get_tick_count64_state
45 boost::atomic
< uint64_t > ticks
;
46 boost::atomic
< init_state
> init
;
47 boost::winapi::HANDLE_ wait_event
;
48 boost::winapi::HANDLE_ wait_handle
;
51 // Zero-initialized initially
52 BOOST_ALIGNMENT(64) static get_tick_count64_state g_state
;
54 //! Artifical implementation of GetTickCount64
55 ticks_type WINAPI
get_tick_count64()
57 uint64_t old_state
= g_state
.ticks
.load(boost::memory_order_acquire
);
59 uint32_t new_ticks
= boost::winapi::GetTickCount();
61 uint32_t old_ticks
= static_cast< uint32_t >(old_state
& UINT64_C(0x00000000ffffffff));
62 uint64_t new_state
= ((old_state
& UINT64_C(0xffffffff00000000)) + (static_cast< uint64_t >(new_ticks
< old_ticks
) << 32)) | static_cast< uint64_t >(new_ticks
);
64 g_state
.ticks
.store(new_state
, boost::memory_order_release
);
69 //! The function is called periodically in the system thread pool to make sure g_state.ticks is timely updated
70 void NTAPI
refresh_get_tick_count64(boost::winapi::PVOID_
, boost::winapi::BOOLEAN_
)
75 //! Cleanup function to stop get_tick_count64 refreshes
76 void cleanup_get_tick_count64()
78 if (g_state
.wait_handle
)
80 boost::winapi::UnregisterWait(g_state
.wait_handle
);
81 g_state
.wait_handle
= NULL
;
84 if (g_state
.wait_event
)
86 boost::winapi::CloseHandle(g_state
.wait_event
);
87 g_state
.wait_event
= NULL
;
91 ticks_type WINAPI
get_tick_count_init()
93 boost::winapi::HMODULE_ hKernel32
= boost::winapi::GetModuleHandleW(L
"kernel32.dll");
96 boost::detail::win32::detail::gettickcount64_t p
=
97 (boost::detail::win32::detail::gettickcount64_t
)boost::winapi::get_proc_address(hKernel32
, "GetTickCount64");
101 boost::detail::interlocked_write_release((void**)&gettickcount64
, (void*)p
);
106 // No native API available. Use emulation with periodic refreshes to make sure the GetTickCount wrap arounds are properly counted.
107 init_state old_init
= uninitialized
;
108 if (g_state
.init
.compare_exchange_strong(old_init
, in_progress
, boost::memory_order_acq_rel
, boost::memory_order_relaxed
))
110 if (!g_state
.wait_event
)
111 g_state
.wait_event
= boost::winapi::create_anonymous_event(NULL
, false, false);
112 if (g_state
.wait_event
)
114 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_
);
117 std::atexit(&cleanup_get_tick_count64
);
119 boost::detail::interlocked_write_release((void**)&gettickcount64
, (void*)&get_tick_count64
);
120 g_state
.init
.store(initialized
, boost::memory_order_release
);
125 g_state
.init
.store(uninitialized
, boost::memory_order_release
);
129 return get_tick_count64();
134 BOOST_THREAD_DECL
boost::detail::win32::detail::gettickcount64_t gettickcount64
= &get_tick_count_init
;
136 #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
139 } // namespace detail