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, see
17 <http://www.gnu.org/licenses/>. */
20 #include <lowlevellock.h>
21 #include <lowlevelcond.h>
22 #include <tcb-offsets.h>
23 #include <pthread-pi-defines.h>
25 #include <bits/kernel-features.h>
30 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
31 .globl __pthread_cond_wait
32 .type __pthread_cond_wait, @function
33 .protected __pthread_cond_wait
40 leaq -FRAME_SIZE(%rsp), %rsp
41 cfi_adjust_cfa_offset(FRAME_SIZE)
46 +--------------------------+
47 rsp + 24 | old wake_seq value |
48 +--------------------------+
49 rsp + 16 | mutex pointer |
50 +--------------------------+
51 rsp + 8 | condvar pointer |
52 +--------------------------+
53 rsp + 4 | old broadcast_seq value |
54 +--------------------------+
55 rsp + 0 | old cancellation mode |
56 +--------------------------+
59 cmpq $-1, dep_mutex(%rdi)
61 /* Prepare structure passed to cancellation handler. */
66 movq %rsi, dep_mutex(%rdi)
68 /* Get internal lock. */
75 cmpxchgl %esi, cond_lock(%rdi)
79 /* Unlock the mutex. */
80 2: movq 16(%rsp), %rdi
82 callq __pthread_mutex_unlock_usercnt
90 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
92 /* Get and store current wakeup_seq value. */
94 movq wakeup_seq(%rdi), %r9
95 movl broadcast_seq(%rdi), %edx
100 8: movl cond_futex(%rdi), %edx
110 4: callq __pthread_enable_asynccancel
114 cmpq $-1, dep_mutex(%rdi)
115 leaq cond_futex(%rdi), %rdi
116 movl $FUTEX_WAIT, %esi
119 movq dep_mutex-cond_futex(%rdi), %r8
120 /* Requeue to a non-robust PI mutex if the PI bit is set and
121 the robust bit is not set. */
122 movl MUTEX_KIND(%r8), %eax
123 andl $(ROBUST_BIT|PI_BIT), %eax
127 movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
128 movl $SYS_futex, %eax
132 #ifdef __ASSUME_REQUEUE_PI
138 # ifndef __ASSUME_PRIVATE_FUTEX
139 movl $FUTEX_WAIT, %esi
144 #ifdef __ASSUME_PRIVATE_FUTEX
145 movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
147 orl %fs:PRIVATE_FUTEX, %esi
150 movl $SYS_futex, %eax
153 62: movl (%rsp), %edi
154 callq __pthread_disable_asynccancel
163 cmpxchgl %esi, (%rdi)
165 cmpxchgl %esi, cond_lock(%rdi)
169 6: movl broadcast_seq(%rdi), %edx
171 movq woken_seq(%rdi), %rax
173 movq wakeup_seq(%rdi), %r9
187 16: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
189 /* Wake up a thread which wants to destroy the condvar object. */
190 cmpq $0xffffffffffffffff, total_seq(%rdi)
192 movl cond_nwaiters(%rdi), %eax
193 andl $~((1 << nwaiters_shift) - 1), %eax
196 addq $cond_nwaiters, %rdi
197 cmpq $-1, dep_mutex-cond_nwaiters(%rdi)
199 #ifdef __ASSUME_PRIVATE_FUTEX
200 movl $FUTEX_WAKE, %eax
201 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
205 movl %fs:PRIVATE_FUTEX, %esi
207 orl $FUTEX_WAKE, %esi
209 movl $SYS_futex, %eax
211 subq $cond_nwaiters, %rdi
221 /* If requeue_pi is used the kernel performs the locking of the
223 11: movq 16(%rsp), %rdi
227 callq __pthread_mutex_cond_lock
229 14: leaq FRAME_SIZE(%rsp), %rsp
230 cfi_adjust_cfa_offset(-FRAME_SIZE)
232 /* We return the result of the mutex_lock operation. */
235 cfi_adjust_cfa_offset(FRAME_SIZE)
237 18: callq __pthread_mutex_cond_lock_adjust
241 /* Initial locking failed. */
244 addq $cond_lock, %rdi
246 cmpq $-1, dep_mutex-cond_lock(%rdi)
247 movl $LLL_PRIVATE, %eax
248 movl $LLL_SHARED, %esi
250 callq __lll_lock_wait
253 /* Unlock in loop requires wakeup. */
256 addq $cond_lock, %rdi
258 cmpq $-1, dep_mutex-cond_lock(%rdi)
259 movl $LLL_PRIVATE, %eax
260 movl $LLL_SHARED, %esi
262 /* The call preserves %rdx. */
263 callq __lll_unlock_wake
265 subq $cond_lock, %rdi
269 /* Locking in loop failed. */
272 addq $cond_lock, %rdi
274 cmpq $-1, dep_mutex-cond_lock(%rdi)
275 movl $LLL_PRIVATE, %eax
276 movl $LLL_SHARED, %esi
278 callq __lll_lock_wait
280 subq $cond_lock, %rdi
284 /* Unlock after loop requires wakeup. */
287 addq $cond_lock, %rdi
289 cmpq $-1, dep_mutex-cond_lock(%rdi)
290 movl $LLL_PRIVATE, %eax
291 movl $LLL_SHARED, %esi
293 callq __lll_unlock_wake
296 /* The initial unlocking of the mutex failed. */
308 addq $cond_lock, %rdi
310 cmpq $-1, dep_mutex-cond_lock(%rdi)
311 movl $LLL_PRIVATE, %eax
312 movl $LLL_SHARED, %esi
314 callq __lll_unlock_wake
318 .size __pthread_cond_wait, .-__pthread_cond_wait
319 weak_alias(__pthread_cond_wait, pthread_cond_wait)
323 .type __condvar_cleanup1, @function
324 .globl __condvar_cleanup1
325 .hidden __condvar_cleanup1
330 +--------------------------+
332 +--------------------------+
333 rsp + 16 | mutex pointer |
334 +--------------------------+
335 rsp + 8 | condvar pointer |
336 +--------------------------+
337 rsp + 4 | old broadcast_seq value |
338 +--------------------------+
339 rsp + 0 | old cancellation mode |
340 +--------------------------+
345 /* Get internal lock. */
351 cmpxchgl %esi, (%rdi)
353 cmpxchgl %esi, cond_lock(%rdi)
358 addq $cond_lock, %rdi
360 cmpq $-1, dep_mutex-cond_lock(%rdi)
361 movl $LLL_PRIVATE, %eax
362 movl $LLL_SHARED, %esi
364 callq __lll_lock_wait
366 subq $cond_lock, %rdi
369 1: movl broadcast_seq(%rdi), %edx
373 /* We increment the wakeup_seq counter only if it is lower than
374 total_seq. If this is not the case the thread was woken and
375 then canceled. In this case we ignore the signal. */
376 movq total_seq(%rdi), %rax
377 cmpq wakeup_seq(%rdi), %rax
379 incq wakeup_seq(%rdi)
380 incl cond_futex(%rdi)
381 6: incq woken_seq(%rdi)
383 3: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
385 /* Wake up a thread which wants to destroy the condvar object. */
387 cmpq $0xffffffffffffffff, total_seq(%rdi)
389 movl cond_nwaiters(%rdi), %eax
390 andl $~((1 << nwaiters_shift) - 1), %eax
393 cmpq $-1, dep_mutex(%rdi)
394 leaq cond_nwaiters(%rdi), %rdi
396 #ifdef __ASSUME_PRIVATE_FUTEX
397 movl $FUTEX_WAKE, %eax
398 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
402 movl %fs:PRIVATE_FUTEX, %esi
404 orl $FUTEX_WAKE, %esi
406 movl $SYS_futex, %eax
408 subq $cond_nwaiters, %rdi
419 addq $cond_lock, %rdi
421 cmpq $-1, dep_mutex-cond_lock(%rdi)
422 movl $LLL_PRIVATE, %eax
423 movl $LLL_SHARED, %esi
425 /* The call preserves %rcx. */
426 callq __lll_unlock_wake
428 /* Wake up all waiters to make sure no signal gets lost. */
431 addq $cond_futex, %rdi
432 cmpq $-1, dep_mutex-cond_futex(%rdi)
433 movl $0x7fffffff, %edx
434 #ifdef __ASSUME_PRIVATE_FUTEX
435 movl $FUTEX_WAKE, %eax
436 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
440 movl %fs:PRIVATE_FUTEX, %esi
442 orl $FUTEX_WAKE, %esi
444 movl $SYS_futex, %eax
447 5: movq 16(%rsp), %rdi
448 callq __pthread_mutex_cond_lock
452 call _Unwind_Resume@PLT
456 .size __condvar_cleanup1, .-__condvar_cleanup1
459 .section .gcc_except_table,"a",@progbits
461 .byte DW_EH_PE_omit # @LPStart format
462 .byte DW_EH_PE_omit # @TType format
463 .byte DW_EH_PE_uleb128 # call-site format
464 .uleb128 .Lcstend-.Lcstbegin
466 .uleb128 .LcleanupSTART-.LSTARTCODE
467 .uleb128 .LcleanupEND-.LcleanupSTART
468 .uleb128 __condvar_cleanup1-.LSTARTCODE
470 .uleb128 .LcallUR-.LSTARTCODE
471 .uleb128 .LENDCODE-.LcallUR
478 .hidden DW.ref.__gcc_personality_v0
479 .weak DW.ref.__gcc_personality_v0
480 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
482 .type DW.ref.__gcc_personality_v0, @object
483 .size DW.ref.__gcc_personality_v0, 8
484 DW.ref.__gcc_personality_v0:
485 .quad __gcc_personality_v0