1 /* Copyright (C) 2002-2005, 2007, 2009, 2010 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-pi-defines.h>
25 #include <pthread-errnos.h>
27 #include <kernel-features.h>
29 /* For the calculation see asm/vsyscall.h. */
30 #define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
36 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
37 const struct timespec *abstime) */
38 .globl __pthread_cond_timedwait
39 .type __pthread_cond_timedwait, @function
41 __pthread_cond_timedwait:
45 cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
46 DW.ref.__gcc_personality_v0)
47 cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
49 cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
50 cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
54 cfi_adjust_cfa_offset(8)
55 cfi_rel_offset(%r12, 0)
57 cfi_adjust_cfa_offset(8)
58 cfi_rel_offset(%r13, 0)
60 cfi_adjust_cfa_offset(8)
61 cfi_rel_offset(%r14, 0)
63 cfi_adjust_cfa_offset(8)
64 cfi_rel_offset(%r15, 0)
65 #ifdef __ASSUME_FUTEX_CLOCK_REALTIME
66 # define FRAME_SIZE 32
68 # define FRAME_SIZE 48
70 subq $FRAME_SIZE, %rsp
71 cfi_adjust_cfa_offset(FRAME_SIZE)
74 cmpq $1000000000, 8(%rdx)
81 +--------------------------+
82 rsp + 32 | timeout value |
83 +--------------------------+
84 rsp + 24 | old wake_seq value |
85 +--------------------------+
86 rsp + 16 | mutex pointer |
87 +--------------------------+
88 rsp + 8 | condvar pointer |
89 +--------------------------+
90 rsp + 4 | old broadcast_seq value |
91 +--------------------------+
92 rsp + 0 | old cancellation mode |
93 +--------------------------+
96 cmpq $-1, dep_mutex(%rdi)
98 /* Prepare structure passed to cancellation handler. */
104 movq %rsi, dep_mutex(%rdi)
107 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
109 cmpl $0, __have_futex_clock_realtime(%rip)
111 cmpl $0, __have_futex_clock_realtime
116 /* Get internal lock. */
121 cmpxchgl %esi, (%rdi)
123 cmpxchgl %esi, cond_lock(%rdi)
127 /* Unlock the mutex. */
128 32: movq 16(%rsp), %rdi
130 callq __pthread_mutex_unlock_usercnt
137 incl cond_futex(%rdi)
138 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
140 /* Get and store current wakeup_seq value. */
142 movq wakeup_seq(%rdi), %r9
143 movl broadcast_seq(%rdi), %edx
148 movq $-ETIMEDOUT, %r14
151 38: movl cond_futex(%rdi), %r12d
163 34: callq __pthread_enable_asynccancel
167 movl $FUTEX_WAIT_BITSET, %esi
168 cmpq $-1, dep_mutex(%rdi)
171 movq dep_mutex(%rdi), %r8
172 /* Requeue to a non-robust PI mutex if the PI bit is set and
173 the robust bit is not set. */
174 movl MUTEX_KIND(%r8), %eax
175 andl $(ROBUST_BIT|PI_BIT), %eax
179 movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
181 /* The following only works like this because we only support
182 two clocks, represented using a single bit. */
183 testl $1, cond_nwaiters(%rdi)
184 movl $FUTEX_CLOCK_REALTIME, %edx
188 addq $cond_futex, %rdi
189 movl $SYS_futex, %eax
193 #ifdef __ASSUME_REQUEUE_PI
199 subq $cond_futex, %rdi
202 61: movl $(FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG), %esi
203 60: xorl %r15d, %r15d
205 /* The following only works like this because we only support
206 two clocks, represented using a single bit. */
207 testl $1, cond_nwaiters(%rdi)
208 movl $FUTEX_CLOCK_REALTIME, %edx
209 movl $0xffffffff, %r9d
213 addq $cond_futex, %rdi
214 movl $SYS_futex, %eax
219 callq __pthread_disable_asynccancel
228 cmpxchgl %esi, (%rdi)
230 cmpxchgl %esi, cond_lock(%rdi)
234 36: movl broadcast_seq(%rdi), %edx
236 movq woken_seq(%rdi), %rax
238 movq wakeup_seq(%rdi), %r9
249 45: cmpq $-ETIMEDOUT, %r14
252 99: incq wakeup_seq(%rdi)
253 incl cond_futex(%rdi)
254 movl $ETIMEDOUT, %r14d
261 44: incq woken_seq(%rdi)
263 54: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
265 /* Wake up a thread which wants to destroy the condvar object. */
266 cmpq $0xffffffffffffffff, total_seq(%rdi)
268 movl cond_nwaiters(%rdi), %eax
269 andl $~((1 << nwaiters_shift) - 1), %eax
272 addq $cond_nwaiters, %rdi
273 cmpq $-1, dep_mutex-cond_nwaiters(%rdi)
275 #ifdef __ASSUME_PRIVATE_FUTEX
276 movl $FUTEX_WAKE, %eax
277 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
281 movl %fs:PRIVATE_FUTEX, %esi
283 orl $FUTEX_WAKE, %esi
285 movl $SYS_futex, %eax
287 subq $cond_nwaiters, %rdi
297 /* If requeue_pi is used the kernel performs the locking of the
299 41: movq 16(%rsp), %rdi
303 callq __pthread_mutex_cond_lock
308 48: addq $FRAME_SIZE, %rsp
309 cfi_adjust_cfa_offset(-FRAME_SIZE)
311 cfi_adjust_cfa_offset(-8)
314 cfi_adjust_cfa_offset(-8)
317 cfi_adjust_cfa_offset(-8)
320 cfi_adjust_cfa_offset(-8)
327 64: callq __pthread_mutex_cond_lock_adjust
331 /* Initial locking failed. */
334 addq $cond_lock, %rdi
336 cmpq $-1, dep_mutex-cond_lock(%rdi)
337 movl $LLL_PRIVATE, %eax
338 movl $LLL_SHARED, %esi
340 callq __lll_lock_wait
343 /* Unlock in loop requires wakeup. */
346 addq $cond_lock, %rdi
348 cmpq $-1, dep_mutex-cond_lock(%rdi)
349 movl $LLL_PRIVATE, %eax
350 movl $LLL_SHARED, %esi
352 callq __lll_unlock_wake
355 /* Locking in loop failed. */
358 addq $cond_lock, %rdi
360 cmpq $-1, dep_mutex-cond_lock(%rdi)
361 movl $LLL_PRIVATE, %eax
362 movl $LLL_SHARED, %esi
364 callq __lll_lock_wait
366 subq $cond_lock, %rdi
370 /* Unlock after loop requires wakeup. */
373 addq $cond_lock, %rdi
375 cmpq $-1, dep_mutex-cond_lock(%rdi)
376 movl $LLL_PRIVATE, %eax
377 movl $LLL_SHARED, %esi
379 callq __lll_unlock_wake
382 /* The initial unlocking of the mutex failed. */
383 46: movq 8(%rsp), %rdi
394 addq $cond_lock, %rdi
396 cmpq $-1, dep_mutex-cond_lock(%rdi)
397 movl $LLL_PRIVATE, %eax
398 movl $LLL_SHARED, %esi
400 callq __lll_unlock_wake
402 47: movq (%rsp), %rax
406 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
410 /* Get internal lock. */
415 cmpxchgl %esi, (%rdi)
417 cmpxchgl %esi, cond_lock(%rdi)
421 /* Unlock the mutex. */
422 2: movq 16(%rsp), %rdi
424 callq __pthread_mutex_unlock_usercnt
431 incl cond_futex(%rdi)
432 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
434 /* Get and store current wakeup_seq value. */
436 movq wakeup_seq(%rdi), %r9
437 movl broadcast_seq(%rdi), %edx
441 /* Get the current time. */
443 # ifdef __NR_clock_gettime
444 /* Get the clock number. Note that the field in the condvar
445 structure stores the number minus 1. */
447 movl cond_nwaiters(%rdi), %edi
448 andl $((1 << nwaiters_shift) - 1), %edi
449 /* Only clocks 0 and 1 are allowed so far. Both are handled in the
453 movq __vdso_clock_gettime@GOTPCREL(%rip), %rax
460 26: movl $__NR_clock_gettime, %eax
463 # ifndef __ASSUME_POSIX_TIMERS
468 /* Compute relative timeout. */
476 movq $VSYSCALL_ADDR_vgettimeofday, %rax
479 /* Compute relative timeout. */
482 mul %rdx /* Milli seconds to nano seconds. */
489 addq $1000000000, %rdx
493 movq $-ETIMEDOUT, %r14
496 /* Store relative timeout. */
497 21: movq %rcx, 32(%rsp)
500 movl cond_futex(%rdi), %r12d
512 4: callq __pthread_enable_asynccancel
516 cmpq $-1, dep_mutex(%rdi)
518 # ifdef __ASSUME_PRIVATE_FUTEX
519 movl $FUTEX_WAIT, %eax
520 movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
524 movl %fs:PRIVATE_FUTEX, %esi
527 orl $FUTEX_WAIT, %esi
530 addq $cond_futex, %rdi
531 movl $SYS_futex, %eax
536 callq __pthread_disable_asynccancel
545 cmpxchgl %esi, (%rdi)
547 cmpxchgl %esi, cond_lock(%rdi)
551 6: movl broadcast_seq(%rdi), %edx
553 movq woken_seq(%rdi), %rax
555 movq wakeup_seq(%rdi), %r9
566 15: cmpq $-ETIMEDOUT, %r14
571 /* Initial locking failed. */
574 addq $cond_lock, %rdi
576 cmpq $-1, dep_mutex-cond_lock(%rdi)
577 movl $LLL_PRIVATE, %eax
578 movl $LLL_SHARED, %esi
580 callq __lll_lock_wait
583 /* Unlock in loop requires wakeup. */
586 addq $cond_lock, %rdi
588 cmpq $-1, dep_mutex-cond_lock(%rdi)
589 movl $LLL_PRIVATE, %eax
590 movl $LLL_SHARED, %esi
592 callq __lll_unlock_wake
595 /* Locking in loop failed. */
598 addq $cond_lock, %rdi
600 cmpq $-1, dep_mutex-cond_lock(%rdi)
601 movl $LLL_PRIVATE, %eax
602 movl $LLL_SHARED, %esi
604 callq __lll_lock_wait
606 subq $cond_lock, %rdi
610 # if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
611 /* clock_gettime not available. */
612 19: leaq 32(%rsp), %rdi
614 movq $VSYSCALL_ADDR_vgettimeofday, %rax
617 /* Compute relative timeout. */
620 mul %rdx /* Milli seconds to nano seconds. */
626 addq $1000000000, %rdx
630 movq $-ETIMEDOUT, %r14
635 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
636 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
641 .type __condvar_cleanup2, @function
646 +--------------------------+
648 +--------------------------+
650 +--------------------------+
652 +--------------------------+
654 +--------------------------+
655 rsp + 16 | mutex pointer |
656 +--------------------------+
657 rsp + 8 | condvar pointer |
658 +--------------------------+
659 rsp + 4 | old broadcast_seq value |
660 +--------------------------+
661 rsp + 0 | old cancellation mode |
662 +--------------------------+
667 /* Get internal lock. */
673 cmpxchgl %esi, (%rdi)
675 cmpxchgl %esi, cond_lock(%rdi)
680 addq $cond_lock, %rdi
682 cmpq $-1, dep_mutex-cond_lock(%rdi)
683 movl $LLL_PRIVATE, %eax
684 movl $LLL_SHARED, %esi
686 callq __lll_lock_wait
688 subq $cond_lock, %rdi
691 1: movl broadcast_seq(%rdi), %edx
695 /* We increment the wakeup_seq counter only if it is lower than
696 total_seq. If this is not the case the thread was woken and
697 then canceled. In this case we ignore the signal. */
698 movq total_seq(%rdi), %rax
699 cmpq wakeup_seq(%rdi), %rax
701 incq wakeup_seq(%rdi)
702 incl cond_futex(%rdi)
703 6: incq woken_seq(%rdi)
705 3: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
707 /* Wake up a thread which wants to destroy the condvar object. */
709 cmpq $0xffffffffffffffff, total_seq(%rdi)
711 movl cond_nwaiters(%rdi), %eax
712 andl $~((1 << nwaiters_shift) - 1), %eax
715 cmpq $-1, dep_mutex(%rdi)
716 leaq cond_nwaiters(%rdi), %rdi
718 #ifdef __ASSUME_PRIVATE_FUTEX
719 movl $FUTEX_WAKE, %eax
720 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
724 movl %fs:PRIVATE_FUTEX, %esi
726 orl $FUTEX_WAKE, %esi
728 movl $SYS_futex, %eax
730 subq $cond_nwaiters, %rdi
741 addq $cond_lock, %rdi
743 cmpq $-1, dep_mutex-cond_lock(%rdi)
744 movl $LLL_PRIVATE, %eax
745 movl $LLL_SHARED, %esi
747 callq __lll_unlock_wake
749 /* Wake up all waiters to make sure no signal gets lost. */
752 addq $cond_futex, %rdi
753 cmpq $-1, dep_mutex-cond_futex(%rdi)
754 movl $0x7fffffff, %edx
755 #ifdef __ASSUME_PRIVATE_FUTEX
756 movl $FUTEX_WAKE, %eax
757 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
761 movl %fs:PRIVATE_FUTEX, %esi
763 orl $FUTEX_WAKE, %esi
765 movl $SYS_futex, %eax
768 5: movq 16(%rsp), %rdi
769 callq __pthread_mutex_cond_lock
772 movq FRAME_SIZE(%rsp), %r15
773 movq FRAME_SIZE+8(%rsp), %r14
774 movq FRAME_SIZE+16(%rsp), %r13
775 movq FRAME_SIZE+24(%rsp), %r12
777 call _Unwind_Resume@PLT
781 .size __condvar_cleanup2, .-__condvar_cleanup2
784 .section .gcc_except_table,"a",@progbits
786 .byte DW_EH_PE_omit # @LPStart format
787 .byte DW_EH_PE_omit # @TType format
788 .byte DW_EH_PE_uleb128 # call-site format
789 .uleb128 .Lcstend-.Lcstbegin
791 .uleb128 .LcleanupSTART1-.LSTARTCODE
792 .uleb128 .LcleanupEND1-.LcleanupSTART1
793 .uleb128 __condvar_cleanup2-.LSTARTCODE
795 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
796 .uleb128 .LcleanupSTART2-.LSTARTCODE
797 .uleb128 .LcleanupEND2-.LcleanupSTART2
798 .uleb128 __condvar_cleanup2-.LSTARTCODE
801 .uleb128 .LcallUR-.LSTARTCODE
802 .uleb128 .LENDCODE-.LcallUR
809 .hidden DW.ref.__gcc_personality_v0
810 .weak DW.ref.__gcc_personality_v0
811 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
813 .type DW.ref.__gcc_personality_v0, @object
814 .size DW.ref.__gcc_personality_v0, 8
815 DW.ref.__gcc_personality_v0:
816 .quad __gcc_personality_v0