]>
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 | /*! | |
9 | * \file wait_ops_windows.cpp | |
10 | * | |
11 | * This file contains implementation of the waiting/notifying atomic operations on Windows. | |
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> | |
22 | #include <boost/winapi/wait_on_address.hpp> | |
23 | ||
24 | #include <boost/atomic/detail/config.hpp> | |
25 | #include <boost/atomic/detail/link.hpp> | |
26 | #include <boost/atomic/detail/once_flag.hpp> | |
27 | #include <boost/atomic/detail/wait_ops_windows.hpp> | |
28 | ||
29 | #if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_WIN8 | |
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> | |
37 | #endif // BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_WIN8 | |
38 | ||
39 | #include <boost/atomic/detail/header.hpp> | |
40 | ||
41 | namespace boost { | |
42 | namespace atomics { | |
43 | namespace detail { | |
44 | ||
45 | #if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_WIN8 | |
46 | ||
47 | BOOST_ATOMIC_DECL wait_on_address_t* wait_on_address = NULL; | |
48 | BOOST_ATOMIC_DECL wake_by_address_t* wake_by_address_single = NULL; | |
49 | BOOST_ATOMIC_DECL wake_by_address_t* wake_by_address_all = NULL; | |
50 | ||
51 | BOOST_ATOMIC_DECL once_flag wait_functions_once_flag = { 2u }; | |
52 | ||
53 | BOOST_ATOMIC_DECL void initialize_wait_functions() BOOST_NOEXCEPT | |
54 | { | |
55 | BOOST_STATIC_ASSERT_MSG(once_flag_operations::is_always_lock_free, "Boost.Atomic unsupported target platform: native atomic operations not implemented for bytes"); | |
56 | ||
57 | once_flag_operations::storage_type old_val = once_flag_operations::load(wait_functions_once_flag.m_flag, boost::memory_order_acquire); | |
58 | while (true) | |
59 | { | |
60 | if (old_val == 2u) | |
61 | { | |
62 | 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))) | |
63 | continue; | |
64 | ||
65 | boost::winapi::HMODULE_ kernel_base = boost::winapi::get_module_handle(L"api-ms-win-core-synch-l1-2-0.dll"); | |
66 | if (BOOST_LIKELY(kernel_base != NULL)) | |
67 | { | |
68 | wait_on_address_t* woa = (wait_on_address_t*)boost::winapi::get_proc_address(kernel_base, "WaitOnAddress"); | |
69 | if (BOOST_LIKELY(woa != NULL)) | |
70 | { | |
71 | wake_by_address_t* wbas = (wake_by_address_t*)boost::winapi::get_proc_address(kernel_base, "WakeByAddressSingle"); | |
72 | wake_by_address_t* wbaa = (wake_by_address_t*)boost::winapi::get_proc_address(kernel_base, "WakeByAddressAll"); | |
73 | ||
74 | if (BOOST_LIKELY(wbas != NULL && wbaa != NULL)) | |
75 | { | |
76 | wait_on_address = woa; | |
77 | wake_by_address_single = wbas; | |
78 | wake_by_address_all = wbaa; | |
79 | } | |
80 | } | |
81 | } | |
82 | ||
83 | once_flag_operations::store(wait_functions_once_flag.m_flag, 0u, boost::memory_order_release); | |
84 | break; | |
85 | } | |
86 | else if (old_val == 1u) | |
87 | { | |
88 | boost::winapi::SwitchToThread(); | |
89 | old_val = once_flag_operations::load(wait_functions_once_flag.m_flag, boost::memory_order_acquire); | |
90 | } | |
91 | else | |
92 | { | |
93 | break; | |
94 | } | |
95 | } | |
96 | } | |
97 | ||
98 | #else // BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_WIN8 | |
99 | ||
100 | BOOST_ATOMIC_DECL wait_on_address_t* wait_on_address = &boost::winapi::WaitOnAddress; | |
101 | BOOST_ATOMIC_DECL wake_by_address_t* wake_by_address_single = &boost::winapi::WakeByAddressSingle; | |
102 | BOOST_ATOMIC_DECL wake_by_address_t* wake_by_address_all = &boost::winapi::WakeByAddressAll; | |
103 | ||
104 | BOOST_ATOMIC_DECL once_flag wait_functions_once_flag = { 0u }; | |
105 | ||
106 | BOOST_ATOMIC_DECL void initialize_wait_functions() BOOST_NOEXCEPT | |
107 | { | |
108 | } | |
109 | ||
110 | #endif // BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_WIN8 | |
111 | ||
112 | } // namespace detail | |
113 | } // namespace atomics | |
114 | } // namespace boost | |
115 | ||
116 | #include <boost/atomic/detail/footer.hpp> |