]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | /* |
2 | * Distributed under the Boost Software License, Version 1.0. | |
3 | * (See accompanying file LICENSE_1_0.txt or copy at | |
4 | * http://www.boost.org/LICENSE_1_0.txt) | |
5 | * | |
6 | * Copyright (c) 2020 Andrey Semashev | |
7 | */ | |
8 | /*! | |
1e59de90 | 9 | * \file wait_on_address.cpp |
20effc67 | 10 | * |
1e59de90 | 11 | * This file contains implementation of runtime detection of \c WaitOnAddress and related APIs on Windows. |
20effc67 TL |
12 | * |
13 | * https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress | |
14 | * https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakebyaddresssingle | |
15 | * https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakebyaddressall | |
16 | */ | |
17 | ||
18 | // Include boost/winapi/config.hpp first to make sure target Windows version is selected by Boost.WinAPI | |
19 | #include <boost/winapi/config.hpp> | |
20 | ||
21 | #include <boost/winapi/basic_types.hpp> | |
20effc67 TL |
22 | |
23 | #include <boost/atomic/detail/config.hpp> | |
24 | #include <boost/atomic/detail/link.hpp> | |
25 | #include <boost/atomic/detail/once_flag.hpp> | |
1e59de90 TL |
26 | #include <boost/atomic/detail/wait_on_address.hpp> |
27 | ||
28 | #if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM | |
20effc67 | 29 | |
20effc67 TL |
30 | #include <boost/static_assert.hpp> |
31 | #include <boost/memory_order.hpp> | |
32 | #include <boost/winapi/thread.hpp> | |
33 | #include <boost/winapi/get_proc_address.hpp> | |
34 | #include <boost/winapi/dll.hpp> | |
35 | ||
36 | #include <boost/atomic/detail/core_operations.hpp> | |
1e59de90 TL |
37 | |
38 | #endif // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM | |
20effc67 TL |
39 | |
40 | #include <boost/atomic/detail/header.hpp> | |
41 | ||
42 | namespace boost { | |
43 | namespace atomics { | |
44 | namespace detail { | |
45 | ||
20effc67 TL |
46 | BOOST_ATOMIC_DECL wait_on_address_t* wait_on_address = NULL; |
47 | BOOST_ATOMIC_DECL wake_by_address_t* wake_by_address_single = NULL; | |
48 | BOOST_ATOMIC_DECL wake_by_address_t* wake_by_address_all = NULL; | |
49 | ||
1e59de90 TL |
50 | #if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM |
51 | ||
20effc67 TL |
52 | BOOST_ATOMIC_DECL once_flag wait_functions_once_flag = { 2u }; |
53 | ||
54 | BOOST_ATOMIC_DECL void initialize_wait_functions() BOOST_NOEXCEPT | |
55 | { | |
56 | BOOST_STATIC_ASSERT_MSG(once_flag_operations::is_always_lock_free, "Boost.Atomic unsupported target platform: native atomic operations not implemented for bytes"); | |
57 | ||
58 | once_flag_operations::storage_type old_val = once_flag_operations::load(wait_functions_once_flag.m_flag, boost::memory_order_acquire); | |
59 | while (true) | |
60 | { | |
61 | if (old_val == 2u) | |
62 | { | |
63 | if (BOOST_UNLIKELY(!once_flag_operations::compare_exchange_strong(wait_functions_once_flag.m_flag, old_val, 1u, boost::memory_order_relaxed, boost::memory_order_relaxed))) | |
64 | continue; | |
65 | ||
66 | boost::winapi::HMODULE_ kernel_base = boost::winapi::get_module_handle(L"api-ms-win-core-synch-l1-2-0.dll"); | |
67 | if (BOOST_LIKELY(kernel_base != NULL)) | |
68 | { | |
69 | wait_on_address_t* woa = (wait_on_address_t*)boost::winapi::get_proc_address(kernel_base, "WaitOnAddress"); | |
70 | if (BOOST_LIKELY(woa != NULL)) | |
71 | { | |
72 | wake_by_address_t* wbas = (wake_by_address_t*)boost::winapi::get_proc_address(kernel_base, "WakeByAddressSingle"); | |
73 | wake_by_address_t* wbaa = (wake_by_address_t*)boost::winapi::get_proc_address(kernel_base, "WakeByAddressAll"); | |
74 | ||
75 | if (BOOST_LIKELY(wbas != NULL && wbaa != NULL)) | |
76 | { | |
77 | wait_on_address = woa; | |
78 | wake_by_address_single = wbas; | |
79 | wake_by_address_all = wbaa; | |
80 | } | |
81 | } | |
82 | } | |
83 | ||
84 | once_flag_operations::store(wait_functions_once_flag.m_flag, 0u, boost::memory_order_release); | |
85 | break; | |
86 | } | |
87 | else if (old_val == 1u) | |
88 | { | |
89 | boost::winapi::SwitchToThread(); | |
90 | old_val = once_flag_operations::load(wait_functions_once_flag.m_flag, boost::memory_order_acquire); | |
91 | } | |
92 | else | |
93 | { | |
94 | break; | |
95 | } | |
96 | } | |
97 | } | |
98 | ||
1e59de90 | 99 | #else // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM |
20effc67 TL |
100 | |
101 | BOOST_ATOMIC_DECL once_flag wait_functions_once_flag = { 0u }; | |
102 | ||
103 | BOOST_ATOMIC_DECL void initialize_wait_functions() BOOST_NOEXCEPT | |
104 | { | |
105 | } | |
106 | ||
1e59de90 | 107 | #endif // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM |
20effc67 TL |
108 | |
109 | } // namespace detail | |
110 | } // namespace atomics | |
111 | } // namespace boost | |
112 | ||
113 | #include <boost/atomic/detail/footer.hpp> |