]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/unix/sysv/linux/futex-internal.h
nptl: Add clockid parameter to futex timed wait calls
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / futex-internal.h
1 /* futex operations for glibc-internal use. Linux version.
2 Copyright (C) 2014-2019 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19 #ifndef FUTEX_INTERNAL_H
20 #define FUTEX_INTERNAL_H
21
22 #include <sysdeps/nptl/futex-internal.h>
23 #include <errno.h>
24 #include <lowlevellock-futex.h>
25 #include <sysdep-cancel.h>
26
27 /* See sysdeps/nptl/futex-internal.h for documentation; this file only
28 contains Linux-specific comments.
29
30 The Linux kernel treats provides absolute timeouts based on the
31 CLOCK_REALTIME clock and relative timeouts measured against the
32 CLOCK_MONOTONIC clock.
33
34 We expect a Linux kernel version of 2.6.22 or more recent (since this
35 version, EINTR is not returned on spurious wake-ups anymore). */
36
37 /* FUTEX_SHARED is always supported by the Linux kernel. */
38 static __always_inline int
39 futex_supports_pshared (int pshared)
40 {
41 if (__glibc_likely (pshared == PTHREAD_PROCESS_PRIVATE))
42 return 0;
43 else if (pshared == PTHREAD_PROCESS_SHARED)
44 return 0;
45 else
46 return EINVAL;
47 }
48
49 /* The Linux kernel supports relative timeouts measured against the
50 CLOCK_MONOTONIC clock. */
51 static __always_inline bool
52 futex_supports_exact_relative_timeouts (void)
53 {
54 return true;
55 }
56
57 /* See sysdeps/nptl/futex-internal.h for details. */
58 static __always_inline int
59 futex_wait (unsigned int *futex_word, unsigned int expected, int private)
60 {
61 int err = lll_futex_timed_wait (futex_word, expected, NULL, private);
62 switch (err)
63 {
64 case 0:
65 case -EAGAIN:
66 case -EINTR:
67 return -err;
68
69 case -ETIMEDOUT: /* Cannot have happened as we provided no timeout. */
70 case -EFAULT: /* Must have been caused by a glibc or application bug. */
71 case -EINVAL: /* Either due to wrong alignment or due to the timeout not
72 being normalized. Must have been caused by a glibc or
73 application bug. */
74 case -ENOSYS: /* Must have been caused by a glibc bug. */
75 /* No other errors are documented at this time. */
76 default:
77 futex_fatal_error ();
78 }
79 }
80
81 /* See sysdeps/nptl/futex-internal.h for details. */
82 static __always_inline int
83 futex_wait_cancelable (unsigned int *futex_word, unsigned int expected,
84 int private)
85 {
86 int oldtype;
87 oldtype = __pthread_enable_asynccancel ();
88 int err = lll_futex_timed_wait (futex_word, expected, NULL, private);
89 __pthread_disable_asynccancel (oldtype);
90 switch (err)
91 {
92 case 0:
93 case -EAGAIN:
94 case -EINTR:
95 return -err;
96
97 case -ETIMEDOUT: /* Cannot have happened as we provided no timeout. */
98 case -EFAULT: /* Must have been caused by a glibc or application bug. */
99 case -EINVAL: /* Either due to wrong alignment or due to the timeout not
100 being normalized. Must have been caused by a glibc or
101 application bug. */
102 case -ENOSYS: /* Must have been caused by a glibc bug. */
103 /* No other errors are documented at this time. */
104 default:
105 futex_fatal_error ();
106 }
107 }
108
109 /* See sysdeps/nptl/futex-internal.h for details. */
110 static __always_inline int
111 futex_reltimed_wait (unsigned int *futex_word, unsigned int expected,
112 const struct timespec *reltime, int private)
113 {
114 int err = lll_futex_timed_wait (futex_word, expected, reltime, private);
115 switch (err)
116 {
117 case 0:
118 case -EAGAIN:
119 case -EINTR:
120 case -ETIMEDOUT:
121 return -err;
122
123 case -EFAULT: /* Must have been caused by a glibc or application bug. */
124 case -EINVAL: /* Either due to wrong alignment or due to the timeout not
125 being normalized. Must have been caused by a glibc or
126 application bug. */
127 case -ENOSYS: /* Must have been caused by a glibc bug. */
128 /* No other errors are documented at this time. */
129 default:
130 futex_fatal_error ();
131 }
132 }
133
134 /* See sysdeps/nptl/futex-internal.h for details. */
135 static __always_inline int
136 futex_reltimed_wait_cancelable (unsigned int *futex_word,
137 unsigned int expected,
138 const struct timespec *reltime, int private)
139 {
140 int oldtype;
141 oldtype = LIBC_CANCEL_ASYNC ();
142 int err = lll_futex_timed_wait (futex_word, expected, reltime, private);
143 LIBC_CANCEL_RESET (oldtype);
144 switch (err)
145 {
146 case 0:
147 case -EAGAIN:
148 case -EINTR:
149 case -ETIMEDOUT:
150 return -err;
151
152 case -EFAULT: /* Must have been caused by a glibc or application bug. */
153 case -EINVAL: /* Either due to wrong alignment or due to the timeout not
154 being normalized. Must have been caused by a glibc or
155 application bug. */
156 case -ENOSYS: /* Must have been caused by a glibc bug. */
157 /* No other errors are documented at this time. */
158 default:
159 futex_fatal_error ();
160 }
161 }
162
163 /* See sysdeps/nptl/futex-internal.h for details. */
164 static __always_inline int
165 futex_abstimed_supported_clockid (clockid_t clockid)
166 {
167 return lll_futex_supported_clockid (clockid);
168 }
169
170 /* See sysdeps/nptl/futex-internal.h for details. */
171 static __always_inline int
172 futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
173 clockid_t clockid,
174 const struct timespec *abstime, int private)
175 {
176 /* Work around the fact that the kernel rejects negative timeout values
177 despite them being valid. */
178 if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
179 return ETIMEDOUT;
180 int err = lll_futex_clock_wait_bitset (futex_word, expected,
181 clockid, abstime,
182 private);
183 switch (err)
184 {
185 case 0:
186 case -EAGAIN:
187 case -EINTR:
188 case -ETIMEDOUT:
189 return -err;
190
191 case -EFAULT: /* Must have been caused by a glibc or application bug. */
192 case -EINVAL: /* Either due to wrong alignment, unsupported
193 clockid or due to the timeout not being
194 normalized. Must have been caused by a glibc or
195 application bug. */
196 case -ENOSYS: /* Must have been caused by a glibc bug. */
197 /* No other errors are documented at this time. */
198 default:
199 futex_fatal_error ();
200 }
201 }
202
203 /* See sysdeps/nptl/futex-internal.h for details. */
204 static __always_inline int
205 futex_abstimed_wait_cancelable (unsigned int *futex_word,
206 unsigned int expected,
207 clockid_t clockid,
208 const struct timespec *abstime, int private)
209 {
210 /* Work around the fact that the kernel rejects negative timeout values
211 despite them being valid. */
212 if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
213 return ETIMEDOUT;
214 int oldtype;
215 oldtype = __pthread_enable_asynccancel ();
216 int err = lll_futex_clock_wait_bitset (futex_word, expected,
217 clockid, abstime,
218 private);
219 __pthread_disable_asynccancel (oldtype);
220 switch (err)
221 {
222 case 0:
223 case -EAGAIN:
224 case -EINTR:
225 case -ETIMEDOUT:
226 return -err;
227
228 case -EFAULT: /* Must have been caused by a glibc or application bug. */
229 case -EINVAL: /* Either due to wrong alignment or due to the timeout not
230 being normalized. Must have been caused by a glibc or
231 application bug. */
232 case -ENOSYS: /* Must have been caused by a glibc bug. */
233 /* No other errors are documented at this time. */
234 default:
235 futex_fatal_error ();
236 }
237 }
238
239 /* See sysdeps/nptl/futex-internal.h for details. */
240 static __always_inline void
241 futex_wake (unsigned int *futex_word, int processes_to_wake, int private)
242 {
243 int res = lll_futex_wake (futex_word, processes_to_wake, private);
244 /* No error. Ignore the number of woken processes. */
245 if (res >= 0)
246 return;
247 switch (res)
248 {
249 case -EFAULT: /* Could have happened due to memory reuse. */
250 case -EINVAL: /* Could be either due to incorrect alignment (a bug in
251 glibc or in the application) or due to memory being
252 reused for a PI futex. We cannot distinguish between the
253 two causes, and one of them is correct use, so we do not
254 act in this case. */
255 return;
256 case -ENOSYS: /* Must have been caused by a glibc bug. */
257 /* No other errors are documented at this time. */
258 default:
259 futex_fatal_error ();
260 }
261 }
262
263 #endif /* futex-internal.h */