1 /* Copyright (C) 2002, 2003, 2004, 2005, 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 <shlib-compat.h>
22 #include <lowlevellock.h>
23 #include <lowlevelcond.h>
24 #include <pthread-errnos.h>
26 #include <kernel-features.h>
28 /* For the calculation see asm/vsyscall.h. */
29 #define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
34 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
35 const struct timespec *abstime) */
36 .globl __pthread_cond_timedwait
37 .type __pthread_cond_timedwait, @function
39 __pthread_cond_timedwait:
48 subq $FRAME_SIZE, %rsp
51 cmpq $1000000000, 8(%rdx)
58 +--------------------------+
59 rsp + 48 | cleanup buffer |
60 +--------------------------+
61 rsp + 40 | old wake_seq value |
62 +--------------------------+
63 rsp + 24 | timeout value |
64 +--------------------------+
65 rsp + 16 | mutex pointer |
66 +--------------------------+
67 rsp + 8 | condvar pointer |
68 +--------------------------+
69 rsp + 4 | old broadcast_seq value |
70 +--------------------------+
71 rsp + 0 | old cancellation mode |
72 +--------------------------+
75 cmpq $-1, dep_mutex(%rdi)
77 /* Prepare structure passed to cancellation handler. */
83 movq %rsi, dep_mutex(%rdi)
85 /* Get internal lock. */
92 cmpxchgl %esi, cond_lock(%rdi)
96 /* Unlock the mutex. */
97 2: movq 16(%rsp), %rdi
99 callq __pthread_mutex_unlock_usercnt
106 incl cond_futex(%rdi)
107 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
109 /* Install cancellation handler. */
111 leaq __condvar_cleanup(%rip), %rsi
113 leaq __condvar_cleanup, %rsi
117 callq __pthread_cleanup_push
119 /* Get and store current wakeup_seq value. */
121 movq wakeup_seq(%rdi), %r9
122 movl broadcast_seq(%rdi), %edx
126 /* Get the current time. */
128 #ifdef __NR_clock_gettime
129 /* Get the clock number. Note that the field in the condvar
130 structure stores the number minus 1. */
132 movl cond_nwaiters(%rdi), %edi
133 andl $((1 << nwaiters_shift) - 1), %edi
134 /* Only clocks 0 and 1 are allowed so far. Both are handled in the
137 movq __vdso_clock_gettime@GOTPCREL(%rip), %rax
143 26: movl $__NR_clock_gettime, %eax
146 # ifndef __ASSUME_POSIX_TIMERS
151 /* Compute relative timeout. */
159 movq $VSYSCALL_ADDR_vgettimeofday, %rax
162 /* Compute relative timeout. */
165 mul %rdx /* Milli seconds to nano seconds. */
172 addq $1000000000, %rdx
176 movq $-ETIMEDOUT, %r14
179 /* Store relative timeout. */
180 21: movq %rcx, 24(%rsp)
183 movl cond_futex(%rdi), %r12d
194 4: callq __pthread_enable_asynccancel
198 cmpq $-1, dep_mutex(%rdi)
200 #ifdef __ASSUME_PRIVATE_FUTEX
201 movl $FUTEX_WAIT, %eax
202 movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
206 movl %fs:PRIVATE_FUTEX, %esi
209 orl $FUTEX_WAIT, %esi
212 addq $cond_futex, %rdi
213 movl $SYS_futex, %eax
218 callq __pthread_disable_asynccancel
226 cmpxchgl %esi, (%rdi)
228 cmpxchgl %esi, cond_lock(%rdi)
232 6: movl broadcast_seq(%rdi), %edx
234 movq woken_seq(%rdi), %rax
236 movq wakeup_seq(%rdi), %r9
247 15: cmpq $-ETIMEDOUT, %r14
250 13: incq wakeup_seq(%rdi)
251 incl cond_futex(%rdi)
252 movl $ETIMEDOUT, %r14d
259 14: incq woken_seq(%rdi)
261 24: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
263 /* Wake up a thread which wants to destroy the condvar object. */
264 cmpq $0xffffffffffffffff, total_seq(%rdi)
266 movl cond_nwaiters(%rdi), %eax
267 andl $~((1 << nwaiters_shift) - 1), %eax
270 addq $cond_nwaiters, %rdi
271 cmpq $-1, dep_mutex-cond_nwaiters(%rdi)
273 #ifdef __ASSUME_PRIVATE_FUTEX
274 movl $FUTEX_WAKE, %eax
275 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
279 movl %fs:PRIVATE_FUTEX, %esi
281 orl $FUTEX_WAKE, %esi
283 movl $SYS_futex, %eax
285 subq $cond_nwaiters, %rdi
295 /* Remove cancellation handler. */
296 11: movq 48+CLEANUP_PREV(%rsp), %rdx
297 movq %rdx, %fs:CLEANUP
300 callq __pthread_mutex_cond_lock
305 18: addq $FRAME_SIZE, %rsp
316 /* Initial locking failed. */
320 addq $cond_lock, %rdi
322 cmpq $-1, dep_mutex-cond_lock(%rdi)
323 movl $LLL_PRIVATE, %eax
324 movl $LLL_SHARED, %esi
326 callq __lll_lock_wait
329 /* Unlock in loop requires wakeup. */
332 addq $cond_lock, %rdi
334 cmpq $-1, dep_mutex-cond_lock(%rdi)
335 movl $LLL_PRIVATE, %eax
336 movl $LLL_SHARED, %esi
338 callq __lll_unlock_wake
341 /* Locking in loop failed. */
344 addq $cond_lock, %rdi
346 cmpq $-1, dep_mutex-cond_lock(%rdi)
347 movl $LLL_PRIVATE, %eax
348 movl $LLL_SHARED, %esi
350 callq __lll_lock_wait
352 subq $cond_lock, %rdi
356 /* Unlock after loop requires wakeup. */
359 addq $cond_lock, %rdi
361 cmpq $-1, dep_mutex-cond_lock(%rdi)
362 movl $LLL_PRIVATE, %eax
363 movl $LLL_SHARED, %esi
365 callq __lll_unlock_wake
368 /* The initial unlocking of the mutex failed. */
369 16: movq 8(%rsp), %rdi
380 addq $cond_lock, %rdi
382 cmpq $-1, dep_mutex-cond_lock(%rdi)
383 movl $LLL_PRIVATE, %eax
384 movl $LLL_SHARED, %esi
386 callq __lll_unlock_wake
388 17: movq (%rsp), %rax
391 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
392 /* clock_gettime not available. */
393 19: leaq 24(%rsp), %rdi
395 movq $VSYSCALL_ADDR_vgettimeofday, %rax
398 /* Compute relative timeout. */
401 mul %rdx /* Milli seconds to nano seconds. */
407 addq $1000000000, %rdx
411 movq $-ETIMEDOUT, %r14
416 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
417 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
421 .section .eh_frame,"a",@progbits
423 .long L(ENDCIE)-L(STARTCIE) # Length of the CIE.
426 .byte 1 # Version number.
428 .string "zR" # NUL-terminated augmentation
431 .ascii "\0" # NUL-terminated augmentation
434 .uleb128 1 # Code alignment factor.
435 .sleb128 -8 # Data alignment factor.
436 .byte 16 # Return address register
439 .uleb128 1 # Augmentation value length.
440 .byte 0x1b # Encoding: DW_EH_PE_pcrel
443 .byte 0x0c # DW_CFA_def_cfa
446 .byte 0x90 # DW_CFA_offset, column 0x8
451 .long .LENDFDE-.LSTARTFDE # Length of the FDE.
453 .long .LSTARTFDE-.LSTARTFRAME # CIE pointer.
455 .long .LSTARTCODE-. # PC-relative start address
458 .long .LSTARTCODE # Start address of the code.
460 .long .LENDCODE-.LSTARTCODE # Length of the code.
462 .uleb128 0 # No augmentation data.
464 .byte 0x40+.Lpush_r12-.LSTARTCODE # DW_CFA_advance_loc+N
465 .byte 14 # DW_CFA_def_cfa_offset
467 .byte 0x8c # DW_CFA_offset %r12
469 .byte 0x40+.Lpush_r13-.Lpush_r12 # DW_CFA_advance_loc+N
470 .byte 14 # DW_CFA_def_cfa_offset
472 .byte 0x8d # DW_CFA_offset %r13
474 .byte 0x40+.Lpush_r14-.Lpush_r13 # DW_CFA_advance_loc+N
475 .byte 14 # DW_CFA_def_cfa_offset
477 .byte 0x84 # DW_CFA_offset %r14
479 .byte 0x40+.Lsubq-.Lpush_r14 # DW_CFA_advance_loc+N
480 .byte 14 # DW_CFA_def_cfa_offset
481 .uleb128 32+FRAME_SIZE
482 .byte 3 # DW_CFA_advance_loc2
484 .byte 14 # DW_CFA_def_cfa_offset
486 .byte 0x40+.Lpop_r14-.Laddq # DW_CFA_advance_loc+N
487 .byte 14 # DW_CFA_def_cfa_offset
489 .byte 0xce # DW_CFA_restore %r14
490 .byte 0x40+.Lpop_r13-.Lpop_r14 # DW_CFA_advance_loc+N
491 .byte 14 # DW_CFA_def_cfa_offset
493 .byte 0xcd # DW_CFA_restore %r13
494 .byte 0x40+.Lpop_r12-.Lpop_r13 # DW_CFA_advance_loc+N
495 .byte 14 # DW_CFA_def_cfa_offset
497 .byte 0xcc # DW_CFA_restore %r12
498 .byte 0x40+.LSbl1-.Lpop_r12 # DW_CFA_advance_loc+N
499 .byte 14 # DW_CFA_def_cfa_offset
500 .uleb128 32+FRAME_SIZE
501 .byte 0x8c # DW_CFA_offset %r12
503 .byte 0x8d # DW_CFA_offset %r13
505 .byte 0x84 # DW_CFA_offset %r14