1 /* Copyright (C) 2002-2012 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, see
17 <http://www.gnu.org/licenses/>. */
20 #include <shlib-compat.h>
21 #include <lowlevellock.h>
22 #include <lowlevelcond.h>
23 #include <pthread-pi-defines.h>
24 #include <pthread-errnos.h>
25 #include <stap-probe.h>
27 #include <kernel-features.h>
33 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
34 const struct timespec *abstime) */
35 .globl __pthread_cond_timedwait
36 .type __pthread_cond_timedwait, @function
38 __pthread_cond_timedwait:
42 cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
43 DW.ref.__gcc_personality_v0)
44 cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
46 cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
47 cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
51 cfi_adjust_cfa_offset(8)
52 cfi_rel_offset(%r12, 0)
54 cfi_adjust_cfa_offset(8)
55 cfi_rel_offset(%r13, 0)
57 cfi_adjust_cfa_offset(8)
58 cfi_rel_offset(%r14, 0)
60 cfi_adjust_cfa_offset(8)
61 cfi_rel_offset(%r15, 0)
62 #ifdef __ASSUME_FUTEX_CLOCK_REALTIME
63 # define FRAME_SIZE (32+8)
65 # define FRAME_SIZE (48+8)
67 subq $FRAME_SIZE, %rsp
68 cfi_adjust_cfa_offset(FRAME_SIZE)
71 LIBC_PROBE (cond_timedwait, 3, %rdi, %rsi, %rdx)
73 cmpq $1000000000, 8(%rdx)
80 +--------------------------+
81 rsp + 32 | timeout value |
82 +--------------------------+
83 rsp + 24 | old wake_seq value |
84 +--------------------------+
85 rsp + 16 | mutex pointer |
86 +--------------------------+
87 rsp + 8 | condvar pointer |
88 +--------------------------+
89 rsp + 4 | old broadcast_seq value |
90 +--------------------------+
91 rsp + 0 | old cancellation mode |
92 +--------------------------+
95 LP_OP(cmp) $-1, dep_mutex(%rdi)
97 /* Prepare structure passed to cancellation handler. */
103 mov %RSI_LP, dep_mutex(%rdi)
108 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
110 cmpl $0, __have_futex_clock_realtime(%rip)
112 cmpl $0, __have_futex_clock_realtime
117 /* Get internal lock. */
122 cmpxchgl %esi, (%rdi)
124 cmpxchgl %esi, cond_lock(%rdi)
128 /* Unlock the mutex. */
129 32: movq 16(%rsp), %rdi
131 callq __pthread_mutex_unlock_usercnt
138 incl cond_futex(%rdi)
139 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
141 /* Get and store current wakeup_seq value. */
143 movq wakeup_seq(%rdi), %r9
144 movl broadcast_seq(%rdi), %edx
149 movq $-ETIMEDOUT, %r14
152 38: movl cond_futex(%rdi), %r12d
164 34: callq __pthread_enable_asynccancel
168 movl $FUTEX_WAIT_BITSET, %esi
169 LP_OP(cmp) $-1, dep_mutex(%rdi)
172 mov dep_mutex(%rdi), %R8_LP
173 /* Requeue to a non-robust PI mutex if the PI bit is set and
174 the robust bit is not set. */
175 movl MUTEX_KIND(%r8), %eax
176 andl $(ROBUST_BIT|PI_BIT), %eax
180 movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
182 /* The following only works like this because we only support
183 two clocks, represented using a single bit. */
184 testl $1, cond_nwaiters(%rdi)
185 movl $FUTEX_CLOCK_REALTIME, %edx
189 addq $cond_futex, %rdi
190 movl $SYS_futex, %eax
194 #ifdef __ASSUME_REQUEUE_PI
200 subq $cond_futex, %rdi
203 61: movl $(FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG), %esi
204 60: xorl %r15d, %r15d
206 /* The following only works like this because we only support
207 two clocks, represented using a single bit. */
208 testl $1, cond_nwaiters(%rdi)
209 movl $FUTEX_CLOCK_REALTIME, %edx
210 movl $0xffffffff, %r9d
214 addq $cond_futex, %rdi
215 movl $SYS_futex, %eax
220 callq __pthread_disable_asynccancel
229 cmpxchgl %esi, (%rdi)
231 cmpxchgl %esi, cond_lock(%rdi)
235 36: movl broadcast_seq(%rdi), %edx
237 movq woken_seq(%rdi), %rax
239 movq wakeup_seq(%rdi), %r9
250 45: cmpq $-ETIMEDOUT, %r14
253 99: incq wakeup_seq(%rdi)
254 incl cond_futex(%rdi)
255 movl $ETIMEDOUT, %r14d
262 44: incq woken_seq(%rdi)
264 54: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
266 /* Wake up a thread which wants to destroy the condvar object. */
267 cmpq $0xffffffffffffffff, total_seq(%rdi)
269 movl cond_nwaiters(%rdi), %eax
270 andl $~((1 << nwaiters_shift) - 1), %eax
273 addq $cond_nwaiters, %rdi
274 LP_OP(cmp) $-1, dep_mutex-cond_nwaiters(%rdi)
276 #ifdef __ASSUME_PRIVATE_FUTEX
277 movl $FUTEX_WAKE, %eax
278 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
282 movl %fs:PRIVATE_FUTEX, %esi
284 orl $FUTEX_WAKE, %esi
286 movl $SYS_futex, %eax
288 subq $cond_nwaiters, %rdi
298 /* If requeue_pi is used the kernel performs the locking of the
300 41: movq 16(%rsp), %rdi
304 callq __pthread_mutex_cond_lock
309 48: addq $FRAME_SIZE, %rsp
310 cfi_adjust_cfa_offset(-FRAME_SIZE)
312 cfi_adjust_cfa_offset(-8)
315 cfi_adjust_cfa_offset(-8)
318 cfi_adjust_cfa_offset(-8)
321 cfi_adjust_cfa_offset(-8)
328 64: callq __pthread_mutex_cond_lock_adjust
332 /* Initial locking failed. */
335 addq $cond_lock, %rdi
337 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
338 movl $LLL_PRIVATE, %eax
339 movl $LLL_SHARED, %esi
341 callq __lll_lock_wait
344 /* Unlock in loop requires wakeup. */
347 addq $cond_lock, %rdi
349 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
350 movl $LLL_PRIVATE, %eax
351 movl $LLL_SHARED, %esi
353 callq __lll_unlock_wake
356 /* Locking in loop failed. */
359 addq $cond_lock, %rdi
361 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
362 movl $LLL_PRIVATE, %eax
363 movl $LLL_SHARED, %esi
365 callq __lll_lock_wait
367 subq $cond_lock, %rdi
371 /* Unlock after loop requires wakeup. */
374 addq $cond_lock, %rdi
376 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
377 movl $LLL_PRIVATE, %eax
378 movl $LLL_SHARED, %esi
380 callq __lll_unlock_wake
383 /* The initial unlocking of the mutex failed. */
384 46: movq 8(%rsp), %rdi
395 addq $cond_lock, %rdi
397 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
398 movl $LLL_PRIVATE, %eax
399 movl $LLL_SHARED, %esi
401 callq __lll_unlock_wake
403 47: movq (%rsp), %rax
407 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
409 /* Get internal lock. */
414 cmpxchgl %esi, (%rdi)
416 cmpxchgl %esi, cond_lock(%rdi)
420 /* Unlock the mutex. */
421 2: movq 16(%rsp), %rdi
423 callq __pthread_mutex_unlock_usercnt
430 incl cond_futex(%rdi)
431 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
433 /* Get and store current wakeup_seq value. */
435 movq wakeup_seq(%rdi), %r9
436 movl broadcast_seq(%rdi), %edx
440 /* Get the current time. */
442 # ifdef __NR_clock_gettime
443 /* Get the clock number. Note that the field in the condvar
444 structure stores the number minus 1. */
446 movl cond_nwaiters(%rdi), %edi
447 andl $((1 << nwaiters_shift) - 1), %edi
448 /* Only clocks 0 and 1 are allowed so far. Both are handled in the
452 mov __vdso_clock_gettime@GOTPCREL(%rip), %RAX_LP
454 PTR_DEMANGLE (%RAX_LP)
457 movl $__NR_clock_gettime, %eax
460 # ifndef __ASSUME_POSIX_TIMERS
465 /* Compute relative timeout. */
473 /* This call works because we directly jump to a system call entry
474 which preserves all the registers. */
475 call JUMPTARGET(__gettimeofday)
477 /* Compute relative timeout. */
480 mul %rdx /* Milli seconds to nano seconds. */
487 addq $1000000000, %rdx
491 movq $-ETIMEDOUT, %r14
494 /* Store relative timeout. */
495 21: movq %rcx, 32(%rsp)
498 movl cond_futex(%rdi), %r12d
510 4: callq __pthread_enable_asynccancel
514 LP_OP(cmp) $-1, dep_mutex(%rdi)
516 # ifdef __ASSUME_PRIVATE_FUTEX
517 movl $FUTEX_WAIT, %eax
518 movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
522 movl %fs:PRIVATE_FUTEX, %esi
525 orl $FUTEX_WAIT, %esi
528 addq $cond_futex, %rdi
529 movl $SYS_futex, %eax
534 callq __pthread_disable_asynccancel
543 cmpxchgl %esi, (%rdi)
545 cmpxchgl %esi, cond_lock(%rdi)
549 6: movl broadcast_seq(%rdi), %edx
551 movq woken_seq(%rdi), %rax
553 movq wakeup_seq(%rdi), %r9
564 15: cmpq $-ETIMEDOUT, %r14
569 /* Initial locking failed. */
572 addq $cond_lock, %rdi
574 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
575 movl $LLL_PRIVATE, %eax
576 movl $LLL_SHARED, %esi
578 callq __lll_lock_wait
581 /* Unlock in loop requires wakeup. */
584 addq $cond_lock, %rdi
586 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
587 movl $LLL_PRIVATE, %eax
588 movl $LLL_SHARED, %esi
590 callq __lll_unlock_wake
593 /* Locking in loop failed. */
596 addq $cond_lock, %rdi
598 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
599 movl $LLL_PRIVATE, %eax
600 movl $LLL_SHARED, %esi
602 callq __lll_lock_wait
604 subq $cond_lock, %rdi
608 # if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
609 /* clock_gettime not available. */
610 19: leaq 32(%rsp), %rdi
612 /* This call works because we directly jump to a system call entry
613 which preserves all the registers. */
614 call JUMPTARGET(__gettimeofday)
616 /* Compute relative timeout. */
619 mul %rdx /* Milli seconds to nano seconds. */
625 addq $1000000000, %rdx
629 movq $-ETIMEDOUT, %r14
634 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
635 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
640 .type __condvar_cleanup2, @function
645 +--------------------------+
647 +--------------------------+
649 +--------------------------+
651 +--------------------------+
653 +--------------------------+
654 rsp + 16 | mutex pointer |
655 +--------------------------+
656 rsp + 8 | condvar pointer |
657 +--------------------------+
658 rsp + 4 | old broadcast_seq value |
659 +--------------------------+
660 rsp + 0 | old cancellation mode |
661 +--------------------------+
666 /* Get internal lock. */
672 cmpxchgl %esi, (%rdi)
674 cmpxchgl %esi, cond_lock(%rdi)
679 addq $cond_lock, %rdi
681 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
682 movl $LLL_PRIVATE, %eax
683 movl $LLL_SHARED, %esi
685 callq __lll_lock_wait
687 subq $cond_lock, %rdi
690 1: movl broadcast_seq(%rdi), %edx
694 /* We increment the wakeup_seq counter only if it is lower than
695 total_seq. If this is not the case the thread was woken and
696 then canceled. In this case we ignore the signal. */
697 movq total_seq(%rdi), %rax
698 cmpq wakeup_seq(%rdi), %rax
700 incq wakeup_seq(%rdi)
701 incl cond_futex(%rdi)
702 6: incq woken_seq(%rdi)
704 3: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
706 /* Wake up a thread which wants to destroy the condvar object. */
708 cmpq $0xffffffffffffffff, total_seq(%rdi)
710 movl cond_nwaiters(%rdi), %eax
711 andl $~((1 << nwaiters_shift) - 1), %eax
714 LP_OP(cmp) $-1, dep_mutex(%rdi)
715 leaq cond_nwaiters(%rdi), %rdi
717 #ifdef __ASSUME_PRIVATE_FUTEX
718 movl $FUTEX_WAKE, %eax
719 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
723 movl %fs:PRIVATE_FUTEX, %esi
725 orl $FUTEX_WAKE, %esi
727 movl $SYS_futex, %eax
729 subq $cond_nwaiters, %rdi
740 addq $cond_lock, %rdi
742 LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
743 movl $LLL_PRIVATE, %eax
744 movl $LLL_SHARED, %esi
746 callq __lll_unlock_wake
748 /* Wake up all waiters to make sure no signal gets lost. */
751 addq $cond_futex, %rdi
752 LP_OP(cmp) $-1, dep_mutex-cond_futex(%rdi)
753 movl $0x7fffffff, %edx
754 #ifdef __ASSUME_PRIVATE_FUTEX
755 movl $FUTEX_WAKE, %eax
756 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
760 movl %fs:PRIVATE_FUTEX, %esi
762 orl $FUTEX_WAKE, %esi
764 movl $SYS_futex, %eax
767 5: movq 16(%rsp), %rdi
768 callq __pthread_mutex_cond_lock
771 movq FRAME_SIZE(%rsp), %r15
772 movq FRAME_SIZE+8(%rsp), %r14
773 movq FRAME_SIZE+16(%rsp), %r13
774 movq FRAME_SIZE+24(%rsp), %r12
776 call _Unwind_Resume@PLT
780 .size __condvar_cleanup2, .-__condvar_cleanup2
783 .section .gcc_except_table,"a",@progbits
785 .byte DW_EH_PE_omit # @LPStart format
786 .byte DW_EH_PE_omit # @TType format
787 .byte DW_EH_PE_uleb128 # call-site format
788 .uleb128 .Lcstend-.Lcstbegin
790 .uleb128 .LcleanupSTART1-.LSTARTCODE
791 .uleb128 .LcleanupEND1-.LcleanupSTART1
792 .uleb128 __condvar_cleanup2-.LSTARTCODE
794 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
795 .uleb128 .LcleanupSTART2-.LSTARTCODE
796 .uleb128 .LcleanupEND2-.LcleanupSTART2
797 .uleb128 __condvar_cleanup2-.LSTARTCODE
800 .uleb128 .LcallUR-.LSTARTCODE
801 .uleb128 .LENDCODE-.LcallUR
808 .hidden DW.ref.__gcc_personality_v0
809 .weak DW.ref.__gcc_personality_v0
810 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
812 .type DW.ref.__gcc_personality_v0, @object
813 .size DW.ref.__gcc_personality_v0, LP_SIZE
814 DW.ref.__gcc_personality_v0:
815 ASM_ADDR __gcc_personality_v0