1 /* Copyright (C) 2002-2005, 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, see
17 <http://www.gnu.org/licenses/>. */
20 #include <lowlevellock.h>
21 #include <lowlevelcond.h>
22 #include <pthread-pi-defines.h>
23 #include <pthread-errnos.h>
24 #include <bits/kernel-features.h>
25 #include <tcb-offsets.h>
27 /* For the calculation see asm/vsyscall.h. */
28 #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
38 .protected __pthread_cond_timedwait
40 __pthread_cond_timedwait:
45 cfi_adjust_cfa_offset(8)
46 cfi_rel_offset(%r12, 0)
48 cfi_adjust_cfa_offset(8)
49 cfi_rel_offset(%r13, 0)
51 cfi_adjust_cfa_offset(8)
52 cfi_rel_offset(%r14, 0)
54 cfi_adjust_cfa_offset(8)
55 cfi_rel_offset(%r15, 0)
56 #ifdef __ASSUME_FUTEX_CLOCK_REALTIME
57 # define FRAME_SIZE 32
59 # define FRAME_SIZE 48
61 subq $FRAME_SIZE, %rsp
62 cfi_adjust_cfa_offset(FRAME_SIZE)
65 cmpq $1000000000, 8(%rdx)
72 +--------------------------+
73 rsp + 32 | timeout value |
74 +--------------------------+
75 rsp + 24 | old wake_seq value |
76 +--------------------------+
77 rsp + 16 | mutex pointer |
78 +--------------------------+
79 rsp + 8 | condvar pointer |
80 +--------------------------+
81 rsp + 4 | old broadcast_seq value |
82 +--------------------------+
83 rsp + 0 | old cancellation mode |
84 +--------------------------+
87 cmpq $-1, dep_mutex(%rdi)
89 /* Prepare structure passed to cancellation handler. */
95 movq %rsi, dep_mutex(%rdi)
98 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
100 cmpl $0, __have_futex_clock_realtime@GOTOFF(%rip)
102 cmpl $0, __have_futex_clock_realtime
107 /* Get internal lock. */
112 cmpxchgl %esi, (%rdi)
114 cmpxchgl %esi, cond_lock(%rdi)
118 /* Unlock the mutex. */
119 32: movq 16(%rsp), %rdi
121 callq __pthread_mutex_unlock_usercnt
128 incl cond_futex(%rdi)
129 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
131 /* Get and store current wakeup_seq value. */
133 movq wakeup_seq(%rdi), %r9
134 movl broadcast_seq(%rdi), %edx
138 38: movl cond_futex(%rdi), %r12d
150 34: callq __pthread_enable_asynccancel
154 movl $FUTEX_WAIT_BITSET, %esi
155 cmpq $-1, dep_mutex(%rdi)
158 movq dep_mutex(%rdi), %r8
159 /* Requeue to a non-robust PI mutex if the PI bit is set and
160 the robust bit is not set. */
161 movl MUTEX_KIND(%r8), %eax
162 andl $(ROBUST_BIT|PI_BIT), %eax
166 movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
168 /* The following only works like this because we only support
169 two clocks, represented using a single bit. */
170 testl $1, cond_nwaiters(%rdi)
171 movl $FUTEX_CLOCK_REALTIME, %edx
175 addq $cond_futex, %rdi
176 movl $SYS_futex, %eax
180 #ifdef __ASSUME_REQUEUE_PI
186 subq $cond_futex, %rdi
189 61: movl $(FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG), %esi
190 60: xorl %r15d, %r15d
192 /* The following only works like this because we only support
193 two clocks, represented using a single bit. */
194 testl $1, cond_nwaiters(%rdi)
195 movl $FUTEX_CLOCK_REALTIME, %edx
196 movl $0xffffffff, %r9d
200 addq $cond_futex, %rdi
201 movl $SYS_futex, %eax
206 callq __pthread_disable_asynccancel
215 cmpxchgl %esi, (%rdi)
217 cmpxchgl %esi, cond_lock(%rdi)
221 36: movl broadcast_seq(%rdi), %edx
223 movq woken_seq(%rdi), %rax
225 movq wakeup_seq(%rdi), %r9
236 45: cmpq $-ETIMEDOUT, %r14
239 99: incq wakeup_seq(%rdi)
240 incl cond_futex(%rdi)
241 movl $ETIMEDOUT, %r14d
248 44: incq woken_seq(%rdi)
250 54: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
252 /* Wake up a thread which wants to destroy the condvar object. */
253 cmpq $0xffffffffffffffff, total_seq(%rdi)
255 movl cond_nwaiters(%rdi), %eax
256 andl $~((1 << nwaiters_shift) - 1), %eax
259 addq $cond_nwaiters, %rdi
260 cmpq $-1, dep_mutex-cond_nwaiters(%rdi)
262 #ifdef __ASSUME_PRIVATE_FUTEX
263 movl $FUTEX_WAKE, %eax
264 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
268 movl %fs:PRIVATE_FUTEX, %esi
270 orl $FUTEX_WAKE, %esi
272 movl $SYS_futex, %eax
274 subq $cond_nwaiters, %rdi
284 /* If requeue_pi is used the kernel performs the locking of the
286 41: movq 16(%rsp), %rdi
290 callq __pthread_mutex_cond_lock
295 48: addq $FRAME_SIZE, %rsp
296 cfi_adjust_cfa_offset(-FRAME_SIZE)
298 cfi_adjust_cfa_offset(-8)
301 cfi_adjust_cfa_offset(-8)
304 cfi_adjust_cfa_offset(-8)
307 cfi_adjust_cfa_offset(-8)
314 64: callq __pthread_mutex_cond_lock_adjust
318 /* Initial locking failed. */
321 addq $cond_lock, %rdi
323 cmpq $-1, dep_mutex-cond_lock(%rdi)
324 movl $LLL_PRIVATE, %eax
325 movl $LLL_SHARED, %esi
327 callq __lll_lock_wait
330 /* Unlock in loop requires wakeup. */
333 addq $cond_lock, %rdi
335 cmpq $-1, dep_mutex-cond_lock(%rdi)
336 movl $LLL_PRIVATE, %eax
337 movl $LLL_SHARED, %esi
339 callq __lll_unlock_wake
342 /* Locking in loop failed. */
345 addq $cond_lock, %rdi
347 cmpq $-1, dep_mutex-cond_lock(%rdi)
348 movl $LLL_PRIVATE, %eax
349 movl $LLL_SHARED, %esi
351 callq __lll_lock_wait
353 subq $cond_lock, %rdi
357 /* Unlock after loop requires wakeup. */
360 addq $cond_lock, %rdi
362 cmpq $-1, dep_mutex-cond_lock(%rdi)
363 movl $LLL_PRIVATE, %eax
364 movl $LLL_SHARED, %esi
366 callq __lll_unlock_wake
369 /* The initial unlocking of the mutex failed. */
370 46: movq 8(%rsp), %rdi
381 addq $cond_lock, %rdi
383 cmpq $-1, dep_mutex-cond_lock(%rdi)
384 movl $LLL_PRIVATE, %eax
385 movl $LLL_SHARED, %esi
387 callq __lll_unlock_wake
389 47: movq (%rsp), %rax
393 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
397 /* Get internal lock. */
402 cmpxchgl %esi, (%rdi)
404 cmpxchgl %esi, cond_lock(%rdi)
408 /* Unlock the mutex. */
409 2: movq 16(%rsp), %rdi
411 callq __pthread_mutex_unlock_usercnt
418 incl cond_futex(%rdi)
419 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
421 /* Get and store current wakeup_seq value. */
423 movq wakeup_seq(%rdi), %r9
424 movl broadcast_seq(%rdi), %edx
428 /* Get the current time. */
430 # ifdef __NR_clock_gettime
431 /* Get the clock number. Note that the field in the condvar
432 structure stores the number minus 1. */
434 movl cond_nwaiters(%rdi), %edi
435 andl $((1 << nwaiters_shift) - 1), %edi
436 /* Only clocks 0 and 1 are allowed so far. Both are handled in the
439 26: movl $__NR_clock_gettime, %eax
442 # ifndef __ASSUME_POSIX_TIMERS
447 /* Compute relative timeout. */
455 movq $VSYSCALL_ADDR_vgettimeofday, %rax
458 /* Compute relative timeout. */
461 mul %rdx /* Milli seconds to nano seconds. */
468 addq $1000000000, %rdx
472 movq $-ETIMEDOUT, %r14
475 /* Store relative timeout. */
476 21: movq %rcx, 32(%rsp)
479 movl cond_futex(%rdi), %r12d
491 4: callq __pthread_enable_asynccancel
495 cmpq $-1, dep_mutex(%rdi)
497 # ifdef __ASSUME_PRIVATE_FUTEX
498 movl $FUTEX_WAIT, %eax
499 movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
503 movl %fs:PRIVATE_FUTEX, %esi
506 orl $FUTEX_WAIT, %esi
509 addq $cond_futex, %rdi
510 movl $SYS_futex, %eax
515 callq __pthread_disable_asynccancel
524 cmpxchgl %esi, (%rdi)
526 cmpxchgl %esi, cond_lock(%rdi)
530 6: movl broadcast_seq(%rdi), %edx
532 movq woken_seq(%rdi), %rax
534 movq wakeup_seq(%rdi), %r9
545 15: cmpq $-ETIMEDOUT, %r14
550 /* Initial locking failed. */
553 addq $cond_lock, %rdi
555 cmpq $-1, dep_mutex-cond_lock(%rdi)
556 movl $LLL_PRIVATE, %eax
557 movl $LLL_SHARED, %esi
559 callq __lll_lock_wait
562 /* Unlock in loop requires wakeup. */
565 addq $cond_lock, %rdi
567 cmpq $-1, dep_mutex-cond_lock(%rdi)
568 movl $LLL_PRIVATE, %eax
569 movl $LLL_SHARED, %esi
571 callq __lll_unlock_wake
574 /* Locking in loop failed. */
577 addq $cond_lock, %rdi
579 cmpq $-1, dep_mutex-cond_lock(%rdi)
580 movl $LLL_PRIVATE, %eax
581 movl $LLL_SHARED, %esi
583 callq __lll_lock_wait
585 subq $cond_lock, %rdi
589 # if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
590 /* clock_gettime not available. */
591 19: leaq 32(%rsp), %rdi
593 movq $VSYSCALL_ADDR_vgettimeofday, %rax
596 /* Compute relative timeout. */
599 mul %rdx /* Milli seconds to nano seconds. */
605 addq $1000000000, %rdx
609 movq $-ETIMEDOUT, %r14
614 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
615 weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait)
619 .type __condvar_cleanup2, @function
624 +--------------------------+
626 +--------------------------+
628 +--------------------------+
630 +--------------------------+
632 +--------------------------+
633 rsp + 16 | mutex pointer |
634 +--------------------------+
635 rsp + 8 | condvar pointer |
636 +--------------------------+
637 rsp + 4 | old broadcast_seq value |
638 +--------------------------+
639 rsp + 0 | old cancellation mode |
640 +--------------------------+
645 /* Get internal lock. */
651 cmpxchgl %esi, (%rdi)
653 cmpxchgl %esi, cond_lock(%rdi)
658 addq $cond_lock, %rdi
660 cmpq $-1, dep_mutex-cond_lock(%rdi)
661 movl $LLL_PRIVATE, %eax
662 movl $LLL_SHARED, %esi
664 callq __lll_lock_wait
666 subq $cond_lock, %rdi
669 1: movl broadcast_seq(%rdi), %edx
673 /* We increment the wakeup_seq counter only if it is lower than
674 total_seq. If this is not the case the thread was woken and
675 then canceled. In this case we ignore the signal. */
676 movq total_seq(%rdi), %rax
677 cmpq wakeup_seq(%rdi), %rax
679 incq wakeup_seq(%rdi)
680 incl cond_futex(%rdi)
681 6: incq woken_seq(%rdi)
683 3: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
685 /* Wake up a thread which wants to destroy the condvar object. */
687 cmpq $0xffffffffffffffff, total_seq(%rdi)
689 movl cond_nwaiters(%rdi), %eax
690 andl $~((1 << nwaiters_shift) - 1), %eax
693 cmpq $-1, dep_mutex(%rdi)
694 leaq cond_nwaiters(%rdi), %rdi
696 #ifdef __ASSUME_PRIVATE_FUTEX
697 movl $FUTEX_WAKE, %eax
698 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
702 movl %fs:PRIVATE_FUTEX, %esi
704 orl $FUTEX_WAKE, %esi
706 movl $SYS_futex, %eax
708 subq $cond_nwaiters, %rdi
719 addq $cond_lock, %rdi
721 cmpq $-1, dep_mutex-cond_lock(%rdi)
722 movl $LLL_PRIVATE, %eax
723 movl $LLL_SHARED, %esi
725 callq __lll_unlock_wake
727 /* Wake up all waiters to make sure no signal gets lost. */
730 addq $cond_futex, %rdi
731 cmpq $-1, dep_mutex-cond_futex(%rdi)
732 movl $0x7fffffff, %edx
733 #ifdef __ASSUME_PRIVATE_FUTEX
734 movl $FUTEX_WAKE, %eax
735 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
739 movl %fs:PRIVATE_FUTEX, %esi
741 orl $FUTEX_WAKE, %esi
743 movl $SYS_futex, %eax
746 5: movq 16(%rsp), %rdi
747 callq __pthread_mutex_cond_lock
750 movq FRAME_SIZE(%rsp), %r15
751 movq FRAME_SIZE+8(%rsp), %r14
752 movq FRAME_SIZE+16(%rsp), %r13
753 movq FRAME_SIZE+24(%rsp), %r12
755 call _Unwind_Resume@PLT
759 .size __condvar_cleanup2, .-__condvar_cleanup2
762 .section .gcc_except_table,"a",@progbits
764 .byte DW_EH_PE_omit # @LPStart format
765 .byte DW_EH_PE_omit # @TType format
766 .byte DW_EH_PE_uleb128 # call-site format
767 .uleb128 .Lcstend-.Lcstbegin
769 .uleb128 .LcleanupSTART1-.LSTARTCODE
770 .uleb128 .LcleanupEND1-.LcleanupSTART1
771 .uleb128 __condvar_cleanup2-.LSTARTCODE
773 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
774 .uleb128 .LcleanupSTART2-.LSTARTCODE
775 .uleb128 .LcleanupEND2-.LcleanupSTART2
776 .uleb128 __condvar_cleanup2-.LSTARTCODE
779 .uleb128 .LcallUR-.LSTARTCODE
780 .uleb128 .LENDCODE-.LcallUR
787 .hidden DW.ref.__gcc_personality_v0
788 .weak DW.ref.__gcc_personality_v0
789 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
791 .type DW.ref.__gcc_personality_v0, @object
792 .size DW.ref.__gcc_personality_v0, 8
793 DW.ref.__gcc_personality_v0:
794 .quad __gcc_personality_v0