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 // GetProcAddress returns a pointer to some function. It can return
97 // pointers to different functions, so it has to return something that is
98 // suitable to store any pointer to function. Microsoft chose FARPROC,
99 // which is int (WINAPI *)() on 32-bit Windows. The user is supposed to
100 // know the signature of the function he requests and perform a cast
101 // (which is a nop on this platform). The result is a pointer to function
102 // with the required signature, which is bitwise equal to what
103 // GetProcAddress returned.
104 // However, gcc >= 8 warns about that.
105 #if defined(BOOST_GCC) && BOOST_GCC >= 80000
106 #pragma GCC diagnostic push
107 #pragma GCC diagnostic ignored "-Wcast-function-type"
109 boost::detail::win32::detail::gettickcount64_t p
=
110 (boost::detail::win32::detail::gettickcount64_t
)boost::winapi::get_proc_address(hKernel32
, "GetTickCount64");
111 #if defined(BOOST_GCC) && BOOST_GCC >= 80000
112 #pragma GCC diagnostic pop
117 boost::detail::interlocked_write_release((void**)&gettickcount64
, (void*)p
);
122 // No native API available. Use emulation with periodic refreshes to make sure the GetTickCount wrap arounds are properly counted.
123 init_state old_init
= uninitialized
;
124 if (g_state
.init
.compare_exchange_strong(old_init
, in_progress
, boost::memory_order_acq_rel
, boost::memory_order_relaxed
))
126 if (!g_state
.wait_event
)
127 g_state
.wait_event
= boost::winapi::create_anonymous_event(NULL
, false, false);
128 if (g_state
.wait_event
)
130 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_
);
133 std::atexit(&cleanup_get_tick_count64
);
135 boost::detail::interlocked_write_release((void**)&gettickcount64
, (void*)&get_tick_count64
);
136 g_state
.init
.store(initialized
, boost::memory_order_release
);
141 g_state
.init
.store(uninitialized
, boost::memory_order_release
);
145 return get_tick_count64();
150 BOOST_THREAD_DECL
boost::detail::win32::detail::gettickcount64_t gettickcount64
= &get_tick_count_init
;
152 #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
155 } // namespace detail