Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:33:57

0001 /*
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * http://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * Copyright (c) 2020 Andrey Semashev
0007  */
0008 /*!
0009  * \file   atomic/detail/futex.hpp
0010  *
0011  * This header defines wrappers around futex syscall.
0012  *
0013  * http://man7.org/linux/man-pages/man2/futex.2.html
0014  * https://man.openbsd.org/futex
0015  */
0016 
0017 #ifndef BOOST_ATOMIC_DETAIL_FUTEX_HPP_INCLUDED_
0018 #define BOOST_ATOMIC_DETAIL_FUTEX_HPP_INCLUDED_
0019 
0020 #include <boost/atomic/detail/config.hpp>
0021 
0022 #ifdef BOOST_HAS_PRAGMA_ONCE
0023 #pragma once
0024 #endif
0025 
0026 #if defined(__linux__) || defined(__OpenBSD__) || defined(__NETBSD__) || defined(__NetBSD__)
0027 
0028 #include <sys/syscall.h>
0029 
0030 #if defined(SYS_futex)
0031 #define BOOST_ATOMIC_DETAIL_SYS_FUTEX SYS_futex
0032 #elif defined(SYS_futex_time64)
0033 // On some 32-bit targets (e.g. riscv32) SYS_futex is not defined and instead SYS_futex_time64 is implemented,
0034 // which is equivalent to SYS_futex but uses 64-bit time_t.
0035 #define BOOST_ATOMIC_DETAIL_SYS_FUTEX SYS_futex_time64
0036 #elif defined(__NR_futex)
0037 // Some Android NDKs (Google NDK and older Crystax.NET NDK versions) don't define SYS_futex.
0038 #define BOOST_ATOMIC_DETAIL_SYS_FUTEX __NR_futex
0039 #elif defined(SYS___futex)
0040 // NetBSD defines SYS___futex, which has slightly different parameters. Basically, it has decoupled timeout and val2 parameters:
0041 // int __futex(int *addr1, int op, int val1, const struct timespec *timeout, int *addr2, int val2, int val3);
0042 // https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/sys/syscall.h
0043 // http://bxr.su/NetBSD/sys/kern/sys_futex.c
0044 #define BOOST_ATOMIC_DETAIL_SYS_FUTEX SYS___futex
0045 #define BOOST_ATOMIC_DETAIL_NETBSD_FUTEX
0046 #endif
0047 
0048 #if defined(BOOST_ATOMIC_DETAIL_SYS_FUTEX)
0049 
0050 #include <cstddef>
0051 #if defined(__linux__)
0052 #include <linux/futex.h>
0053 #else
0054 #include <sys/futex.h>
0055 #endif
0056 #include <boost/atomic/detail/intptr.hpp>
0057 #include <boost/atomic/detail/header.hpp>
0058 
0059 #define BOOST_ATOMIC_DETAIL_HAS_FUTEX
0060 
0061 #if defined(FUTEX_PRIVATE_FLAG)
0062 #define BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG FUTEX_PRIVATE_FLAG
0063 #elif defined(__ANDROID__)
0064 // On Android, futex.h is lacking many definitions, but the actual Linux kernel supports the API in full.
0065 #define BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG 128
0066 #else
0067 #define BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG 0
0068 #endif
0069 
0070 namespace boost {
0071 namespace atomics {
0072 namespace detail {
0073 
0074 //! Invokes an operation on the futex
0075 BOOST_FORCEINLINE int futex_invoke(void* addr1, int op, unsigned int val1, const void* timeout = NULL, void* addr2 = NULL, unsigned int val3 = 0) BOOST_NOEXCEPT
0076 {
0077 #if !defined(BOOST_ATOMIC_DETAIL_NETBSD_FUTEX)
0078     return ::syscall(BOOST_ATOMIC_DETAIL_SYS_FUTEX, addr1, op, val1, timeout, addr2, val3);
0079 #else
0080     // Pass 0 in val2.
0081     return ::syscall(BOOST_ATOMIC_DETAIL_SYS_FUTEX, addr1, op, val1, timeout, addr2, 0u, val3);
0082 #endif
0083 }
0084 
0085 //! Invokes an operation on the futex
0086 BOOST_FORCEINLINE int futex_invoke(void* addr1, int op, unsigned int val1, unsigned int val2, void* addr2 = NULL, unsigned int val3 = 0) BOOST_NOEXCEPT
0087 {
0088 #if !defined(BOOST_ATOMIC_DETAIL_NETBSD_FUTEX)
0089     return ::syscall(BOOST_ATOMIC_DETAIL_SYS_FUTEX, addr1, op, val1, static_cast< atomics::detail::uintptr_t >(val2), addr2, val3);
0090 #else
0091     // Pass NULL in timeout.
0092     return ::syscall(BOOST_ATOMIC_DETAIL_SYS_FUTEX, addr1, op, val1, static_cast< void* >(NULL), addr2, val2, val3);
0093 #endif
0094 }
0095 
0096 //! Checks that the value \c pval is \c expected and blocks
0097 BOOST_FORCEINLINE int futex_wait(void* pval, unsigned int expected) BOOST_NOEXCEPT
0098 {
0099     return futex_invoke(pval, FUTEX_WAIT, expected);
0100 }
0101 
0102 //! Checks that the value \c pval is \c expected and blocks
0103 BOOST_FORCEINLINE int futex_wait_private(void* pval, unsigned int expected) BOOST_NOEXCEPT
0104 {
0105     return futex_invoke(pval, FUTEX_WAIT | BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG, expected);
0106 }
0107 
0108 //! Wakes the specified number of threads waiting on the futex
0109 BOOST_FORCEINLINE int futex_signal(void* pval, unsigned int count = 1u) BOOST_NOEXCEPT
0110 {
0111     return futex_invoke(pval, FUTEX_WAKE, count);
0112 }
0113 
0114 //! Wakes the specified number of threads waiting on the futex
0115 BOOST_FORCEINLINE int futex_signal_private(void* pval, unsigned int count = 1u) BOOST_NOEXCEPT
0116 {
0117     return futex_invoke(pval, FUTEX_WAKE | BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG, count);
0118 }
0119 
0120 //! Wakes all threads waiting on the futex
0121 BOOST_FORCEINLINE int futex_broadcast(void* pval) BOOST_NOEXCEPT
0122 {
0123     return futex_signal(pval, (~static_cast< unsigned int >(0u)) >> 1);
0124 }
0125 
0126 //! Wakes all threads waiting on the futex
0127 BOOST_FORCEINLINE int futex_broadcast_private(void* pval) BOOST_NOEXCEPT
0128 {
0129     return futex_signal_private(pval, (~static_cast< unsigned int >(0u)) >> 1);
0130 }
0131 
0132 //! Wakes the wake_count threads waiting on the futex pval1 and requeues up to requeue_count of the blocked threads onto another futex pval2
0133 BOOST_FORCEINLINE int futex_requeue(void* pval1, void* pval2, unsigned int wake_count = 1u, unsigned int requeue_count = (~static_cast< unsigned int >(0u)) >> 1) BOOST_NOEXCEPT
0134 {
0135     return futex_invoke(pval1, FUTEX_REQUEUE, wake_count, requeue_count, pval2);
0136 }
0137 
0138 //! Wakes the wake_count threads waiting on the futex pval1 and requeues up to requeue_count of the blocked threads onto another futex pval2
0139 BOOST_FORCEINLINE int futex_requeue_private(void* pval1, void* pval2, unsigned int wake_count = 1u, unsigned int requeue_count = (~static_cast< unsigned int >(0u)) >> 1) BOOST_NOEXCEPT
0140 {
0141     return futex_invoke(pval1, FUTEX_REQUEUE | BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG, wake_count, requeue_count, pval2);
0142 }
0143 
0144 } // namespace detail
0145 } // namespace atomics
0146 } // namespace boost
0147 
0148 #include <boost/atomic/detail/footer.hpp>
0149 
0150 #endif // defined(BOOST_ATOMIC_DETAIL_SYS_FUTEX)
0151 
0152 #endif // defined(__linux__) || defined(__OpenBSD__) || defined(__NETBSD__) || defined(__NetBSD__)
0153 
0154 #endif // BOOST_ATOMIC_DETAIL_FUTEX_HPP_INCLUDED_