1 /* Copyright (C) 2002-2006, 2007 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_WAKE(reg) \
35 xorl $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
38 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
39 movl %fs:PRIVATE_FUTEX, reg
41 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
42 movl %fs:PRIVATE_FUTEX, reg ; \
45 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
46 movl %fs:PRIVATE_FUTEX, reg ; \
49 # define LOAD_FUTEX_WAIT(reg) \
50 xorl $FUTEX_PRIVATE_FLAG, reg ; \
51 andl %fs:PRIVATE_FUTEX, reg
53 # define LOAD_FUTEX_WAIT(reg) \
54 xorl $FUTEX_PRIVATE_FLAG, reg ; \
55 andl %fs:PRIVATE_FUTEX, reg ; \
58 # define LOAD_FUTEX_WAKE(reg) \
59 xorl $FUTEX_PRIVATE_FLAG, reg ; \
60 andl %fs:PRIVATE_FUTEX, reg ; \
65 /* For the calculation see asm/vsyscall.h. */
66 #define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
69 .globl __lll_lock_wait_private
70 .type __lll_lock_wait_private,@function
71 .hidden __lll_lock_wait_private
73 __lll_lock_wait_private:
76 cfi_adjust_cfa_offset(8)
78 cfi_adjust_cfa_offset(8)
81 xorq %r10, %r10 /* No timeout. */
83 LOAD_PRIVATE_FUTEX_WAIT (%esi)
85 cmpl %edx, %eax /* NB: %edx == 2 */
88 1: movl $SYS_futex, %eax
92 xchgl %eax, (%rdi) /* NB: lock is implied */
98 cfi_adjust_cfa_offset(-8)
101 cfi_adjust_cfa_offset(-8)
105 .size __lll_lock_wait_private,.-__lll_lock_wait_private
108 .globl __lll_lock_wait
109 .type __lll_lock_wait,@function
110 .hidden __lll_lock_wait
115 cfi_adjust_cfa_offset(8)
117 cfi_adjust_cfa_offset(8)
118 cfi_offset(%r10, -16)
119 cfi_offset(%rdx, -24)
120 xorq %r10, %r10 /* No timeout. */
122 LOAD_FUTEX_WAIT (%esi)
124 cmpl %edx, %eax /* NB: %edx == 2 */
127 1: movl $SYS_futex, %eax
131 xchgl %eax, (%rdi) /* NB: lock is implied */
137 cfi_adjust_cfa_offset(-8)
140 cfi_adjust_cfa_offset(-8)
144 .size __lll_lock_wait,.-__lll_lock_wait
146 .globl __lll_timedlock_wait
147 .type __lll_timedlock_wait,@function
148 .hidden __lll_timedlock_wait
150 __lll_timedlock_wait:
152 /* Check for a valid timeout value. */
153 cmpq $1000000000, 8(%rdx)
157 cfi_adjust_cfa_offset(8)
159 cfi_adjust_cfa_offset(8)
161 cfi_adjust_cfa_offset(8)
163 cfi_adjust_cfa_offset(8)
165 cfi_adjust_cfa_offset(8)
168 cfi_offset(%r12, -32)
169 cfi_offset(%r13, -40)
170 cfi_offset(%r14, -48)
172 cfi_adjust_cfa_offset(8)
174 /* Stack frame for the timespec and timeval structs. */
176 cfi_adjust_cfa_offset(24)
188 /* Get current time. */
191 movq $VSYSCALL_ADDR_vgettimeofday, %rax
192 /* This is a regular function call, all caller-save registers
193 might be clobbered. */
196 /* Compute relative timeout. */
199 mul %rdi /* Milli seconds to nano seconds. */
205 addq $1000000000, %rsi
208 js 2f /* Time is already up. */
210 /* Store relative timeout. */
219 LOAD_FUTEX_WAIT (%esi)
221 movl $SYS_futex, %eax
230 cmpl $-ETIMEDOUT, %eax
232 2: movl $ETIMEDOUT, %edx
235 cfi_adjust_cfa_offset(-32)
237 cfi_adjust_cfa_offset(-8)
240 cfi_adjust_cfa_offset(-8)
243 cfi_adjust_cfa_offset(-8)
246 cfi_adjust_cfa_offset(-8)
249 cfi_adjust_cfa_offset(-8)
254 3: movl $EINVAL, %eax
257 .size __lll_timedlock_wait,.-__lll_timedlock_wait
261 .globl __lll_unlock_wake_private
262 .type __lll_unlock_wake_private,@function
263 .hidden __lll_unlock_wake_private
265 __lll_unlock_wake_private:
268 cfi_adjust_cfa_offset(8)
270 cfi_adjust_cfa_offset(8)
271 cfi_offset(%rsi, -16)
272 cfi_offset(%rdx, -24)
275 LOAD_PRIVATE_FUTEX_WAKE (%esi)
276 movl $1, %edx /* Wake one thread. */
277 movl $SYS_futex, %eax
281 cfi_adjust_cfa_offset(-8)
284 cfi_adjust_cfa_offset(-8)
288 .size __lll_unlock_wake_private,.-__lll_unlock_wake_private
291 .globl __lll_unlock_wake
292 .type __lll_unlock_wake,@function
293 .hidden __lll_unlock_wake
298 cfi_adjust_cfa_offset(8)
300 cfi_adjust_cfa_offset(8)
301 cfi_offset(%rsi, -16)
302 cfi_offset(%rdx, -24)
305 LOAD_FUTEX_WAKE (%esi)
306 movl $1, %edx /* Wake one thread. */
307 movl $SYS_futex, %eax
311 cfi_adjust_cfa_offset(-8)
314 cfi_adjust_cfa_offset(-8)
318 .size __lll_unlock_wake,.-__lll_unlock_wake
320 .globl __lll_timedwait_tid
321 .type __lll_timedwait_tid,@function
322 .hidden __lll_timedwait_tid
327 cfi_adjust_cfa_offset(8)
329 cfi_adjust_cfa_offset(8)
330 cfi_offset(%r12, -16)
331 cfi_offset(%r13, -24)
337 cfi_adjust_cfa_offset(16)
339 /* Get current time. */
342 movq $VSYSCALL_ADDR_vgettimeofday, %rax
345 /* Compute relative timeout. */
348 mul %rdi /* Milli seconds to nano seconds. */
354 addq $1000000000, %rsi
357 js 6f /* Time is already up. */
359 movq %rdi, (%rsp) /* Store relative timeout. */
367 /* XXX The kernel so far uses global futex for the wakeup at
372 movl $FUTEX_WAIT, %esi
375 movl $SYS_futex, %eax
383 cfi_adjust_cfa_offset(-16)
385 cfi_adjust_cfa_offset(-8)
388 cfi_adjust_cfa_offset(-8)
392 cfi_adjust_cfa_offset(32)
393 1: cmpq $-ETIMEDOUT, %rax
396 6: movl $ETIMEDOUT, %eax
399 .size __lll_timedwait_tid,.-__lll_timedwait_tid