]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/futex-internal.c
x86: Add seperate non-temporal tunable for memset
[thirdparty/glibc.git] / nptl / futex-internal.c
CommitLineData
323592fd 1/* futex helper functions for glibc-internal use.
dff8da6b 2 Copyright (C) 2020-2024 Free Software Foundation, Inc.
323592fd
LM
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 <https://www.gnu.org/licenses/>. */
18
19#include <errno.h>
20#include <sysdep.h>
21#include <time.h>
22#include <futex-internal.h>
23#include <kernel-features.h>
24
25#ifndef __ASSUME_TIME64_SYSCALLS
26static int
a2b9e1ec
AZ
27__futex_abstimed_wait_common32 (unsigned int* futex_word,
28 unsigned int expected, int op,
29 const struct __timespec64* abstime,
30 int private, bool cancel)
323592fd 31{
50e19ddf
AZ
32 struct timespec ts32, *pts32 = NULL;
33 if (abstime != NULL)
34 {
50e19ddf
AZ
35 ts32 = valid_timespec64_to_timespec (*abstime);
36 pts32 = &ts32;
37 }
323592fd 38
a2b9e1ec
AZ
39 if (cancel)
40 return INTERNAL_SYSCALL_CANCEL (futex, futex_word, op, expected,
41 pts32, NULL /* Unused. */,
42 FUTEX_BITSET_MATCH_ANY);
43 else
44 return INTERNAL_SYSCALL_CALL (futex, futex_word, op, expected,
50e19ddf 45 pts32, NULL /* Unused. */,
323592fd
LM
46 FUTEX_BITSET_MATCH_ANY);
47}
9cb2c923 48#endif /* ! __ASSUME_TIME64_SYSCALLS */
323592fd 49
a2b9e1ec
AZ
50static int
51__futex_abstimed_wait_common64 (unsigned int* futex_word,
b769b0a2 52 unsigned int expected, int op,
a2b9e1ec
AZ
53 const struct __timespec64* abstime,
54 int private, bool cancel)
323592fd 55{
b769b0a2
AZ
56 if (cancel)
57 return INTERNAL_SYSCALL_CANCEL (futex_time64, futex_word, op, expected,
58 abstime, NULL /* Unused. */,
59 FUTEX_BITSET_MATCH_ANY);
60 else
61 return INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op, expected,
7f0d9e61 62 abstime, NULL /* Unused. */,
b769b0a2
AZ
63 FUTEX_BITSET_MATCH_ANY);
64}
65
66static int
67__futex_abstimed_wait_common (unsigned int* futex_word,
68 unsigned int expected, clockid_t clockid,
69 const struct __timespec64* abstime,
70 int private, bool cancel)
71{
323592fd 72 int err;
b769b0a2 73 unsigned int clockbit;
323592fd
LM
74
75 /* Work around the fact that the kernel rejects negative timeout values
76 despite them being valid. */
77 if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
78 return ETIMEDOUT;
79
80 if (! lll_futex_supported_clockid (clockid))
81 return EINVAL;
82
83 clockbit = (clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0;
84 int op = __lll_private_flag (FUTEX_WAIT_BITSET | clockbit, private);
85
b769b0a2
AZ
86#ifdef __ASSUME_TIME64_SYSCALLS
87 err = __futex_abstimed_wait_common64 (futex_word, expected, op, abstime,
88 private, cancel);
89#else
a9acb7b3 90 bool need_time64 = abstime != NULL && !in_int32_t_range (abstime->tv_sec);
b769b0a2
AZ
91 if (need_time64)
92 {
93 err = __futex_abstimed_wait_common64 (futex_word, expected, op, abstime,
94 private, cancel);
95 if (err == -ENOSYS)
96 err = -EOVERFLOW;
97 }
a2b9e1ec 98 else
a2b9e1ec
AZ
99 err = __futex_abstimed_wait_common32 (futex_word, expected, op, abstime,
100 private, cancel);
323592fd
LM
101#endif
102
103 switch (err)
104 {
105 case 0:
106 case -EAGAIN:
107 case -EINTR:
108 case -ETIMEDOUT:
a3e7aead 109 case -EINVAL:
323592fd
LM
110 case -EOVERFLOW: /* Passed absolute timeout uses 64 bit time_t type, but
111 underlying kernel does not support 64 bit time_t futex
112 syscalls. */
113 return -err;
114
115 case -EFAULT: /* Must have been caused by a glibc or application bug. */
323592fd
LM
116 case -ENOSYS: /* Must have been caused by a glibc bug. */
117 /* No other errors are documented at this time. */
118 default:
119 futex_fatal_error ();
120 }
121}
b2cdadde
LM
122
123int
124__futex_abstimed_wait64 (unsigned int* futex_word, unsigned int expected,
125 clockid_t clockid,
126 const struct __timespec64* abstime, int private)
127{
b769b0a2
AZ
128 return __futex_abstimed_wait_common (futex_word, expected, clockid,
129 abstime, private, false);
a2b9e1ec 130}
b5be9ae7 131libc_hidden_def (__futex_abstimed_wait64)
b2cdadde 132
a2b9e1ec
AZ
133int
134__futex_abstimed_wait_cancelable64 (unsigned int* futex_word,
135 unsigned int expected, clockid_t clockid,
136 const struct __timespec64* abstime,
137 int private)
138{
b769b0a2
AZ
139 return __futex_abstimed_wait_common (futex_word, expected, clockid,
140 abstime, private, true);
b2cdadde 141}
b5be9ae7 142libc_hidden_def (__futex_abstimed_wait_cancelable64)
8352b6df
AZ
143
144int
145__futex_lock_pi64 (int *futex_word, clockid_t clockid,
146 const struct __timespec64 *abstime, int private)
147{
148 int err;
149
150 unsigned int clockbit = clockid == CLOCK_REALTIME
151 ? FUTEX_CLOCK_REALTIME : 0;
152 int op_pi2 = __lll_private_flag (FUTEX_LOCK_PI2 | clockbit, private);
153#if __ASSUME_FUTEX_LOCK_PI2
154 /* Assume __ASSUME_TIME64_SYSCALLS since FUTEX_LOCK_PI2 was added later. */
155 err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op_pi2, 0, abstime);
156#else
157 /* FUTEX_LOCK_PI does not support clock selection, so for CLOCK_MONOTONIC
158 the only option is to use FUTEX_LOCK_PI2. */
159 int op_pi1 = __lll_private_flag (FUTEX_LOCK_PI, private);
160 int op_pi = abstime != NULL && clockid != CLOCK_REALTIME ? op_pi2 : op_pi1;
161
162# ifdef __ASSUME_TIME64_SYSCALLS
163 err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op_pi, 0, abstime);
164# else
a9acb7b3 165 bool need_time64 = abstime != NULL && !in_int32_t_range (abstime->tv_sec);
8352b6df
AZ
166 if (need_time64)
167 err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op_pi, 0, abstime);
168 else
169 {
170 struct timespec ts32, *pts32 = NULL;
171 if (abstime != NULL)
172 {
173 ts32 = valid_timespec64_to_timespec (*abstime);
174 pts32 = &ts32;
175 }
176 err = INTERNAL_SYSCALL_CALL (futex, futex_word, op_pi, 0, pts32);
177 }
178# endif /* __ASSUME_TIME64_SYSCALLS */
179 /* FUTEX_LOCK_PI2 is not available on this kernel. */
180 if (err == -ENOSYS)
181 err = -EINVAL;
182#endif /* __ASSUME_FUTEX_LOCK_PI2 */
183
184 switch (err)
185 {
186 case 0:
187 case -EAGAIN:
188 case -EINTR:
189 case -ETIMEDOUT:
190 case -ESRCH:
191 case -EDEADLK:
192 case -EINVAL: /* This indicates either state corruption or that the kernel
193 found a waiter on futex address which is waiting via
194 FUTEX_WAIT or FUTEX_WAIT_BITSET. This is reported on
195 some futex_lock_pi usage (pthread_mutex_timedlock for
196 instance). */
197 return -err;
198
199 case -EFAULT: /* Must have been caused by a glibc or application bug. */
200 case -ENOSYS: /* Must have been caused by a glibc bug. */
201 /* No other errors are documented at this time. */
202 default:
203 futex_fatal_error ();
204 }
205}