]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/src/win32/thread_primitives.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / thread / src / win32 / thread_primitives.cpp
1 // thread_primitives.cpp
2 //
3 // (C) Copyright 2018 Andrey Semashev
4 //
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)
8
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>
15 #include <cstdlib>
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>
22
23 namespace boost {
24 namespace detail {
25 namespace win32 {
26
27 #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
28
29 // Directly use API from Vista and later
30 BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &::boost::winapi::GetTickCount64;
31
32 #else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
33
34 namespace {
35
36 enum init_state
37 {
38 uninitialized = 0,
39 in_progress,
40 initialized
41 };
42
43 struct get_tick_count64_state
44 {
45 boost::atomic< uint64_t > ticks;
46 boost::atomic< init_state > init;
47 boost::winapi::HANDLE_ wait_event;
48 boost::winapi::HANDLE_ wait_handle;
49 };
50
51 // Zero-initialized initially
52 BOOST_ALIGNMENT(64) static get_tick_count64_state g_state;
53
54 //! Artifical implementation of GetTickCount64
55 ticks_type WINAPI get_tick_count64()
56 {
57 uint64_t old_state = g_state.ticks.load(boost::memory_order_acquire);
58
59 uint32_t new_ticks = boost::winapi::GetTickCount();
60
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);
63
64 g_state.ticks.store(new_state, boost::memory_order_release);
65
66 return new_state;
67 }
68
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_)
71 {
72 get_tick_count64();
73 }
74
75 //! Cleanup function to stop get_tick_count64 refreshes
76 void cleanup_get_tick_count64()
77 {
78 if (g_state.wait_handle)
79 {
80 boost::winapi::UnregisterWait(g_state.wait_handle);
81 g_state.wait_handle = NULL;
82 }
83
84 if (g_state.wait_event)
85 {
86 boost::winapi::CloseHandle(g_state.wait_event);
87 g_state.wait_event = NULL;
88 }
89 }
90
91 ticks_type WINAPI get_tick_count_init()
92 {
93 boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
94 if (hKernel32)
95 {
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"
108 #endif
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
113 #endif
114 if (p)
115 {
116 // Use native API
117 boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)p);
118 return p();
119 }
120 }
121
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))
125 {
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)
129 {
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_);
131 if (res)
132 {
133 std::atexit(&cleanup_get_tick_count64);
134
135 boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)&get_tick_count64);
136 g_state.init.store(initialized, boost::memory_order_release);
137 goto finish;
138 }
139 }
140
141 g_state.init.store(uninitialized, boost::memory_order_release);
142 }
143
144 finish:
145 return get_tick_count64();
146 }
147
148 } // namespace
149
150 BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &get_tick_count_init;
151
152 #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
153
154 } // namespace win32
155 } // namespace detail
156 } // namespace boost