Adjust shell script to allow Bash in other locations
[urcu.git] / include / urcu / futex.h
CommitLineData
d3d3857f
MJ
1// SPDX-FileCopyrightText: 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4
49617de1
MD
5#ifndef _URCU_FUTEX_H
6#define _URCU_FUTEX_H
7
8/*
49617de1 9 * Userspace RCU - sys_futex/compat_futex header.
49617de1
MD
10 */
11
12#include <urcu/config.h>
ca91060e
MJ
13#include <urcu/syscall-compat.h>
14
32146086 15#include <errno.h>
6d841bc2 16#include <stdint.h>
6a29bfc1 17#include <time.h>
49617de1 18
d428afc4
MD
19#if (defined(__linux__) && defined(__NR_futex))
20
21/* For backwards compat */
8f44fbdc 22# define CONFIG_RCU_HAVE_FUTEX 1
d428afc4 23
8f44fbdc
MD
24# include <unistd.h>
25# include <errno.h>
26# include <urcu/compiler.h>
27# include <urcu/arch.h>
28# include <urcu/assert.h>
d428afc4
MD
29
30#elif defined(__FreeBSD__)
31
8f44fbdc
MD
32# include <sys/types.h>
33# include <sys/umtx.h>
d428afc4 34
e9af364c
BS
35#elif defined(__OpenBSD__)
36
8f44fbdc
MD
37# include <sys/time.h>
38# include <sys/futex.h>
e9af364c 39
d428afc4
MD
40#endif
41
36bc70a8
MD
42#ifdef __cplusplus
43extern "C" {
67ecffc0 44#endif
36bc70a8 45
e9af364c 46#ifndef __OpenBSD__
8f44fbdc
MD
47# define FUTEX_WAIT 0
48# define FUTEX_WAKE 1
e9af364c 49#endif
49617de1
MD
50
51/*
52 * sys_futex compatibility header.
53 * Use *only* *either of* futex_noasync OR futex_async on a given address.
54 *
55 * futex_noasync cannot be executed in signal handlers, but ensures that
56 * it will be put in a wait queue even in compatibility mode.
57 *
58 * futex_async is signal-handler safe for the wakeup. It uses polling
59 * on the wait-side in compatibility mode.
b0a841b4
MD
60 *
61 * BEWARE: sys_futex() FUTEX_WAIT may return early if interrupted
62 * (returns EINTR).
49617de1
MD
63 */
64
42dfe454
MD
65extern int compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
66 const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
67extern int compat_futex_async(int32_t *uaddr, int op, int32_t val,
68 const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
69
0afb29b2 70#if (defined(__linux__) && defined(__NR_futex))
ca91060e 71
42dfe454
MD
72static inline int futex(int32_t *uaddr, int op, int32_t val,
73 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
74{
e463c38f 75 return syscall(__NR_futex, uaddr, op, val, timeout, uaddr2, val3);
42dfe454
MD
76}
77
78static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
79 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
80{
81 int ret;
82
83 ret = futex(uaddr, op, val, timeout, uaddr2, val3);
84 if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
b2633d21
MD
85 /*
86 * The fallback on ENOSYS is the async-safe version of
87 * the compat futex implementation, because the
88 * async-safe compat implementation allows being used
89 * concurrently with calls to futex(). Indeed, sys_futex
90 * FUTEX_WAIT, on some architectures (mips and parisc),
91 * within a given process, spuriously return ENOSYS due
92 * to signal restart bugs on some kernel versions.
93 */
94 return compat_futex_async(uaddr, op, val, timeout,
42dfe454
MD
95 uaddr2, val3);
96 }
97 return ret;
98
99}
100
101static inline int futex_async(int32_t *uaddr, int op, int32_t val,
102 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
103{
104 int ret;
105
106 ret = futex(uaddr, op, val, timeout, uaddr2, val3);
107 if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
108 return compat_futex_async(uaddr, op, val, timeout,
109 uaddr2, val3);
110 }
111 return ret;
112}
113
32146086
AX
114#elif defined(__FreeBSD__)
115
32146086 116static inline int futex_async(int32_t *uaddr, int op, int32_t val,
e463c38f 117 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
32146086
AX
118{
119 int umtx_op;
120 void *umtx_uaddr = NULL, *umtx_uaddr2 = NULL;
121 struct _umtx_time umtx_timeout = {
122 ._flags = UMTX_ABSTIME,
123 ._clockid = CLOCK_MONOTONIC,
124 };
125
e463c38f
MD
126 /*
127 * Check if NULL or zero. Don't let users expect that they are
128 * taken into account.
129 */
130 urcu_posix_assert(!uaddr2);
131 urcu_posix_assert(!val3);
132
32146086
AX
133 switch (op) {
134 case FUTEX_WAIT:
135 /* On FreeBSD, a "u_int" is a 32-bit integer. */
136 umtx_op = UMTX_OP_WAIT_UINT;
137 if (timeout != NULL) {
138 umtx_timeout._timeout = *timeout;
139 umtx_uaddr = (void *) sizeof(umtx_timeout);
140 umtx_uaddr2 = (void *) &umtx_timeout;
141 }
142 break;
143 case FUTEX_WAKE:
144 umtx_op = UMTX_OP_WAKE;
145 break;
146 default:
147 errno = EINVAL;
148 return -1;
149 }
150
151 return _umtx_op(uaddr, umtx_op, (uint32_t) val, umtx_uaddr,
152 umtx_uaddr2);
153}
154
155static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
156 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
157{
158 return futex_async(uaddr, op, val, timeout, uaddr2, val3);
159}
160
e9af364c
BS
161#elif defined(__OpenBSD__)
162
163static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
164 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
165{
166 int ret;
167
e463c38f
MD
168 /*
169 * Check that val3 is zero. Don't let users expect that it is
170 * taken into account.
171 */
172 urcu_posix_assert(!val3);
173
e9af364c
BS
174 ret = futex((volatile uint32_t *) uaddr, op, val, timeout,
175 (volatile uint32_t *) uaddr2);
176 if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
177 return compat_futex_noasync(uaddr, op, val, timeout,
178 uaddr2, val3);
179 }
180 return ret;
181}
182
183static inline int futex_async(int32_t *uaddr, int op, int32_t val,
184 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
185{
186 int ret;
187
e463c38f
MD
188 /*
189 * Check that val3 is zero. Don't let users expect that it is
190 * taken into account.
191 */
192 urcu_posix_assert(!val3);
193
e9af364c
BS
194 ret = futex((volatile uint32_t *) uaddr, op, val, timeout,
195 (volatile uint32_t *) uaddr2);
196 if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
197 return compat_futex_async(uaddr, op, val, timeout,
198 uaddr2, val3);
199 }
200 return ret;
201}
202
bb109fb6
MJ
203#elif defined(__CYGWIN__)
204
205/*
206 * The futex_noasync compat code uses a weak symbol to share state across
207 * different shared object which is not possible on Windows with the
208 * Portable Executable format. Use the async compat code for both cases.
209 */
210static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
211 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
212{
213 return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3);
214}
215
216static inline int futex_async(int32_t *uaddr, int op, int32_t val,
217 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
218{
219 return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3);
220}
221
49617de1 222#else
42dfe454
MD
223
224static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
225 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
226{
227 return compat_futex_noasync(uaddr, op, val, timeout, uaddr2, val3);
228}
229
230static inline int futex_async(int32_t *uaddr, int op, int32_t val,
231 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
232{
233 return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3);
234}
235
49617de1
MD
236#endif
237
67ecffc0 238#ifdef __cplusplus
36bc70a8
MD
239}
240#endif
241
49617de1 242#endif /* _URCU_FUTEX_H */
This page took 0.06429 seconds and 4 git commands to generate.