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) 2021 Andrey Semashev 7 */ 8 /*! 9 * \file atomic/detail/wait_ops_darwin_ulock.hpp 10 * 11 * This header contains implementation of the waiting/notifying atomic operations based on Darwin systems using ulock syscalls. 12 * 13 * https://github.com/apple/darwin-xnu/blob/master/bsd/sys/ulock.h 14 * https://github.com/apple/darwin-xnu/blob/master/bsd/kern/sys_ulock.c 15 */ 16 17 #ifndef BOOST_ATOMIC_DETAIL_WAIT_OPS_DARWIN_ULOCK_HPP_INCLUDED_ 18 #define BOOST_ATOMIC_DETAIL_WAIT_OPS_DARWIN_ULOCK_HPP_INCLUDED_ 19 20 #include <stdint.h> 21 #include <cerrno> 22 #include <boost/memory_order.hpp> 23 #include <boost/atomic/detail/config.hpp> 24 #include <boost/atomic/detail/wait_capabilities.hpp> 25 #include <boost/atomic/detail/wait_operations_fwd.hpp> 26 #include <boost/atomic/detail/header.hpp> 27 28 #ifdef BOOST_HAS_PRAGMA_ONCE 29 #pragma once 30 #endif 31 32 namespace boost { 33 namespace atomics { 34 namespace detail { 35 36 extern "C" { 37 // Timeout is in microseconds with zero meaning no timeout 38 int __ulock_wait(uint32_t operation, void* addr, uint64_t value, uint32_t timeout); 39 #if defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_WAIT2) 40 // Timeout is in nanoseconds with zero meaning no timeout 41 int __ulock_wait2(uint32_t operation, void* addr, uint64_t value, uint64_t timeout, uint64_t value2); 42 #endif // defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_WAIT2) 43 int __ulock_wake(uint32_t operation, void* addr, uint64_t wake_value); 44 } // extern "C" 45 46 enum ulock_op 47 { 48 ulock_op_compare_and_wait = 1, 49 #if defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_SHARED) 50 ulock_op_compare_and_wait_shared = 3, 51 #endif // defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_SHARED) 52 #if defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK64) 53 ulock_op_compare_and_wait64 = 5, 54 #if defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_SHARED) 55 ulock_op_compare_and_wait64_shared = 6, 56 #endif // defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_SHARED) 57 #endif // defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK64) 58 59 // Flags for __ulock_wake 60 ulock_flag_wake_all = 0x00000100, 61 62 // Generic flags 63 ulock_flag_no_errno = 0x01000000 64 }; 65 66 template< typename Base, uint32_t Opcode > 67 struct wait_operations_darwin_ulock_common : 68 public Base 69 { 70 typedef Base base_type; 71 typedef typename base_type::storage_type storage_type; 72 73 static BOOST_CONSTEXPR_OR_CONST bool always_has_native_wait_notify = true; 74 has_native_wait_notifyboost::atomics::detail::wait_operations_darwin_ulock_common75 static BOOST_FORCEINLINE bool has_native_wait_notify(storage_type const volatile&) BOOST_NOEXCEPT 76 { 77 return true; 78 } 79 waitboost::atomics::detail::wait_operations_darwin_ulock_common80 static BOOST_FORCEINLINE storage_type wait(storage_type const volatile& storage, storage_type old_val, memory_order order) BOOST_NOEXCEPT 81 { 82 storage_type new_val = base_type::load(storage, order); 83 while (new_val == old_val) 84 { 85 #if defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_WAIT2) 86 __ulock_wait2(Opcode | ulock_flag_no_errno, const_cast< storage_type* >(&storage), old_val, 0u, 0u); 87 #else 88 __ulock_wait(Opcode | ulock_flag_no_errno, const_cast< storage_type* >(&storage), old_val, 0u); 89 #endif 90 new_val = base_type::load(storage, order); 91 } 92 93 return new_val; 94 } 95 notify_oneboost::atomics::detail::wait_operations_darwin_ulock_common96 static BOOST_FORCEINLINE void notify_one(storage_type volatile& storage) BOOST_NOEXCEPT 97 { 98 while (true) 99 { 100 const int res = __ulock_wake(Opcode | ulock_flag_no_errno, const_cast< storage_type* >(&storage), 0u); 101 if (BOOST_LIKELY(res != -EINTR)) 102 break; 103 } 104 } 105 notify_allboost::atomics::detail::wait_operations_darwin_ulock_common106 static BOOST_FORCEINLINE void notify_all(storage_type volatile& storage) BOOST_NOEXCEPT 107 { 108 while (true) 109 { 110 const int res = __ulock_wake(Opcode | ulock_flag_wake_all | ulock_flag_no_errno, const_cast< storage_type* >(&storage), 0u); 111 if (BOOST_LIKELY(res != -EINTR)) 112 break; 113 } 114 } 115 }; 116 117 template< typename Base > 118 struct wait_operations< Base, sizeof(uint32_t), true, false > : 119 public wait_operations_darwin_ulock_common< Base, ulock_op_compare_and_wait > 120 { 121 }; 122 123 #if defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_SHARED) 124 125 template< typename Base > 126 struct wait_operations< Base, sizeof(uint32_t), true, true > : 127 public wait_operations_darwin_ulock_common< Base, ulock_op_compare_and_wait_shared > 128 { 129 }; 130 131 #endif // defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_SHARED) 132 133 #if defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK64) 134 135 template< typename Base > 136 struct wait_operations< Base, sizeof(uint64_t), true, false > : 137 public wait_operations_darwin_ulock_common< Base, ulock_op_compare_and_wait64 > 138 { 139 }; 140 141 #if defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_SHARED) 142 143 template< typename Base > 144 struct wait_operations< Base, sizeof(uint64_t), true, true > : 145 public wait_operations_darwin_ulock_common< Base, ulock_op_compare_and_wait64_shared > 146 { 147 }; 148 149 #endif // defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK_SHARED) 150 #endif // defined(BOOST_ATOMIC_DETAIL_HAS_DARWIN_ULOCK64) 151 152 } // namespace detail 153 } // namespace atomics 154 } // namespace boost 155 156 #include <boost/atomic/detail/footer.hpp> 157 158 #endif // BOOST_ATOMIC_DETAIL_WAIT_OPS_DARWIN_ULOCK_HPP_INCLUDED_ 159