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   atomic/detail/wait_ops_freebsd_umtx.hpp
10  *
11  * This header contains implementation of the waiting/notifying atomic operations based on FreeBSD _umtx_op syscall.
12  * https://www.freebsd.org/cgi/man.cgi?query=_umtx_op&apropos=0&sektion=2&manpath=FreeBSD+11-current&format=html
13  */
14 
15 #ifndef BOOST_ATOMIC_DETAIL_WAIT_OPS_FREEBSD_UMTX_HPP_INCLUDED_
16 #define BOOST_ATOMIC_DETAIL_WAIT_OPS_FREEBSD_UMTX_HPP_INCLUDED_
17 
18 #include <sys/types.h>
19 #include <sys/umtx.h>
20 #include <cstddef>
21 #include <boost/memory_order.hpp>
22 #include <boost/atomic/detail/config.hpp>
23 #include <boost/atomic/detail/int_sizes.hpp>
24 #include <boost/atomic/detail/wait_operations_fwd.hpp>
25 #include <boost/atomic/detail/header.hpp>
26 
27 #ifdef BOOST_HAS_PRAGMA_ONCE
28 #pragma once
29 #endif
30 
31 namespace boost {
32 namespace atomics {
33 namespace detail {
34 
35 #if defined(UMTX_OP_WAIT_UINT) || defined(UMTX_OP_WAIT)
36 
37 template< typename Base >
38 struct wait_operations_freebsd_umtx_common :
39     public Base
40 {
41     typedef Base base_type;
42     typedef typename base_type::storage_type storage_type;
43 
44     static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = true;
45 
has_native_wait_notifyboost::atomics::detail::wait_operations_freebsd_umtx_common46     static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT
47     {
48         return true;
49     }
50 
notify_oneboost::atomics::detail::wait_operations_freebsd_umtx_common51     static BOOST_FORCEINLINE void notify_one(storage_type volatile& storage) BOOST_NOEXCEPT
52     {
53         ::_umtx_op(const_cast< storage_type* >(&storage), UMTX_OP_WAKE, 1u, NULL, NULL);
54     }
55 
notify_allboost::atomics::detail::wait_operations_freebsd_umtx_common56     static BOOST_FORCEINLINE void notify_all(storage_type volatile& storage) BOOST_NOEXCEPT
57     {
58         ::_umtx_op(const_cast< storage_type* >(&storage), UMTX_OP_WAKE, (~static_cast< unsigned int >(0u)) >> 1, NULL, NULL);
59     }
60 };
61 
62 #endif // defined(UMTX_OP_WAIT_UINT) || defined(UMTX_OP_WAIT)
63 
64 // UMTX_OP_WAIT_UINT only appeared in FreeBSD 8.0
65 #if defined(UMTX_OP_WAIT_UINT) && BOOST_ATOMIC_DETAIL_SIZEOF_INT < BOOST_ATOMIC_DETAIL_SIZEOF_LONG
66 
67 template< typename Base, bool Interprocess >
68 struct wait_operations< Base, sizeof(unsigned int), true, Interprocess > :
69     public wait_operations_freebsd_umtx_common< Base >
70 {
71     typedef wait_operations_freebsd_umtx_common< Base > base_type;
72     typedef typename base_type::storage_type storage_type;
73 
waitboost::atomics::detail::wait_operations74     static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order order) BOOST_NOEXCEPT
75     {
76         storage_type new_val = base_type::load(storage, order);
77         while (new_val == old_val)
78         {
79             ::_umtx_op(const_cast< storage_type* >(&storage), UMTX_OP_WAIT_UINT, old_val, NULL, NULL);
80             new_val = base_type::load(storage, order);
81         }
82 
83         return new_val;
84     }
85 };
86 
87 #endif // defined(UMTX_OP_WAIT_UINT) && BOOST_ATOMIC_DETAIL_SIZEOF_INT < BOOST_ATOMIC_DETAIL_SIZEOF_LONG
88 
89 #if defined(UMTX_OP_WAIT)
90 
91 template< typename Base, bool Interprocess >
92 struct wait_operations< Base, sizeof(unsigned long), true, Interprocess > :
93     public wait_operations_freebsd_umtx_common< Base >
94 {
95     typedef wait_operations_freebsd_umtx_common< Base > base_type;
96     typedef typename base_type::storage_type storage_type;
97 
waitboost::atomics::detail::wait_operations98     static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order order) BOOST_NOEXCEPT
99     {
100         storage_type new_val = base_type::load(storage, order);
101         while (new_val == old_val)
102         {
103             ::_umtx_op(const_cast< storage_type* >(&storage), UMTX_OP_WAIT, old_val, NULL, NULL);
104             new_val = base_type::load(storage, order);
105         }
106 
107         return new_val;
108     }
109 };
110 
111 #endif // defined(UMTX_OP_WAIT)
112 
113 } // namespace detail
114 } // namespace atomics
115 } // namespace boost
116 
117 #include <boost/atomic/detail/footer.hpp>
118 
119 #endif // BOOST_ATOMIC_DETAIL_WAIT_OPS_FREEBSD_UMTX_HPP_INCLUDED_
120