aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/atomic/src/wait_on_address.cpp
blob: 6f8a165530fb537860030a0b85a2d5763da85377 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * Copyright (c) 2020 Andrey Semashev
 */
/*!
 * \file   wait_on_address.cpp
 *
 * This file contains implementation of runtime detection of \c WaitOnAddress and related APIs on Windows.
 *
 * https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress
 * https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakebyaddresssingle
 * https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakebyaddressall
 */

// Include boost/winapi/config.hpp first to make sure target Windows version is selected by Boost.WinAPI
#include <boost/winapi/config.hpp>

#include <boost/winapi/basic_types.hpp>

#include <boost/atomic/detail/config.hpp>
#include <boost/atomic/detail/link.hpp>
#include <boost/atomic/detail/once_flag.hpp>
#include <boost/atomic/detail/wait_on_address.hpp>

#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM

#include <boost/static_assert.hpp>
#include <boost/memory_order.hpp>
#include <boost/winapi/thread.hpp>
#include <boost/winapi/get_proc_address.hpp>
#include <boost/winapi/dll.hpp>

#include <boost/atomic/detail/core_operations.hpp>

#endif // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM

#include <boost/atomic/detail/header.hpp>

namespace boost {
namespace atomics {
namespace detail {

BOOST_ATOMIC_DECL wait_on_address_t* wait_on_address = NULL;
BOOST_ATOMIC_DECL wake_by_address_t* wake_by_address_single = NULL;
BOOST_ATOMIC_DECL wake_by_address_t* wake_by_address_all = NULL;

#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM

BOOST_ATOMIC_DECL once_flag wait_functions_once_flag = { 2u };

BOOST_ATOMIC_DECL void initialize_wait_functions() BOOST_NOEXCEPT
{
    BOOST_STATIC_ASSERT_MSG(once_flag_operations::is_always_lock_free, "Boost.Atomic unsupported target platform: native atomic operations not implemented for bytes");

    once_flag_operations::storage_type old_val = once_flag_operations::load(wait_functions_once_flag.m_flag, boost::memory_order_acquire);
    while (true)
    {
        if (old_val == 2u)
        {
            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)))
                continue;

            boost::winapi::HMODULE_ kernel_base = boost::winapi::get_module_handle(L"api-ms-win-core-synch-l1-2-0.dll");
            if (BOOST_LIKELY(kernel_base != NULL))
            {
                wait_on_address_t* woa = (wait_on_address_t*)boost::winapi::get_proc_address(kernel_base, "WaitOnAddress");
                if (BOOST_LIKELY(woa != NULL))
                {
                    wake_by_address_t* wbas = (wake_by_address_t*)boost::winapi::get_proc_address(kernel_base, "WakeByAddressSingle");
                    wake_by_address_t* wbaa = (wake_by_address_t*)boost::winapi::get_proc_address(kernel_base, "WakeByAddressAll");

                    if (BOOST_LIKELY(wbas != NULL && wbaa != NULL))
                    {
                        wait_on_address = woa;
                        wake_by_address_single = wbas;
                        wake_by_address_all = wbaa;
                    }
                }
            }

            once_flag_operations::store(wait_functions_once_flag.m_flag, 0u, boost::memory_order_release);
            break;
        }
        else if (old_val == 1u)
        {
            boost::winapi::SwitchToThread();
            old_val = once_flag_operations::load(wait_functions_once_flag.m_flag, boost::memory_order_acquire);
        }
        else
        {
            break;
        }
    }
}

#else // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM

BOOST_ATOMIC_DECL once_flag wait_functions_once_flag = { 0u };

BOOST_ATOMIC_DECL void initialize_wait_functions() BOOST_NOEXCEPT
{
}

#endif // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM

} // namespace detail
} // namespace atomics
} // namespace boost

#include <boost/atomic/detail/footer.hpp>