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 <tcb-offsets.h>
23 #include <kernel-features.h>
24 #include "lowlevel-atomic.h"
28 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
29 .globl __pthread_cond_wait
30 .type __pthread_cond_wait, @function
36 cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
37 DW.ref.__gcc_personality_v0)
38 cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
40 cfi_personality(DW_EH_PE_absptr, __gcc_personality_v0)
41 cfi_lsda(DW_EH_PE_absptr, .LexceptSTART)
44 cfi_adjust_cfa_offset (4)
45 cfi_rel_offset (r8, 0)
47 cfi_adjust_cfa_offset (4)
48 cfi_rel_offset (r9, 0)
50 cfi_adjust_cfa_offset (4)
51 cfi_rel_offset (r10, 0)
53 cfi_adjust_cfa_offset (4)
54 cfi_rel_offset (r11, 0)
56 cfi_adjust_cfa_offset (4)
57 cfi_rel_offset (r12, 0)
59 cfi_adjust_cfa_offset (4)
60 cfi_rel_offset (pr, 0)
62 cfi_adjust_cfa_offset (48)
72 /* Get internal lock. */
76 CMPXCHG (r3, @(cond_lock,r8), r4, r2)
78 CMPXCHG (r3, @r8, r4, r2)
86 .long _GLOBAL_OFFSET_TABLE_
90 /* Store the reference to the mutex. If there is already a
91 different value in there this is a bad user bug. */
92 mov.l @(dep_mutex,r8),r0
95 mov.l r9, @(dep_mutex,r8)
98 /* Unlock the mutex. */
114 mov.l @(total_seq,r8),r0
115 mov.l @(total_seq+4,r8),r1
118 mov.l r0,@(total_seq,r8)
119 mov.l r1,@(total_seq+4,r8)
120 mov.l @(cond_futex,r8),r0
122 mov.l r0,@(cond_futex,r8)
123 mov #(1 << nwaiters_shift), r2
124 mov.l @(cond_nwaiters,r8), r0
126 mov.l r0, @(cond_nwaiters,r8)
128 /* Get and store current wakeup_seq value. */
129 mov.l @(wakeup_seq,r8), r10
130 mov.l @(wakeup_seq+4,r8), r11
131 mov.l @(broadcast_seq,r8), r0
135 mov.l @(cond_futex,r8),r0
140 DEC (@(cond_lock,r8), r2)
155 mov.l @(dep_mutex,r8), r0
159 #ifdef __ASSUME_PRIVATE_FUTEX
160 mov #(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), r5
189 CMPXCHG (r3, @(cond_lock,r8), r4, r2)
191 CMPXCHG (r3, @r8, r4, r2)
195 mov.l @(broadcast_seq,r8), r0
200 mov.l @(woken_seq,r8), r0
201 mov.l @(woken_seq+4,r8), r1
203 mov.l @(wakeup_seq,r8), r2
204 mov.l @(wakeup_seq+4,r8), r3
220 mov.l @(woken_seq,r8),r0
221 mov.l @(woken_seq+4,r8),r1
224 mov.l r0,@(woken_seq,r8)
225 mov.l r1,@(woken_seq+4,r8)
228 mov #(1 << nwaiters_shift), r2
229 mov.l @(cond_nwaiters,r8),r0
231 mov.l r0,@(cond_nwaiters,r8)
233 /* Wake up a thread which wants to destroy the condvar object. */
234 mov.l @(total_seq,r8),r0
235 mov.l @(total_seq+4,r8),r1
240 mov #((1 << nwaiters_shift) - 1), r1
242 mov.l @(cond_nwaiters,r8),r0
247 add #cond_nwaiters, r4
248 mov.l @(dep_mutex,r8), r0
252 #ifdef __ASSUME_PRIVATE_FUTEX
253 mov #(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5
273 DEC (@(cond_lock,r8), r2)
285 /* We return the result of the mutex_lock operation. */
290 cfi_adjust_cfa_offset (-48)
292 cfi_adjust_cfa_offset (-4)
295 cfi_adjust_cfa_offset (-4)
298 cfi_adjust_cfa_offset (-4)
301 cfi_adjust_cfa_offset (-4)
304 cfi_adjust_cfa_offset (-4)
308 /* Omit CFI for restore in delay slot. */
311 #ifndef __ASSUME_PRIVATE_FUTEX
313 .word PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
317 .long __pthread_mutex_unlock_usercnt-.Lmunlock0b
319 .long __pthread_enable_asynccancel-.Lenable0b
321 .long __pthread_disable_asynccancel-.Ldisable0b
323 .long __pthread_mutex_cond_lock-.Lmlocki0b
326 /* Initial locking failed. */
331 mov.l @(dep_mutex,r8), r0
345 /* Unlock in loop requires waekup. */
350 mov.l @(dep_mutex,r8), r0
364 /* Locking in loop failed. */
369 mov.l @(dep_mutex,r8), r0
384 /* Unlock after loop requires wakeup. */
389 mov.l @(dep_mutex,r8), r0
403 /* The initial unlocking of the mutex failed. */
406 DEC (@(cond_lock,r8), r2)
417 mov.l @(dep_mutex,r8), r0
434 .long __lll_lock_wait-.Lwait0b
436 .long __lll_unlock_wake-.Lwake0b
438 .long __lll_lock_wait-.Lwait1b
440 .long __lll_unlock_wake-.Lwake1b
442 .long __lll_unlock_wake-.Lwake2b
443 .size __pthread_cond_wait, .-__pthread_cond_wait
444 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
448 .type __condvar_w_cleanup, @function
452 /* Get internal lock. */
456 CMPXCHG (r3, @(cond_lock,r8), r4, r2)
458 CMPXCHG (r3, @r8, r4, r2)
467 mov.l @(dep_mutex,r8), r0
480 mov.l @(broadcast_seq,r8), r0
488 /* We increment the wakeup_seq counter only if it is lower than
489 total_seq. If this is not the case the thread was woken and
490 then canceled. In this case we ignore the signal. */
491 mov.l @(total_seq+4,r8), r0
492 mov.l @(wakeup_seq+4,r8), r1
497 mov.l @(total_seq,r8), r0
498 mov.l @(wakeup_seq,r8), r1
504 mov.l @(wakeup_seq,r8),r0
505 mov.l @(wakeup_seq+4,r8),r1
508 mov.l r0,@(wakeup_seq,r8)
509 mov.l r1,@(wakeup_seq+4,r8)
510 mov.l @(cond_futex,r8),r0
512 mov.l r0,@(cond_futex,r8)
516 mov.l @(woken_seq,r8),r0
517 mov.l @(woken_seq+4,r8),r1
520 mov.l r0,@(woken_seq,r8)
521 mov.l r1,@(woken_seq+4,r8)
524 mov #(1 << nwaiters_shift), r2
525 mov.l @(cond_nwaiters,r8),r0
527 mov.l r0,@(cond_nwaiters,r8)
529 /* Wake up a thread which wants to destroy the condvar object. */
531 mov.l @(total_seq,r8),r0
532 mov.l @(total_seq+4,r8),r1
537 mov #((1 << nwaiters_shift) - 1), r1
539 mov.l @(cond_nwaiters,r8),r0
544 add #cond_nwaiters, r4
545 mov.l @(dep_mutex,r8), r0
549 #ifdef __ASSUME_PRIVATE_FUTEX
550 mov #(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5
571 DEC (@(cond_lock,r8), r2)
582 mov.l @(dep_mutex,r8), r0
594 /* Wake up all waiters to make sure no signal gets lost. */
599 mov.l @(dep_mutex,r8), r0
603 #ifdef __ASSUME_PRIVATE_FUTEX
604 mov #(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5
616 shlr r6 /* r6 = 0x7fffffff */
638 #ifndef __ASSUME_PRIVATE_FUTEX
640 .word PRIVATE_FUTEX - TLS_PRE_TCB_SIZE
644 .long __lll_lock_wait-.Lwait3b
646 .long __lll_unlock_wake-.Lwake3b
648 .long __pthread_mutex_cond_lock-.Lmlocki3b
651 .long _Unwind_Resume@GOTOFF
657 .size __condvar_w_cleanup, .-__condvar_w_cleanup
660 .section .gcc_except_table,"a",@progbits
662 .byte DW_EH_PE_omit ! @LPStart format (omit)
663 .byte DW_EH_PE_omit ! @TType format (omit)
664 .byte DW_EH_PE_sdata4 ! call-site format
665 .uleb128 .Lcstend-.Lcstbegin
667 .ualong .LcleanupSTART-.LSTARTCODE
668 .ualong .LcleanupEND-.LcleanupSTART
669 .ualong __condvar_w_cleanup-.LSTARTCODE
671 .ualong .LcallUR-.LSTARTCODE
672 .ualong .LENDCODE-.LcallUR
679 .hidden DW.ref.__gcc_personality_v0
680 .weak DW.ref.__gcc_personality_v0
681 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
683 .type DW.ref.__gcc_personality_v0, @object
684 .size DW.ref.__gcc_personality_v0, 4
685 DW.ref.__gcc_personality_v0:
686 .long __gcc_personality_v0