1 /* Copyright (C) 2003-2014 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
19 #include <shlib-compat.h>
20 #include <lowlevellock.h>
21 #include <lowlevelcond.h>
22 #include <pthread-errnos.h>
23 #include <kernel-features.h>
24 #include <tcb-offsets.h>
25 #include "lowlevel-atomic.h"
29 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
30 const struct timespec *abstime) */
31 .globl __pthread_cond_timedwait
32 .type __pthread_cond_timedwait, @function
35 __pthread_cond_timedwait:
38 cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
39 DW.ref.__gcc_personality_v0)
40 cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
42 cfi_personality(DW_EH_PE_absptr, __gcc_personality_v0)
43 cfi_lsda(DW_EH_PE_absptr, .LexceptSTART)
46 cfi_adjust_cfa_offset (4)
47 cfi_rel_offset (r8, 0)
49 cfi_adjust_cfa_offset (4)
50 cfi_rel_offset (r9, 0)
52 cfi_adjust_cfa_offset (4)
53 cfi_rel_offset (r10, 0)
55 cfi_adjust_cfa_offset (4)
56 cfi_rel_offset (r11, 0)
58 cfi_adjust_cfa_offset (4)
59 cfi_rel_offset (r12, 0)
61 cfi_adjust_cfa_offset (4)
62 cfi_rel_offset (r13, 0)
64 cfi_adjust_cfa_offset (4)
65 cfi_rel_offset (pr, 0)
67 cfi_adjust_cfa_offset (64)
85 /* Get internal lock. */
89 CMPXCHG (r3, @(cond_lock,r8), r4, r2)
91 CMPXCHG (r3, @r8, r4, r2)
99 .long _GLOBAL_OFFSET_TABLE_
103 /* Store the reference to the mutex. If there is already a
104 different value in there this is a bad user bug. */
105 mov.l @(dep_mutex,r8),r0
108 mov.l r9, @(dep_mutex,r8)
111 /* Unlock the mutex. */
127 mov.l @(total_seq,r8),r0
128 mov.l @(total_seq+4,r8),r1
131 mov.l r0,@(total_seq,r8)
132 mov.l r1,@(total_seq+4,r8)
133 mov.l @(cond_futex,r8), r0
135 mov.l r0, @(cond_futex,r8)
136 mov #(1 << nwaiters_shift), r2
137 mov.l @(cond_nwaiters,r8), r0
139 mov.l r0, @(cond_nwaiters,r8)
141 /* Get and store current wakeup_seq value. */
142 mov.l @(wakeup_seq,r8), r10
143 mov.l @(wakeup_seq+4,r8), r11
144 mov.l @(broadcast_seq,r8), r0
148 /* Get current time. */
149 #ifdef __NR_clock_gettime
150 /* Get the clock number. */
151 mov.l @(cond_nwaiters,r8), r4
152 mov #((1 << nwaiters_shift) - 1), r0
154 /* Only clocks 0 and 1 are allowed. Both are handled in the
158 mov.w .L__NR_clock_gettime, r3
162 /* Compute relative timeout. */
168 .L__NR_clock_gettime:
169 .word __NR_clock_gettime
176 mov #__NR_gettimeofday, r3
180 /* Compute relative timeout. */
183 dmulu.l r0, r1 /* Micro seconds to nano seconds. */
200 bf 6f /* Time is already up. */
202 /* Store relative timeout. */
205 mov.l @(cond_futex,r8), r1
210 DEC (@(cond_lock,r8), r2)
228 mov.l @(dep_mutex,r8), r0
232 #ifdef __ASSUME_PRIVATE_FUTEX
233 mov #(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), r5
263 CMPXCHG (r3, @(cond_lock,r8), r4, r2)
265 CMPXCHG (r3, @r8, r4, r2)
269 mov.l @(broadcast_seq,r8), r0
274 mov.l @(woken_seq,r8), r0
275 mov.l @(woken_seq+4,r8), r1
277 mov.l @(wakeup_seq,r8), r2
278 mov.l @(wakeup_seq+4,r8), r3
291 cmp/eq #-ETIMEDOUT, r0
298 mov.l @(wakeup_seq,r8),r0
299 mov.l @(wakeup_seq+4,r8),r1
302 mov.l r0,@(wakeup_seq,r8)
303 mov.l r1,@(wakeup_seq+4,r8)
304 mov.l @(cond_futex,r8),r0
306 mov.l r0,@(cond_futex,r8)
324 mov.l @(woken_seq,r8),r0
325 mov.l @(woken_seq+4,r8),r1
328 mov.l r0,@(woken_seq,r8)
329 mov.l r1,@(woken_seq+4,r8)
332 mov #(1 << nwaiters_shift), r2
333 mov.l @(cond_nwaiters,r8),r0
335 mov.l r0,@(cond_nwaiters,r8)
337 /* Wake up a thread which wants to destroy the condvar object. */
338 mov.l @(total_seq,r8),r0
339 mov.l @(total_seq+4,r8),r1
344 mov #((1 << nwaiters_shift) - 1), r1
346 mov.l @(cond_nwaiters,r8),r0
351 add #cond_nwaiters, r4
352 mov.l @(dep_mutex,r8), r0
356 #ifdef __ASSUME_PRIVATE_FUTEX
357 mov #(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5
377 DEC (@(cond_lock,r8), r2)
391 /* We return the result of the mutex_lock operation if it failed. */
399 cfi_adjust_cfa_offset (-64)
401 cfi_adjust_cfa_offset (-4)
404 cfi_adjust_cfa_offset (-4)
407 cfi_adjust_cfa_offset (-4)
410 cfi_adjust_cfa_offset (-4)
413 cfi_adjust_cfa_offset (-4)
416 cfi_adjust_cfa_offset (-4)
420 /* Omit CFI for restore in delay slot. */
423 #ifndef __ASSUME_PRIVATE_FUTEX
425 .word PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
431 .long __pthread_mutex_unlock_usercnt-.Lmunlock1b
433 .long __pthread_enable_asynccancel-.Lenable1b
435 .long __pthread_disable_asynccancel-.Ldisable1b
437 .long __pthread_mutex_cond_lock-.Lmlocki1b
442 /* Initial locking failed. */
447 mov.l @(dep_mutex,r8), r0
462 /* Unlock in loop requires wakeup. */
467 mov.l @(dep_mutex,r8), r0
481 /* Locking in loop failed. */
486 mov.l @(dep_mutex,r8), r0
501 /* Unlock after loop requires wakeup. */
506 mov.l @(dep_mutex,r8), r0
520 /* The initial unlocking of the mutex failed. */
523 DEC (@(cond_lock,r8), r2)
534 mov.l @(dep_mutex,r8), r0
550 .long __lll_lock_wait-.Lwait2b
552 .long __lll_unlock_wake-.Lmwait2b
554 .long __lll_lock_wait-.Lwait3b
556 .long __lll_unlock_wake-.Lmwait3b
558 .long __lll_unlock_wake-.Lmwait4b
559 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
560 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
564 .type __condvar_tw_cleanup, @function
565 __condvar_tw_cleanup:
568 /* Get internal lock. */
572 CMPXCHG (r3, @(cond_lock,r8), r4, r2)
574 CMPXCHG (r3, @r8, r4, r2)
583 mov.l @(dep_mutex,r8), r0
596 mov.l @(broadcast_seq,r8), r0
604 /* We increment the wakeup_seq counter only if it is lower than
605 total_seq. If this is not the case the thread was woken and
606 then canceled. In this case we ignore the signal. */
607 mov.l @(total_seq+4,r8), r0
608 mov.l @(wakeup_seq+4,r8), r1
613 mov.l @(total_seq,r8), r0
614 mov.l @(wakeup_seq,r8), r1
620 mov.l @(wakeup_seq,r8),r0
621 mov.l @(wakeup_seq+4,r8),r1
624 mov.l r0,@(wakeup_seq,r8)
625 mov.l r1,@(wakeup_seq+4,r8)
626 mov.l @(cond_futex,r8),r0
628 mov.l r0,@(cond_futex,r8)
632 mov.l @(woken_seq,r8),r0
633 mov.l @(woken_seq+4,r8),r1
636 mov.l r0,@(woken_seq,r8)
637 mov.l r1,@(woken_seq+4,r8)
640 mov #(1 << nwaiters_shift), r2
641 mov.l @(cond_nwaiters,r8),r0
643 mov.l r0,@(cond_nwaiters,r8)
645 /* Wake up a thread which wants to destroy the condvar object. */
647 mov.l @(total_seq,r8),r0
648 mov.l @(total_seq+4,r8),r1
653 mov #((1 << nwaiters_shift) - 1), r1
655 mov.l @(cond_nwaiters,r8),r0
660 add #cond_nwaiters, r4
672 DEC (@(cond_lock,r8), r2)
683 mov.l @(dep_mutex,r8), r0
695 /* Wake up all waiters to make sure no signal gets lost. */
702 shlr r6 /* r6 = 0x7fffffff */
726 .long __lll_lock_wait-.Lwait5b
728 .long __lll_unlock_wake-.Lmwait5b
730 .long __pthread_mutex_cond_lock-.Lmlocki5b
733 .long _Unwind_Resume@GOTOFF
739 .size __condvar_tw_cleanup, .-__condvar_tw_cleanup
742 .section .gcc_except_table,"a",@progbits
744 .byte DW_EH_PE_omit ! @LPStart format (omit)
745 .byte DW_EH_PE_omit ! @TType format (omit)
746 .byte DW_EH_PE_sdata4 ! call-site format
747 .uleb128 .Lcstend-.Lcstbegin
749 .ualong .LcleanupSTART-.LSTARTCODE
750 .ualong .LcleanupEND-.LcleanupSTART
751 .ualong __condvar_tw_cleanup-.LSTARTCODE
753 .ualong .LcallUR-.LSTARTCODE
754 .ualong .LENDCODE-.LcallUR
761 .hidden DW.ref.__gcc_personality_v0
762 .weak DW.ref.__gcc_personality_v0
763 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
765 .type DW.ref.__gcc_personality_v0, @object
766 .size DW.ref.__gcc_personality_v0, 4
767 DW.ref.__gcc_personality_v0:
768 .long __gcc_personality_v0