1 /* Copyright (C) 2002-2006, 2007, 2009 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 #include <pthread-errnos.h>
22 #include <bits/kernel-features.h>
23 #include <lowlevellock.h>
24 #include <tcb-offsets.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 %fs:PRIVATE_FUTEX, reg
44 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
45 movl %fs:PRIVATE_FUTEX, reg ; \
48 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
49 movl %fs:PRIVATE_FUTEX, reg ; \
52 # define LOAD_FUTEX_WAIT(reg) \
53 xorl $FUTEX_PRIVATE_FLAG, reg ; \
54 andl %fs:PRIVATE_FUTEX, reg
56 # define LOAD_FUTEX_WAIT(reg) \
57 xorl $FUTEX_PRIVATE_FLAG, reg ; \
58 andl %fs:PRIVATE_FUTEX, reg ; \
61 # define LOAD_FUTEX_WAIT_ABS(reg) \
62 xorl $FUTEX_PRIVATE_FLAG, reg ; \
63 andl %fs: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 %fs:PRIVATE_FUTEX, reg ; \
72 /* For the calculation see asm/vsyscall.h. */
73 #define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
76 .globl __lll_lock_wait_private
77 .type __lll_lock_wait_private,@function
78 .hidden __lll_lock_wait_private
80 __lll_lock_wait_private:
83 cfi_adjust_cfa_offset(8)
85 cfi_adjust_cfa_offset(8)
88 xorq %r10, %r10 /* No timeout. */
90 LOAD_PRIVATE_FUTEX_WAIT (%esi)
92 cmpl %edx, %eax /* NB: %edx == 2 */
95 1: movl $SYS_futex, %eax
99 xchgl %eax, (%rdi) /* NB: lock is implied */
105 cfi_adjust_cfa_offset(-8)
108 cfi_adjust_cfa_offset(-8)
112 .size __lll_lock_wait_private,.-__lll_lock_wait_private
115 .globl __lll_lock_wait
116 .type __lll_lock_wait,@function
117 .hidden __lll_lock_wait
122 cfi_adjust_cfa_offset(8)
124 cfi_adjust_cfa_offset(8)
125 cfi_offset(%r10, -16)
126 cfi_offset(%rdx, -24)
127 xorq %r10, %r10 /* No timeout. */
129 LOAD_FUTEX_WAIT (%esi)
131 cmpl %edx, %eax /* NB: %edx == 2 */
134 1: movl $SYS_futex, %eax
138 xchgl %eax, (%rdi) /* NB: lock is implied */
144 cfi_adjust_cfa_offset(-8)
147 cfi_adjust_cfa_offset(-8)
151 .size __lll_lock_wait,.-__lll_lock_wait
158 .globl __lll_timedlock_wait
159 .type __lll_timedlock_wait,@function
160 .hidden __lll_timedlock_wait
162 __lll_timedlock_wait:
164 # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
166 cmpl $0, __have_futex_clock_realtime(%rip)
168 cmpl $0, __have_futex_clock_realtime
174 cfi_adjust_cfa_offset(8)
175 cfi_rel_offset(%r9, 0)
177 movl $0xffffffff, %r9d
178 LOAD_FUTEX_WAIT_ABS (%esi)
184 1: movl $SYS_futex, %eax
188 2: xchgl %edx, (%rdi) /* NB: lock is implied */
193 cmpl $-ETIMEDOUT, %eax
202 cfi_adjust_cfa_offset(-8)
206 # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
208 /* Check for a valid timeout value. */
209 cmpq $1000000000, 8(%rdx)
213 cfi_adjust_cfa_offset(8)
215 cfi_adjust_cfa_offset(8)
217 cfi_adjust_cfa_offset(8)
219 cfi_adjust_cfa_offset(8)
221 cfi_adjust_cfa_offset(8)
224 cfi_offset(%r12, -32)
225 cfi_offset(%r13, -40)
226 cfi_offset(%r14, -48)
228 cfi_adjust_cfa_offset(8)
230 /* Stack frame for the timespec and timeval structs. */
232 cfi_adjust_cfa_offset(24)
244 /* Get current time. */
247 movq $VSYSCALL_ADDR_vgettimeofday, %rax
248 /* This is a regular function call, all caller-save registers
249 might be clobbered. */
252 /* Compute relative timeout. */
255 mul %rdi /* Milli seconds to nano seconds. */
261 addq $1000000000, %rsi
264 js 2f /* Time is already up. */
266 /* Store relative timeout. */
275 LOAD_FUTEX_WAIT (%esi)
277 movl $SYS_futex, %eax
286 cmpl $-ETIMEDOUT, %eax
288 2: movl $ETIMEDOUT, %edx
291 cfi_adjust_cfa_offset(-32)
293 cfi_adjust_cfa_offset(-8)
296 cfi_adjust_cfa_offset(-8)
299 cfi_adjust_cfa_offset(-8)
302 cfi_adjust_cfa_offset(-8)
305 cfi_adjust_cfa_offset(-8)
310 3: movl $EINVAL, %eax
314 .size __lll_timedlock_wait,.-__lll_timedlock_wait
318 .globl __lll_unlock_wake_private
319 .type __lll_unlock_wake_private,@function
320 .hidden __lll_unlock_wake_private
322 __lll_unlock_wake_private:
325 cfi_adjust_cfa_offset(8)
327 cfi_adjust_cfa_offset(8)
328 cfi_offset(%rsi, -16)
329 cfi_offset(%rdx, -24)
332 LOAD_PRIVATE_FUTEX_WAKE (%esi)
333 movl $1, %edx /* Wake one thread. */
334 movl $SYS_futex, %eax
338 cfi_adjust_cfa_offset(-8)
341 cfi_adjust_cfa_offset(-8)
345 .size __lll_unlock_wake_private,.-__lll_unlock_wake_private
348 .globl __lll_unlock_wake
349 .type __lll_unlock_wake,@function
350 .hidden __lll_unlock_wake
355 cfi_adjust_cfa_offset(8)
357 cfi_adjust_cfa_offset(8)
358 cfi_offset(%rsi, -16)
359 cfi_offset(%rdx, -24)
362 LOAD_FUTEX_WAKE (%esi)
363 movl $1, %edx /* Wake one thread. */
364 movl $SYS_futex, %eax
368 cfi_adjust_cfa_offset(-8)
371 cfi_adjust_cfa_offset(-8)
375 .size __lll_unlock_wake,.-__lll_unlock_wake
377 .globl __lll_timedwait_tid
378 .type __lll_timedwait_tid,@function
379 .hidden __lll_timedwait_tid
384 cfi_adjust_cfa_offset(8)
386 cfi_adjust_cfa_offset(8)
387 cfi_offset(%r12, -16)
388 cfi_offset(%r13, -24)
394 cfi_adjust_cfa_offset(16)
396 /* Get current time. */
399 movq $VSYSCALL_ADDR_vgettimeofday, %rax
402 /* Compute relative timeout. */
405 mul %rdi /* Milli seconds to nano seconds. */
411 addq $1000000000, %rsi
414 js 6f /* Time is already up. */
416 movq %rdi, (%rsp) /* Store relative timeout. */
424 /* XXX The kernel so far uses global futex for the wakeup at
429 movl $FUTEX_WAIT, %esi
432 movl $SYS_futex, %eax
440 cfi_adjust_cfa_offset(-16)
442 cfi_adjust_cfa_offset(-8)
445 cfi_adjust_cfa_offset(-8)
449 cfi_adjust_cfa_offset(32)
450 1: cmpq $-ETIMEDOUT, %rax
453 6: movl $ETIMEDOUT, %eax
456 .size __lll_timedwait_tid,.-__lll_timedwait_tid