1 /* Copyright (C) 2002-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, 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 <tcb-offsets.h>
25 #include <pthread-pi-defines.h>
27 #include <kernel-features.h>
32 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
33 .globl __pthread_cond_wait
34 .type __pthread_cond_wait, @function
40 cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
41 DW.ref.__gcc_personality_v0)
42 cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
44 cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
45 cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
49 leaq -FRAME_SIZE(%rsp), %rsp
50 cfi_adjust_cfa_offset(FRAME_SIZE)
55 +--------------------------+
56 rsp + 24 | old wake_seq value |
57 +--------------------------+
58 rsp + 16 | mutex pointer |
59 +--------------------------+
60 rsp + 8 | condvar pointer |
61 +--------------------------+
62 rsp + 4 | old broadcast_seq value |
63 +--------------------------+
64 rsp + 0 | old cancellation mode |
65 +--------------------------+
68 cmpq $-1, dep_mutex(%rdi)
70 /* Prepare structure passed to cancellation handler. */
75 movq %rsi, dep_mutex(%rdi)
77 /* Get internal lock. */
84 cmpxchgl %esi, cond_lock(%rdi)
88 /* Unlock the mutex. */
89 2: movq 16(%rsp), %rdi
91 callq __pthread_mutex_unlock_usercnt
99 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
101 /* Get and store current wakeup_seq value. */
103 movq wakeup_seq(%rdi), %r9
104 movl broadcast_seq(%rdi), %edx
109 8: movl cond_futex(%rdi), %edx
119 4: callq __pthread_enable_asynccancel
123 cmpq $-1, dep_mutex(%rdi)
124 leaq cond_futex(%rdi), %rdi
125 movl $FUTEX_WAIT, %esi
128 movq dep_mutex-cond_futex(%rdi), %r8
129 /* Requeue to a non-robust PI mutex if the PI bit is set and
130 the robust bit is not set. */
131 movl MUTEX_KIND(%r8), %eax
132 andl $(ROBUST_BIT|PI_BIT), %eax
136 movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
137 movl $SYS_futex, %eax
141 #ifdef __ASSUME_REQUEUE_PI
147 # ifndef __ASSUME_PRIVATE_FUTEX
148 movl $FUTEX_WAIT, %esi
153 #ifdef __ASSUME_PRIVATE_FUTEX
154 movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
156 orl %fs:PRIVATE_FUTEX, %esi
159 movl $SYS_futex, %eax
162 62: movl (%rsp), %edi
163 callq __pthread_disable_asynccancel
172 cmpxchgl %esi, (%rdi)
174 cmpxchgl %esi, cond_lock(%rdi)
178 6: movl broadcast_seq(%rdi), %edx
180 movq woken_seq(%rdi), %rax
182 movq wakeup_seq(%rdi), %r9
196 16: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
198 /* Wake up a thread which wants to destroy the condvar object. */
199 cmpq $0xffffffffffffffff, total_seq(%rdi)
201 movl cond_nwaiters(%rdi), %eax
202 andl $~((1 << nwaiters_shift) - 1), %eax
205 addq $cond_nwaiters, %rdi
206 cmpq $-1, dep_mutex-cond_nwaiters(%rdi)
208 #ifdef __ASSUME_PRIVATE_FUTEX
209 movl $FUTEX_WAKE, %eax
210 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
214 movl %fs:PRIVATE_FUTEX, %esi
216 orl $FUTEX_WAKE, %esi
218 movl $SYS_futex, %eax
220 subq $cond_nwaiters, %rdi
230 /* If requeue_pi is used the kernel performs the locking of the
232 11: movq 16(%rsp), %rdi
236 callq __pthread_mutex_cond_lock
238 14: leaq FRAME_SIZE(%rsp), %rsp
239 cfi_adjust_cfa_offset(-FRAME_SIZE)
241 /* We return the result of the mutex_lock operation. */
244 cfi_adjust_cfa_offset(FRAME_SIZE)
246 18: callq __pthread_mutex_cond_lock_adjust
250 /* Initial locking failed. */
253 addq $cond_lock, %rdi
255 cmpq $-1, dep_mutex-cond_lock(%rdi)
256 movl $LLL_PRIVATE, %eax
257 movl $LLL_SHARED, %esi
259 callq __lll_lock_wait
262 /* Unlock in loop requires wakeup. */
265 addq $cond_lock, %rdi
267 cmpq $-1, dep_mutex-cond_lock(%rdi)
268 movl $LLL_PRIVATE, %eax
269 movl $LLL_SHARED, %esi
271 /* The call preserves %rdx. */
272 callq __lll_unlock_wake
274 subq $cond_lock, %rdi
278 /* Locking in loop failed. */
281 addq $cond_lock, %rdi
283 cmpq $-1, dep_mutex-cond_lock(%rdi)
284 movl $LLL_PRIVATE, %eax
285 movl $LLL_SHARED, %esi
287 callq __lll_lock_wait
289 subq $cond_lock, %rdi
293 /* Unlock after loop requires wakeup. */
296 addq $cond_lock, %rdi
298 cmpq $-1, dep_mutex-cond_lock(%rdi)
299 movl $LLL_PRIVATE, %eax
300 movl $LLL_SHARED, %esi
302 callq __lll_unlock_wake
305 /* The initial unlocking of the mutex failed. */
317 addq $cond_lock, %rdi
319 cmpq $-1, dep_mutex-cond_lock(%rdi)
320 movl $LLL_PRIVATE, %eax
321 movl $LLL_SHARED, %esi
323 callq __lll_unlock_wake
327 .size __pthread_cond_wait, .-__pthread_cond_wait
328 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
333 .type __condvar_cleanup1, @function
334 .globl __condvar_cleanup1
335 .hidden __condvar_cleanup1
340 +--------------------------+
342 +--------------------------+
343 rsp + 16 | mutex pointer |
344 +--------------------------+
345 rsp + 8 | condvar pointer |
346 +--------------------------+
347 rsp + 4 | old broadcast_seq value |
348 +--------------------------+
349 rsp + 0 | old cancellation mode |
350 +--------------------------+
355 /* Get internal lock. */
361 cmpxchgl %esi, (%rdi)
363 cmpxchgl %esi, cond_lock(%rdi)
368 addq $cond_lock, %rdi
370 cmpq $-1, dep_mutex-cond_lock(%rdi)
371 movl $LLL_PRIVATE, %eax
372 movl $LLL_SHARED, %esi
374 callq __lll_lock_wait
376 subq $cond_lock, %rdi
379 1: movl broadcast_seq(%rdi), %edx
383 /* We increment the wakeup_seq counter only if it is lower than
384 total_seq. If this is not the case the thread was woken and
385 then canceled. In this case we ignore the signal. */
386 movq total_seq(%rdi), %rax
387 cmpq wakeup_seq(%rdi), %rax
389 incq wakeup_seq(%rdi)
390 incl cond_futex(%rdi)
391 6: incq woken_seq(%rdi)
393 3: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
395 /* Wake up a thread which wants to destroy the condvar object. */
397 cmpq $0xffffffffffffffff, total_seq(%rdi)
399 movl cond_nwaiters(%rdi), %eax
400 andl $~((1 << nwaiters_shift) - 1), %eax
403 cmpq $-1, dep_mutex(%rdi)
404 leaq cond_nwaiters(%rdi), %rdi
406 #ifdef __ASSUME_PRIVATE_FUTEX
407 movl $FUTEX_WAKE, %eax
408 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
412 movl %fs:PRIVATE_FUTEX, %esi
414 orl $FUTEX_WAKE, %esi
416 movl $SYS_futex, %eax
418 subq $cond_nwaiters, %rdi
429 addq $cond_lock, %rdi
431 cmpq $-1, dep_mutex-cond_lock(%rdi)
432 movl $LLL_PRIVATE, %eax
433 movl $LLL_SHARED, %esi
435 /* The call preserves %rcx. */
436 callq __lll_unlock_wake
438 /* Wake up all waiters to make sure no signal gets lost. */
441 addq $cond_futex, %rdi
442 cmpq $-1, dep_mutex-cond_futex(%rdi)
443 movl $0x7fffffff, %edx
444 #ifdef __ASSUME_PRIVATE_FUTEX
445 movl $FUTEX_WAKE, %eax
446 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
450 movl %fs:PRIVATE_FUTEX, %esi
452 orl $FUTEX_WAKE, %esi
454 movl $SYS_futex, %eax
457 5: movq 16(%rsp), %rdi
458 callq __pthread_mutex_cond_lock
462 call _Unwind_Resume@PLT
466 .size __condvar_cleanup1, .-__condvar_cleanup1
469 .section .gcc_except_table,"a",@progbits
471 .byte DW_EH_PE_omit # @LPStart format
472 .byte DW_EH_PE_omit # @TType format
473 .byte DW_EH_PE_uleb128 # call-site format
474 .uleb128 .Lcstend-.Lcstbegin
476 .uleb128 .LcleanupSTART-.LSTARTCODE
477 .uleb128 .LcleanupEND-.LcleanupSTART
478 .uleb128 __condvar_cleanup1-.LSTARTCODE
480 .uleb128 .LcallUR-.LSTARTCODE
481 .uleb128 .LENDCODE-.LcallUR
488 .hidden DW.ref.__gcc_personality_v0
489 .weak DW.ref.__gcc_personality_v0
490 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
492 .type DW.ref.__gcc_personality_v0, @object
493 .size DW.ref.__gcc_personality_v0, 8
494 DW.ref.__gcc_personality_v0:
495 .quad __gcc_personality_v0