futex.h: Indent preprocessor directives
[urcu.git] / include / urcu / futex.h
... / ...
CommitLineData
1// SPDX-FileCopyrightText: 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4
5#ifndef _URCU_FUTEX_H
6#define _URCU_FUTEX_H
7
8/*
9 * Userspace RCU - sys_futex/compat_futex header.
10 */
11
12#include <urcu/config.h>
13#include <urcu/syscall-compat.h>
14
15#include <errno.h>
16#include <stdint.h>
17#include <time.h>
18
19#if (defined(__linux__) && defined(__NR_futex))
20
21/* For backwards compat */
22# define CONFIG_RCU_HAVE_FUTEX 1
23
24# include <unistd.h>
25# include <errno.h>
26# include <urcu/compiler.h>
27# include <urcu/arch.h>
28# include <urcu/assert.h>
29
30#elif defined(__FreeBSD__)
31
32# include <sys/types.h>
33# include <sys/umtx.h>
34
35#elif defined(__OpenBSD__)
36
37# include <sys/time.h>
38# include <sys/futex.h>
39
40#endif
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46#ifndef __OpenBSD__
47# define FUTEX_WAIT 0
48# define FUTEX_WAKE 1
49#endif
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.
60 *
61 * BEWARE: sys_futex() FUTEX_WAIT may return early if interrupted
62 * (returns EINTR).
63 */
64
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
70#if (defined(__linux__) && defined(__NR_futex))
71
72static inline int futex(int32_t *uaddr, int op, int32_t val,
73 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
74{
75 return syscall(__NR_futex, uaddr, op, val, timeout, uaddr2, val3);
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)) {
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,
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
114#elif defined(__FreeBSD__)
115
116static inline int futex_async(int32_t *uaddr, int op, int32_t val,
117 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
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
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
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
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
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
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
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
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
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
222#else
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
236#endif
237
238#ifdef __cplusplus
239}
240#endif
241
242#endif /* _URCU_FUTEX_H */
This page took 0.029366 seconds and 5 git commands to generate.