Use futex on OpenBSD
[urcu.git] / include / urcu / futex.h
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
29 #elif defined(__FreeBSD__)
30
31 #include <sys/types.h>
32 #include <sys/umtx.h>
33
34 #elif defined(__OpenBSD__)
35
36 #include <sys/time.h>
37 #include <sys/futex.h>
38
39 #endif
40
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44
45 #ifndef __OpenBSD__
46 #define FUTEX_WAIT 0
47 #define FUTEX_WAKE 1
48 #endif
49
50 /*
51 * sys_futex compatibility header.
52 * Use *only* *either of* futex_noasync OR futex_async on a given address.
53 *
54 * futex_noasync cannot be executed in signal handlers, but ensures that
55 * it will be put in a wait queue even in compatibility mode.
56 *
57 * futex_async is signal-handler safe for the wakeup. It uses polling
58 * on the wait-side in compatibility mode.
59 *
60 * BEWARE: sys_futex() FUTEX_WAIT may return early if interrupted
61 * (returns EINTR).
62 */
63
64 extern int compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
65 const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
66 extern int compat_futex_async(int32_t *uaddr, int op, int32_t val,
67 const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
68
69 #if (defined(__linux__) && defined(__NR_futex))
70
71 static inline int futex(int32_t *uaddr, int op, int32_t val,
72 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
73 {
74 return syscall(__NR_futex, uaddr, op, val, timeout,
75 uaddr2, val3);
76 }
77
78 static 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
101 static 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
116 static inline int futex_async(int32_t *uaddr, int op, int32_t val,
117 const struct timespec *timeout,
118 int32_t *uaddr2 __attribute__((unused)),
119 int32_t val3 __attribute__((unused)))
120 {
121 int umtx_op;
122 void *umtx_uaddr = NULL, *umtx_uaddr2 = NULL;
123 struct _umtx_time umtx_timeout = {
124 ._flags = UMTX_ABSTIME,
125 ._clockid = CLOCK_MONOTONIC,
126 };
127
128 switch (op) {
129 case FUTEX_WAIT:
130 /* On FreeBSD, a "u_int" is a 32-bit integer. */
131 umtx_op = UMTX_OP_WAIT_UINT;
132 if (timeout != NULL) {
133 umtx_timeout._timeout = *timeout;
134 umtx_uaddr = (void *) sizeof(umtx_timeout);
135 umtx_uaddr2 = (void *) &umtx_timeout;
136 }
137 break;
138 case FUTEX_WAKE:
139 umtx_op = UMTX_OP_WAKE;
140 break;
141 default:
142 errno = EINVAL;
143 return -1;
144 }
145
146 return _umtx_op(uaddr, umtx_op, (uint32_t) val, umtx_uaddr,
147 umtx_uaddr2);
148 }
149
150 static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
151 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
152 {
153 return futex_async(uaddr, op, val, timeout, uaddr2, val3);
154 }
155
156 #elif defined(__OpenBSD__)
157
158 static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
159 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
160 {
161 int ret;
162
163 ret = futex((volatile uint32_t *) uaddr, op, val, timeout,
164 (volatile uint32_t *) uaddr2);
165 if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
166 return compat_futex_noasync(uaddr, op, val, timeout,
167 uaddr2, val3);
168 }
169 return ret;
170 }
171
172 static inline int futex_async(int32_t *uaddr, int op, int32_t val,
173 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
174 {
175 int ret;
176
177 ret = futex((volatile uint32_t *) uaddr, op, val, timeout,
178 (volatile uint32_t *) uaddr2);
179 if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
180 return compat_futex_async(uaddr, op, val, timeout,
181 uaddr2, val3);
182 }
183 return ret;
184 }
185
186 #elif defined(__CYGWIN__)
187
188 /*
189 * The futex_noasync compat code uses a weak symbol to share state across
190 * different shared object which is not possible on Windows with the
191 * Portable Executable format. Use the async compat code for both cases.
192 */
193 static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
194 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
195 {
196 return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3);
197 }
198
199 static inline int futex_async(int32_t *uaddr, int op, int32_t val,
200 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
201 {
202 return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3);
203 }
204
205 #else
206
207 static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
208 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
209 {
210 return compat_futex_noasync(uaddr, op, val, timeout, uaddr2, val3);
211 }
212
213 static inline int futex_async(int32_t *uaddr, int op, int32_t val,
214 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
215 {
216 return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3);
217 }
218
219 #endif
220
221 #ifdef __cplusplus
222 }
223 #endif
224
225 #endif /* _URCU_FUTEX_H */
This page took 0.034447 seconds and 5 git commands to generate.