]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/src/win32/thread_primitives.cpp
update sources to ceph Nautilus 14.2.1
[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 boost::detail::win32::detail::gettickcount64_t p =
97 (boost::detail::win32::detail::gettickcount64_t)boost::winapi::get_proc_address(hKernel32, "GetTickCount64");
98 if (p)
99 {
100 // Use native API
101 boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)p);
102 return p();
103 }
104 }
105
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))
109 {
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)
113 {
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_);
115 if (res)
116 {
117 std::atexit(&cleanup_get_tick_count64);
118
119 boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)&get_tick_count64);
120 g_state.init.store(initialized, boost::memory_order_release);
121 goto finish;
122 }
123 }
124
125 g_state.init.store(uninitialized, boost::memory_order_release);
126 }
127
128 finish:
129 return get_tick_count64();
130 }
131
132 } // namespace
133
134 BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &get_tick_count_init;
135
136 #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
137
138 } // namespace win32
139 } // namespace detail
140 } // namespace boost