]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/atomic/detail/futex.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / atomic / detail / futex.hpp
CommitLineData
20effc67
TL
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/futex.hpp
10 *
11 * This header defines wrappers around futex syscall.
12 *
13 * http://man7.org/linux/man-pages/man2/futex.2.html
14 * https://man.openbsd.org/futex
15 */
16
17#ifndef BOOST_ATOMIC_DETAIL_FUTEX_HPP_INCLUDED_
18#define BOOST_ATOMIC_DETAIL_FUTEX_HPP_INCLUDED_
19
20#include <boost/atomic/detail/config.hpp>
21
22#ifdef BOOST_HAS_PRAGMA_ONCE
23#pragma once
24#endif
25
26#if defined(__linux__) || defined(__OpenBSD__) || defined(__NETBSD__) || defined(__NetBSD__)
27
28#include <sys/syscall.h>
29
30// Some Android NDKs (Google NDK and older Crystax.NET NDK versions) don't define SYS_futex.
31#if defined(SYS_futex)
32#define BOOST_ATOMIC_DETAIL_SYS_FUTEX SYS_futex
33#elif defined(__NR_futex)
34#define BOOST_ATOMIC_DETAIL_SYS_FUTEX __NR_futex
35#elif defined(SYS___futex)
36// NetBSD defines SYS___futex, which has slightly different parameters. Basically, it has decoupled timeout and val2 parameters:
37// int __futex(int *addr1, int op, int val1, const struct timespec *timeout, int *addr2, int val2, int val3);
38// https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/sys/syscall.h
39// http://bxr.su/NetBSD/sys/kern/sys_futex.c
40#define BOOST_ATOMIC_DETAIL_SYS_FUTEX SYS___futex
41#define BOOST_ATOMIC_DETAIL_NETBSD_FUTEX
42#endif
43
44#if defined(BOOST_ATOMIC_DETAIL_SYS_FUTEX)
45
46#include <cstddef>
47#if defined(__linux__)
48#include <linux/futex.h>
49#else
50#include <sys/futex.h>
51#endif
52#include <boost/atomic/detail/intptr.hpp>
53#include <boost/atomic/detail/header.hpp>
54
55#define BOOST_ATOMIC_DETAIL_HAS_FUTEX
56
57#if defined(FUTEX_PRIVATE_FLAG)
58#define BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG FUTEX_PRIVATE_FLAG
59#else
60#define BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG 0
61#endif
62
63namespace boost {
64namespace atomics {
65namespace detail {
66
67//! Invokes an operation on the futex
68BOOST_FORCEINLINE int futex_invoke(void* addr1, int op, unsigned int val1, const void* timeout = NULL, void* addr2 = NULL, unsigned int val3 = 0) BOOST_NOEXCEPT
69{
70#if !defined(BOOST_ATOMIC_DETAIL_NETBSD_FUTEX)
71 return ::syscall(BOOST_ATOMIC_DETAIL_SYS_FUTEX, addr1, op, val1, timeout, addr2, val3);
72#else
73 // Pass 0 in val2.
74 return ::syscall(BOOST_ATOMIC_DETAIL_SYS_FUTEX, addr1, op, val1, timeout, addr2, 0u, val3);
75#endif
76}
77
78//! Invokes an operation on the futex
79BOOST_FORCEINLINE int futex_invoke(void* addr1, int op, unsigned int val1, unsigned int val2, void* addr2 = NULL, unsigned int val3 = 0) BOOST_NOEXCEPT
80{
81#if !defined(BOOST_ATOMIC_DETAIL_NETBSD_FUTEX)
82 return ::syscall(BOOST_ATOMIC_DETAIL_SYS_FUTEX, addr1, op, val1, static_cast< atomics::detail::uintptr_t >(val2), addr2, val3);
83#else
84 // Pass NULL in timeout.
85 return ::syscall(BOOST_ATOMIC_DETAIL_SYS_FUTEX, addr1, op, val1, static_cast< void* >(NULL), addr2, val2, val3);
86#endif
87}
88
89//! Checks that the value \c pval is \c expected and blocks
90BOOST_FORCEINLINE int futex_wait(void* pval, unsigned int expected) BOOST_NOEXCEPT
91{
92 return futex_invoke(pval, FUTEX_WAIT, expected);
93}
94
95//! Checks that the value \c pval is \c expected and blocks
96BOOST_FORCEINLINE int futex_wait_private(void* pval, unsigned int expected) BOOST_NOEXCEPT
97{
98 return futex_invoke(pval, FUTEX_WAIT | BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG, expected);
99}
100
101//! Wakes the specified number of threads waiting on the futex
102BOOST_FORCEINLINE int futex_signal(void* pval, unsigned int count = 1u) BOOST_NOEXCEPT
103{
104 return futex_invoke(pval, FUTEX_WAKE, count);
105}
106
107//! Wakes the specified number of threads waiting on the futex
108BOOST_FORCEINLINE int futex_signal_private(void* pval, unsigned int count = 1u) BOOST_NOEXCEPT
109{
110 return futex_invoke(pval, FUTEX_WAKE | BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG, count);
111}
112
113//! Wakes all threads waiting on the futex
114BOOST_FORCEINLINE int futex_broadcast(void* pval) BOOST_NOEXCEPT
115{
116 return futex_signal(pval, (~static_cast< unsigned int >(0u)) >> 1);
117}
118
119//! Wakes all threads waiting on the futex
120BOOST_FORCEINLINE int futex_broadcast_private(void* pval) BOOST_NOEXCEPT
121{
122 return futex_signal_private(pval, (~static_cast< unsigned int >(0u)) >> 1);
123}
124
125//! Wakes the wake_count threads waiting on the futex pval1 and requeues up to requeue_count of the blocked threads onto another futex pval2
126BOOST_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
127{
128 return futex_invoke(pval1, FUTEX_REQUEUE, wake_count, requeue_count, pval2);
129}
130
131//! Wakes the wake_count threads waiting on the futex pval1 and requeues up to requeue_count of the blocked threads onto another futex pval2
132BOOST_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
133{
134 return futex_invoke(pval1, FUTEX_REQUEUE | BOOST_ATOMIC_DETAIL_FUTEX_PRIVATE_FLAG, wake_count, requeue_count, pval2);
135}
136
137} // namespace detail
138} // namespace atomics
139} // namespace boost
140
141#include <boost/atomic/detail/footer.hpp>
142
143#endif // defined(BOOST_ATOMIC_DETAIL_SYS_FUTEX)
144
145#endif // defined(__linux__) || defined(__OpenBSD__) || defined(__NETBSD__) || defined(__NetBSD__)
146
147#endif // BOOST_ATOMIC_DETAIL_FUTEX_HPP_INCLUDED_