Use futex on OpenBSD
[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 */
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
e9af364c
BS
34#elif defined(__OpenBSD__)
35
36#include <sys/time.h>
37#include <sys/futex.h>
38
d428afc4
MD
39#endif
40
36bc70a8
MD
41#ifdef __cplusplus
42extern "C" {
67ecffc0 43#endif
36bc70a8 44
e9af364c 45#ifndef __OpenBSD__
49617de1
MD
46#define FUTEX_WAIT 0
47#define FUTEX_WAKE 1
e9af364c 48#endif
49617de1
MD
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.
b0a841b4
MD
59 *
60 * BEWARE: sys_futex() FUTEX_WAIT may return early if interrupted
61 * (returns EINTR).
49617de1
MD
62 */
63
42dfe454
MD
64extern int compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
65 const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
66extern int compat_futex_async(int32_t *uaddr, int op, int32_t val,
67 const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
68
0afb29b2 69#if (defined(__linux__) && defined(__NR_futex))
ca91060e 70
42dfe454
MD
71static 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
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,
a142df4e
MJ
117 const struct timespec *timeout,
118 int32_t *uaddr2 __attribute__((unused)),
119 int32_t val3 __attribute__((unused)))
32146086
AX
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
150static 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
e9af364c
BS
156#elif defined(__OpenBSD__)
157
158static 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
172static 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
bb109fb6
MJ
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 */
193static 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
199static 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
49617de1 205#else
42dfe454
MD
206
207static 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
213static 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
49617de1
MD
219#endif
220
67ecffc0 221#ifdef __cplusplus
36bc70a8
MD
222}
223#endif
224
49617de1 225#endif /* _URCU_FUTEX_H */
This page took 0.056988 seconds and 4 git commands to generate.