]>
Commit | Line | Data |
---|---|---|
a2f0363f | 1 | /* futex operations for glibc-internal use. Linux version. |
688903eb | 2 | Copyright (C) 2014-2018 Free Software Foundation, Inc. |
a2f0363f TR |
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 <nptl/pthreadP.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 = __pthread_enable_asynccancel (); | |
142 | int err = lll_futex_timed_wait (futex_word, expected, reltime, private); | |
143 | __pthread_disable_asynccancel (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_wait (unsigned int *futex_word, unsigned int expected, | |
166 | const struct timespec *abstime, int private) | |
167 | { | |
168 | /* Work around the fact that the kernel rejects negative timeout values | |
169 | despite them being valid. */ | |
170 | if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0))) | |
171 | return ETIMEDOUT; | |
172 | int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime, | |
173 | FUTEX_CLOCK_REALTIME, private); | |
174 | switch (err) | |
175 | { | |
176 | case 0: | |
177 | case -EAGAIN: | |
178 | case -EINTR: | |
179 | case -ETIMEDOUT: | |
180 | return -err; | |
181 | ||
182 | case -EFAULT: /* Must have been caused by a glibc or application bug. */ | |
183 | case -EINVAL: /* Either due to wrong alignment or due to the timeout not | |
184 | being normalized. Must have been caused by a glibc or | |
185 | application bug. */ | |
186 | case -ENOSYS: /* Must have been caused by a glibc bug. */ | |
187 | /* No other errors are documented at this time. */ | |
188 | default: | |
189 | futex_fatal_error (); | |
190 | } | |
191 | } | |
192 | ||
193 | /* See sysdeps/nptl/futex-internal.h for details. */ | |
194 | static __always_inline int | |
195 | futex_abstimed_wait_cancelable (unsigned int *futex_word, | |
196 | unsigned int expected, | |
be3c0fe8 | 197 | const struct timespec *abstime, int clockbit, int private) |
a2f0363f TR |
198 | { |
199 | /* Work around the fact that the kernel rejects negative timeout values | |
200 | despite them being valid. */ | |
201 | if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0))) | |
202 | return ETIMEDOUT; | |
203 | int oldtype; | |
204 | oldtype = __pthread_enable_asynccancel (); | |
205 | int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime, | |
be3c0fe8 | 206 | clockbit, private); |
a2f0363f TR |
207 | __pthread_disable_asynccancel (oldtype); |
208 | switch (err) | |
209 | { | |
210 | case 0: | |
211 | case -EAGAIN: | |
212 | case -EINTR: | |
213 | case -ETIMEDOUT: | |
214 | return -err; | |
215 | ||
216 | case -EFAULT: /* Must have been caused by a glibc or application bug. */ | |
217 | case -EINVAL: /* Either due to wrong alignment or due to the timeout not | |
218 | being normalized. Must have been caused by a glibc or | |
219 | application bug. */ | |
220 | case -ENOSYS: /* Must have been caused by a glibc bug. */ | |
221 | /* No other errors are documented at this time. */ | |
222 | default: | |
223 | futex_fatal_error (); | |
224 | } | |
225 | } | |
226 | ||
227 | /* See sysdeps/nptl/futex-internal.h for details. */ | |
228 | static __always_inline void | |
229 | futex_wake (unsigned int *futex_word, int processes_to_wake, int private) | |
230 | { | |
231 | int res = lll_futex_wake (futex_word, processes_to_wake, private); | |
232 | /* No error. Ignore the number of woken processes. */ | |
233 | if (res >= 0) | |
234 | return; | |
235 | switch (res) | |
236 | { | |
237 | case -EFAULT: /* Could have happened due to memory reuse. */ | |
238 | case -EINVAL: /* Could be either due to incorrect alignment (a bug in | |
239 | glibc or in the application) or due to memory being | |
240 | reused for a PI futex. We cannot distinguish between the | |
241 | two causes, and one of them is correct use, so we do not | |
242 | act in this case. */ | |
243 | return; | |
244 | case -ENOSYS: /* Must have been caused by a glibc bug. */ | |
245 | /* No other errors are documented at this time. */ | |
246 | default: | |
247 | futex_fatal_error (); | |
248 | } | |
249 | } | |
250 | ||
251 | #endif /* futex-internal.h */ |