1 /* Copyright (C) 2002-2018 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
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.
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.
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/>. */
20 #include <pthread-errnos.h>
21 #include <kernel-features.h>
22 #include <lowlevellock.h>
24 #include <stap-probe.h>
28 #ifdef __ASSUME_PRIVATE_FUTEX
29 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
30 movl $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
31 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
32 movl $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
33 # define LOAD_FUTEX_WAIT(reg) \
34 xorl $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
35 # define LOAD_FUTEX_WAIT_ABS(reg) \
36 xorl $(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg
37 # define LOAD_FUTEX_WAKE(reg) \
38 xorl $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
41 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
42 movl %gs:PRIVATE_FUTEX, reg
44 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
45 movl %gs:PRIVATE_FUTEX, reg ; \
48 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
49 movl %gs:PRIVATE_FUTEX, reg ; \
52 # define LOAD_FUTEX_WAIT(reg) \
53 xorl $FUTEX_PRIVATE_FLAG, reg ; \
54 andl %gs:PRIVATE_FUTEX, reg
56 # define LOAD_FUTEX_WAIT(reg) \
57 xorl $FUTEX_PRIVATE_FLAG, reg ; \
58 andl %gs:PRIVATE_FUTEX, reg ; \
61 # define LOAD_FUTEX_WAIT_ABS(reg) \
62 xorl $FUTEX_PRIVATE_FLAG, reg ; \
63 andl %gs:PRIVATE_FUTEX, reg ; \
64 orl $FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg
65 # define LOAD_FUTEX_WAKE(reg) \
66 xorl $FUTEX_PRIVATE_FLAG, reg ; \
67 andl %gs:PRIVATE_FUTEX, reg ; \
71 .globl __lll_lock_wait_private
72 .type __lll_lock_wait_private,@function
73 .hidden __lll_lock_wait_private
75 __lll_lock_wait_private:
78 cfi_adjust_cfa_offset(4)
80 cfi_adjust_cfa_offset(4)
82 cfi_adjust_cfa_offset(4)
89 xorl %esi, %esi /* No timeout. */
90 LOAD_PRIVATE_FUTEX_WAIT (%ecx)
92 cmpl %edx, %eax /* NB: %edx == 2 */
95 1: LIBC_PROBE (lll_lock_wait_private, 1, %ebx)
100 xchgl %eax, (%ebx) /* NB: lock is implied */
106 cfi_adjust_cfa_offset(-4)
109 cfi_adjust_cfa_offset(-4)
112 cfi_adjust_cfa_offset(-4)
116 .size __lll_lock_wait_private,.-__lll_lock_wait_private
119 .globl __lll_lock_wait
120 .type __lll_lock_wait,@function
121 .hidden __lll_lock_wait
126 cfi_adjust_cfa_offset(4)
128 cfi_adjust_cfa_offset(4)
130 cfi_adjust_cfa_offset(4)
132 cfi_offset(%ebx, -12)
133 cfi_offset(%esi, -16)
137 xorl %esi, %esi /* No timeout. */
138 LOAD_FUTEX_WAIT (%ecx)
140 cmpl %edx, %eax /* NB: %edx == 2 */
143 1: movl $SYS_futex, %eax
147 xchgl %eax, (%ebx) /* NB: lock is implied */
153 cfi_adjust_cfa_offset(-4)
156 cfi_adjust_cfa_offset(-4)
159 cfi_adjust_cfa_offset(-4)
163 .size __lll_lock_wait,.-__lll_lock_wait
170 .globl __lll_timedlock_wait
171 .type __lll_timedlock_wait,@function
172 .hidden __lll_timedlock_wait
174 __lll_timedlock_wait:
177 cfi_adjust_cfa_offset(4)
178 cfi_rel_offset(%ebp, 0)
180 cfi_adjust_cfa_offset(4)
181 cfi_rel_offset(%ebx, 0)
183 # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
186 cmpl $0, __have_futex_clock_realtime@GOTOFF(%ebx)
188 cmpl $0, __have_futex_clock_realtime
199 movl $0xffffffff, %ebp
200 LOAD_FUTEX_WAIT_ABS (%ecx)
206 1: movl $SYS_futex, %eax
210 2: xchgl %edx, (%ebx) /* NB: lock is implied */
215 cmpl $-ETIMEDOUT, %eax
224 cfi_adjust_cfa_offset(-4)
227 cfi_adjust_cfa_offset(-4)
231 8: movl $ETIMEDOUT, %eax
234 # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
236 /* Check for a valid timeout value. */
237 cmpl $1000000000, 4(%edx)
241 cfi_adjust_cfa_offset(4)
242 cfi_rel_offset(%esi, 0)
244 cfi_adjust_cfa_offset(4)
245 cfi_rel_offset(%edi, 0)
247 /* Stack frame for the timespec and timeval structs. */
249 cfi_adjust_cfa_offset(8)
261 /* Get current time. */
264 movl $__NR_gettimeofday, %eax
267 /* Compute relative timeout. */
270 mul %edx /* Milli seconds to nano seconds. */
276 addl $1000000000, %edx
279 js 2f /* Time is already up. */
281 /* Store relative timeout. */
290 LOAD_FUTEX_WAIT (%ecx)
291 movl $SYS_futex, %eax
300 cmpl $-ETIMEDOUT, %eax
302 2: movl $ETIMEDOUT, %edx
305 cfi_adjust_cfa_offset(-8)
307 cfi_adjust_cfa_offset(-4)
310 cfi_adjust_cfa_offset(-4)
313 cfi_adjust_cfa_offset(-4)
316 cfi_adjust_cfa_offset(-4)
321 3: movl $EINVAL, %edx
325 .size __lll_timedlock_wait,.-__lll_timedlock_wait
328 .globl __lll_unlock_wake_private
329 .type __lll_unlock_wake_private,@function
330 .hidden __lll_unlock_wake_private
332 __lll_unlock_wake_private:
335 cfi_adjust_cfa_offset(4)
337 cfi_adjust_cfa_offset(4)
339 cfi_adjust_cfa_offset(4)
341 cfi_offset(%ecx, -12)
342 cfi_offset(%edx, -16)
346 LOAD_PRIVATE_FUTEX_WAKE (%ecx)
347 movl $1, %edx /* Wake one thread. */
348 movl $SYS_futex, %eax
352 cfi_adjust_cfa_offset(-4)
355 cfi_adjust_cfa_offset(-4)
358 cfi_adjust_cfa_offset(-4)
362 .size __lll_unlock_wake_private,.-__lll_unlock_wake_private
365 .globl __lll_unlock_wake
366 .type __lll_unlock_wake,@function
367 .hidden __lll_unlock_wake
372 cfi_adjust_cfa_offset(4)
374 cfi_adjust_cfa_offset(4)
376 cfi_adjust_cfa_offset(4)
378 cfi_offset(%ecx, -12)
379 cfi_offset(%edx, -16)
383 LOAD_FUTEX_WAKE (%ecx)
384 movl $1, %edx /* Wake one thread. */
385 movl $SYS_futex, %eax
389 cfi_adjust_cfa_offset(-4)
392 cfi_adjust_cfa_offset(-4)
395 cfi_adjust_cfa_offset(-4)
399 .size __lll_unlock_wake,.-__lll_unlock_wake
401 .globl __lll_timedwait_tid
402 .type __lll_timedwait_tid,@function
403 .hidden __lll_timedwait_tid
415 /* Get current time. */
418 movl $__NR_gettimeofday, %eax
421 /* Compute relative timeout. */
424 mul %edx /* Milli seconds to nano seconds. */
430 addl $1000000000, %edx
433 js 6f /* Time is already up. */
435 movl %ecx, (%esp) /* Store relative timeout. */
443 /* XXX The kernel so far uses global futex for the wakeup at
445 xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
447 movl $SYS_futex, %eax
461 1: cmpl $-ETIMEDOUT, %eax
463 6: movl $ETIMEDOUT, %eax
465 .size __lll_timedwait_tid,.-__lll_timedwait_tid