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  * (C) Copyright 2013 Tim Blechmann
7  * (C) Copyright 2013 Andrey Semashev
8  */
9 /*!
10  * \file   futex.hpp
11  *
12  * \brief  This header is the Boost.Sync library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/sync/doc/html/index.html.
14  *
15  * This header contains Linux futex API declarations.
16  */
17 
18 #ifndef BOOST_SYNC_DETAIL_FUTEX_HPP_INCLUDED_
19 #define BOOST_SYNC_DETAIL_FUTEX_HPP_INCLUDED_
20 
21 #include <stddef.h>
22 #include <limits.h>
23 #include <unistd.h>
24 #include <sys/time.h>
25 #include <sys/syscall.h>
26 #include <linux/futex.h>
27 #include <boost/sync/detail/config.hpp>
28 #include <boost/sync/detail/header.hpp>
29 
30 #ifdef BOOST_HAS_PRAGMA_ONCE
31 #pragma once
32 #endif
33 
34 // Some Android NDKs (Google NDK and older Crystax.NET NDK versions) don't define SYS_futex
35 #if defined(SYS_futex)
36 #define BOOST_SYNC_DETAIL_SYS_FUTEX SYS_futex
37 #else
38 #define BOOST_SYNC_DETAIL_SYS_FUTEX __NR_futex
39 #endif
40 
41 namespace boost {
42 
43 namespace sync {
44 
45 namespace detail {
46 
47 namespace linux_ {
48 
49 //! Invokes an operation on the futex
futex_invoke(int * addr1,int op,int val1,const struct::timespec * timeout=NULL,int * addr2=NULL,int val3=0)50 BOOST_FORCEINLINE int futex_invoke(int* addr1, int op, int val1, const struct ::timespec* timeout = NULL, int* addr2 = NULL, int val3 = 0) BOOST_NOEXCEPT
51 {
52     return ::syscall(BOOST_SYNC_DETAIL_SYS_FUTEX, addr1, op, val1, timeout, addr2, val3);
53 }
54 
55 //! Checks that the value \c pval is \c expected and blocks
futex_wait(int * pval,int expected)56 BOOST_FORCEINLINE int futex_wait(int* pval, int expected) BOOST_NOEXCEPT
57 {
58     return futex_invoke
59     (
60         pval,
61 #ifdef FUTEX_WAIT_PRIVATE
62         FUTEX_WAIT_PRIVATE,
63 #else
64         FUTEX_WAIT,
65 #endif
66         expected
67     );
68 }
69 
70 //! Checks that the value \c pval is \c expected and blocks until \c timeout_nsec expires
futex_timedwait(int * pval,int expected,uint64_t timeout_nsec)71 BOOST_FORCEINLINE int futex_timedwait(int* pval, int expected, uint64_t timeout_nsec) BOOST_NOEXCEPT
72 {
73     struct ::timespec timeout;
74     timeout.tv_sec = timeout_nsec / 1000000000u;
75     timeout.tv_nsec = timeout_nsec % 1000000000u;
76     return futex_invoke
77     (
78         pval,
79 #ifdef FUTEX_WAIT_PRIVATE
80         FUTEX_WAIT_PRIVATE,
81 #else
82         FUTEX_WAIT,
83 #endif
84         expected,
85         &timeout
86     );
87 }
88 
89 //! Wakes all threads waiting on the futex
futex_broadcast(int * pval)90 BOOST_FORCEINLINE int futex_broadcast(int* pval) BOOST_NOEXCEPT
91 {
92     return futex_invoke
93     (
94         pval,
95 #ifdef FUTEX_WAKE_PRIVATE
96         FUTEX_WAKE_PRIVATE,
97 #else
98         FUTEX_WAKE,
99 #endif
100         INT_MAX
101     );
102 }
103 
104 //! Wakes the specified number of threads waiting on the futex
futex_signal(int * pval,int count=1)105 BOOST_FORCEINLINE int futex_signal(int* pval, int count = 1) BOOST_NOEXCEPT
106 {
107     return futex_invoke
108     (
109         pval,
110 #ifdef FUTEX_WAKE_PRIVATE
111         FUTEX_WAKE_PRIVATE,
112 #else
113         FUTEX_WAKE,
114 #endif
115         count
116     );
117 }
118 
119 } // namespace linux_
120 
121 } // namespace detail
122 
123 } // namespace sync
124 
125 } // namespace boost
126 
127 #include <boost/sync/detail/footer.hpp>
128 
129 #endif // BOOST_SYNC_DETAIL_FUTEX_HPP_INCLUDED_
130