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 <kernel-features.h>
23 #include <lowlevellock.h>
27 #ifdef __ASSUME_PRIVATE_FUTEX
28 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
29 movl $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
30 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
31 movl $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
32 # define LOAD_FUTEX_WAIT(reg) \
33 xorl $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
34 # define LOAD_FUTEX_WAIT_ABS(reg) \
35 xorl $(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg
36 # define LOAD_FUTEX_WAKE(reg) \
37 xorl $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
40 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
41 movl %fs:PRIVATE_FUTEX, reg
43 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
44 movl %fs:PRIVATE_FUTEX, reg ; \
47 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
48 movl %fs:PRIVATE_FUTEX, reg ; \
51 # define LOAD_FUTEX_WAIT(reg) \
52 xorl $FUTEX_PRIVATE_FLAG, reg ; \
53 andl %fs:PRIVATE_FUTEX, reg
55 # define LOAD_FUTEX_WAIT(reg) \
56 xorl $FUTEX_PRIVATE_FLAG, reg ; \
57 andl %fs:PRIVATE_FUTEX, reg ; \
60 # define LOAD_FUTEX_WAIT_ABS(reg) \
61 xorl $FUTEX_PRIVATE_FLAG, reg ; \
62 andl %fs:PRIVATE_FUTEX, reg ; \
63 orl $FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg
64 # define LOAD_FUTEX_WAKE(reg) \
65 xorl $FUTEX_PRIVATE_FLAG, reg ; \
66 andl %fs:PRIVATE_FUTEX, reg ; \
71 /* For the calculation see asm/vsyscall.h. */
72 #define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
75 .globl __lll_lock_wait_private
76 .type __lll_lock_wait_private,@function
77 .hidden __lll_lock_wait_private
79 __lll_lock_wait_private:
82 cfi_adjust_cfa_offset(8)
84 cfi_adjust_cfa_offset(8)
87 xorq %r10, %r10 /* No timeout. */
89 LOAD_PRIVATE_FUTEX_WAIT (%esi)
91 cmpl %edx, %eax /* NB: %edx == 2 */
94 1: movl $SYS_futex, %eax
98 xchgl %eax, (%rdi) /* NB: lock is implied */
104 cfi_adjust_cfa_offset(-8)
107 cfi_adjust_cfa_offset(-8)
111 .size __lll_lock_wait_private,.-__lll_lock_wait_private
114 .globl __lll_lock_wait
115 .type __lll_lock_wait,@function
116 .hidden __lll_lock_wait
121 cfi_adjust_cfa_offset(8)
123 cfi_adjust_cfa_offset(8)
124 cfi_offset(%r10, -16)
125 cfi_offset(%rdx, -24)
126 xorq %r10, %r10 /* No timeout. */
128 LOAD_FUTEX_WAIT (%esi)
130 cmpl %edx, %eax /* NB: %edx == 2 */
133 1: movl $SYS_futex, %eax
137 xchgl %eax, (%rdi) /* NB: lock is implied */
143 cfi_adjust_cfa_offset(-8)
146 cfi_adjust_cfa_offset(-8)
150 .size __lll_lock_wait,.-__lll_lock_wait
157 .globl __lll_timedlock_wait
158 .type __lll_timedlock_wait,@function
159 .hidden __lll_timedlock_wait
161 __lll_timedlock_wait:
163 # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
165 cmpl $0, __have_futex_clock_realtime(%rip)
167 cmpl $0, __have_futex_clock_realtime
173 cfi_adjust_cfa_offset(9)
176 movl $0xffffffff, %r9d
177 LOAD_FUTEX_WAIT_ABS (%esi)
183 1: movl $SYS_futex, %eax
187 2: xchgl %edx, (%rdi) /* NB: lock is implied */
192 cmpl $-ETIMEDOUT, %eax
201 cfi_adjust_cfa_offset(-8)
205 # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
207 /* Check for a valid timeout value. */
208 cmpq $1000000000, 8(%rdx)
212 cfi_adjust_cfa_offset(8)
214 cfi_adjust_cfa_offset(8)
216 cfi_adjust_cfa_offset(8)
218 cfi_adjust_cfa_offset(8)
220 cfi_adjust_cfa_offset(8)
223 cfi_offset(%r12, -32)
224 cfi_offset(%r13, -40)
225 cfi_offset(%r14, -48)
227 cfi_adjust_cfa_offset(8)
229 /* Stack frame for the timespec and timeval structs. */
231 cfi_adjust_cfa_offset(24)
243 /* Get current time. */
246 movq $VSYSCALL_ADDR_vgettimeofday, %rax
247 /* This is a regular function call, all caller-save registers
248 might be clobbered. */
251 /* Compute relative timeout. */
254 mul %rdi /* Milli seconds to nano seconds. */
260 addq $1000000000, %rsi
263 js 2f /* Time is already up. */
265 /* Store relative timeout. */
274 LOAD_FUTEX_WAIT (%esi)
276 movl $SYS_futex, %eax
285 cmpl $-ETIMEDOUT, %eax
287 2: movl $ETIMEDOUT, %edx
290 cfi_adjust_cfa_offset(-32)
292 cfi_adjust_cfa_offset(-8)
295 cfi_adjust_cfa_offset(-8)
298 cfi_adjust_cfa_offset(-8)
301 cfi_adjust_cfa_offset(-8)
304 cfi_adjust_cfa_offset(-8)
309 3: movl $EINVAL, %eax
313 .size __lll_timedlock_wait,.-__lll_timedlock_wait
317 .globl __lll_unlock_wake_private
318 .type __lll_unlock_wake_private,@function
319 .hidden __lll_unlock_wake_private
321 __lll_unlock_wake_private:
324 cfi_adjust_cfa_offset(8)
326 cfi_adjust_cfa_offset(8)
327 cfi_offset(%rsi, -16)
328 cfi_offset(%rdx, -24)
331 LOAD_PRIVATE_FUTEX_WAKE (%esi)
332 movl $1, %edx /* Wake one thread. */
333 movl $SYS_futex, %eax
337 cfi_adjust_cfa_offset(-8)
340 cfi_adjust_cfa_offset(-8)
344 .size __lll_unlock_wake_private,.-__lll_unlock_wake_private
347 .globl __lll_unlock_wake
348 .type __lll_unlock_wake,@function
349 .hidden __lll_unlock_wake
354 cfi_adjust_cfa_offset(8)
356 cfi_adjust_cfa_offset(8)
357 cfi_offset(%rsi, -16)
358 cfi_offset(%rdx, -24)
361 LOAD_FUTEX_WAKE (%esi)
362 movl $1, %edx /* Wake one thread. */
363 movl $SYS_futex, %eax
367 cfi_adjust_cfa_offset(-8)
370 cfi_adjust_cfa_offset(-8)
374 .size __lll_unlock_wake,.-__lll_unlock_wake
376 .globl __lll_timedwait_tid
377 .type __lll_timedwait_tid,@function
378 .hidden __lll_timedwait_tid
383 cfi_adjust_cfa_offset(8)
385 cfi_adjust_cfa_offset(8)
386 cfi_offset(%r12, -16)
387 cfi_offset(%r13, -24)
393 cfi_adjust_cfa_offset(16)
395 /* Get current time. */
398 movq $VSYSCALL_ADDR_vgettimeofday, %rax
401 /* Compute relative timeout. */
404 mul %rdi /* Milli seconds to nano seconds. */
410 addq $1000000000, %rsi
413 js 6f /* Time is already up. */
415 movq %rdi, (%rsp) /* Store relative timeout. */
423 /* XXX The kernel so far uses global futex for the wakeup at
428 movl $FUTEX_WAIT, %esi
431 movl $SYS_futex, %eax
439 cfi_adjust_cfa_offset(-16)
441 cfi_adjust_cfa_offset(-8)
444 cfi_adjust_cfa_offset(-8)
448 cfi_adjust_cfa_offset(32)
449 1: cmpq $-ETIMEDOUT, %rax
452 6: movl $ETIMEDOUT, %eax
455 .size __lll_timedwait_tid,.-__lll_timedwait_tid