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 
initialize_wait_functions()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>
117