1 /* Copyright (C) 2002,2003,2004,2005,2006,2007 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>
26 #include <kernel-features.h>
32 .type __condvar_cleanup, @function
33 .globl __condvar_cleanup
34 .hidden __condvar_cleanup
38 /* Get internal lock. */
47 cmpxchgl %esi, cond_lock(%rdi)
54 cmpq $-1, dep_mutex-cond_lock(%rdi)
55 movl $LLL_PRIVATE, %eax
56 movl $LLL_SHARED, %esi
63 1: movl broadcast_seq(%rdi), %edx
67 /* We increment the wakeup_seq counter only if it is lower than
68 total_seq. If this is not the case the thread was woken and
69 then canceled. In this case we ignore the signal. */
70 movq total_seq(%rdi), %rax
71 cmpq wakeup_seq(%rdi), %rax
75 6: incq woken_seq(%rdi)
77 3: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
79 /* Wake up a thread which wants to destroy the condvar object. */
81 cmpq $0xffffffffffffffff, total_seq(%rdi)
83 movl cond_nwaiters(%rdi), %eax
84 andl $~((1 << nwaiters_shift) - 1), %eax
87 addq $cond_nwaiters, %rdi
88 cmpq $-1, dep_mutex-cond_nwaiters(%rdi)
90 #ifdef __ASSUME_PRIVATE_FUTEX
91 movl $FUTEX_WAKE, %eax
92 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
96 movl %fs:PRIVATE_FUTEX, %esi
100 movl $SYS_futex, %eax
102 subq $cond_nwaiters, %rdi
113 addq $cond_lock, %rdi
115 cmpq $-1, dep_mutex-cond_lock(%rdi)
116 movl $LLL_PRIVATE, %eax
117 movl $LLL_SHARED, %esi
119 callq __lll_unlock_wake
121 /* Wake up all waiters to make sure no signal gets lost. */
124 addq $cond_futex, %rdi
125 cmpq $-1, dep_mutex-cond_futex(%rdi)
126 movl $0x7fffffff, %edx
127 #ifdef __ASSUME_PRIVATE_FUTEX
128 movl $FUTEX_WAKE, %eax
129 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
133 movl %fs:PRIVATE_FUTEX, %esi
135 orl $FUTEX_WAKE, %esi
137 movl $SYS_futex, %eax
140 5: movq 16(%r8), %rdi
141 callq __pthread_mutex_cond_lock
146 .size __condvar_cleanup, .-__condvar_cleanup
149 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
150 .globl __pthread_cond_wait
151 .type __pthread_cond_wait, @function
157 #define FRAME_SIZE 64
158 subq $FRAME_SIZE, %rsp
163 +--------------------------+
164 rsp + 32 | cleanup buffer |
165 +--------------------------+
166 rsp + 24 | old wake_seq value |
167 +--------------------------+
168 rsp + 16 | mutex pointer |
169 +--------------------------+
170 rsp + 8 | condvar pointer |
171 +--------------------------+
172 rsp + 4 | old broadcast_seq value |
173 +--------------------------+
174 rsp + 0 | old cancellation mode |
175 +--------------------------+
178 cmpq $-1, dep_mutex(%rdi)
180 /* Prepare structure passed to cancellation handler. */
185 movq %rsi, dep_mutex(%rdi)
187 /* Get internal lock. */
192 cmpxchgl %esi, (%rdi)
194 cmpxchgl %esi, cond_lock(%rdi)
198 /* Unlock the mutex. */
199 2: movq 16(%rsp), %rdi
201 callq __pthread_mutex_unlock_usercnt
208 incl cond_futex(%rdi)
209 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
211 /* Install cancellation handler. */
213 leaq __condvar_cleanup(%rip), %rsi
215 leaq __condvar_cleanup, %rsi
219 callq __pthread_cleanup_push
221 /* Get and store current wakeup_seq value. */
223 movq wakeup_seq(%rdi), %r9
224 movl broadcast_seq(%rdi), %edx
229 8: movl cond_futex(%rdi), %r12d
238 4: callq __pthread_enable_asynccancel
244 addq $cond_futex-cond_lock, %rdi
245 cmpq $-1, dep_mutex-cond_futex(%rdi)
246 #ifdef __ASSUME_PRIVATE_FUTEX
247 movl $FUTEX_WAIT, %eax
248 movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
251 movl $FUTEX_WAIT, %eax
252 movl %fs:PRIVATE_FUTEX, %esi
255 orl $FUTEX_WAIT, %esi
258 movl $SYS_futex, %eax
262 callq __pthread_disable_asynccancel
270 cmpxchgl %esi, (%rdi)
272 cmpxchgl %esi, cond_lock(%rdi)
276 6: movl broadcast_seq(%rdi), %edx
278 movq woken_seq(%rdi), %rax
280 movq wakeup_seq(%rdi), %r9
294 16: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
296 /* Wake up a thread which wants to destroy the condvar object. */
297 cmpq $0xffffffffffffffff, total_seq(%rdi)
299 movl cond_nwaiters(%rdi), %eax
300 andl $~((1 << nwaiters_shift) - 1), %eax
303 addq $cond_nwaiters, %rdi
304 cmpq $-1, dep_mutex-cond_nwaiters(%rdi)
306 #ifdef __ASSUME_PRIVATE_FUTEX
307 movl $FUTEX_WAKE, %eax
308 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
312 movl %fs:PRIVATE_FUTEX, %esi
314 orl $FUTEX_WAKE, %esi
316 movl $SYS_futex, %eax
318 subq $cond_nwaiters, %rdi
328 /* Remove cancellation handler. */
329 11: movq 32+CLEANUP_PREV(%rsp), %rdx
330 movq %rdx, %fs:CLEANUP
333 callq __pthread_mutex_cond_lock
334 14: addq $FRAME_SIZE, %rsp
340 /* We return the result of the mutex_lock operation. */
343 /* Initial locking failed. */
347 addq $cond_lock, %rdi
349 cmpq $-1, dep_mutex-cond_lock(%rdi)
350 movl $LLL_PRIVATE, %eax
351 movl $LLL_SHARED, %esi
353 callq __lll_lock_wait
356 /* Unlock in loop requires wakeup. */
359 addq $cond_lock, %rdi
361 cmpq $-1, dep_mutex-cond_lock(%rdi)
362 movl $LLL_PRIVATE, %eax
363 movl $LLL_SHARED, %esi
365 callq __lll_unlock_wake
368 /* Locking in loop failed. */
371 addq $cond_lock, %rdi
373 cmpq $-1, dep_mutex-cond_lock(%rdi)
374 movl $LLL_PRIVATE, %eax
375 movl $LLL_SHARED, %esi
377 callq __lll_lock_wait
379 subq $cond_lock, %rdi
383 /* Unlock after loop requires wakeup. */
386 addq $cond_lock, %rdi
388 cmpq $-1, dep_mutex-cond_lock(%rdi)
389 movl $LLL_PRIVATE, %eax
390 movl $LLL_SHARED, %esi
392 callq __lll_unlock_wake
395 /* The initial unlocking of the mutex failed. */
407 addq $cond_lock, %rdi
409 cmpq $-1, dep_mutex-cond_lock(%rdi)
410 movl $LLL_PRIVATE, %eax
411 movl $LLL_SHARED, %esi
413 callq __lll_unlock_wake
418 .size __pthread_cond_wait, .-__pthread_cond_wait
419 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
423 .section .eh_frame,"a",@progbits
425 .long L(ENDCIE)-L(STARTCIE) # Length of the CIE.
428 .byte 1 # Version number.
430 .string "zR" # NUL-terminated augmentation
433 .ascii "\0" # NUL-terminated augmentation
436 .uleb128 1 # Code alignment factor.
437 .sleb128 -8 # Data alignment factor.
438 .byte 16 # Return address register
441 .uleb128 1 # Augmentation value length.
442 .byte 0x1b # Encoding: DW_EH_PE_pcrel
445 .byte 0x0c # DW_CFA_def_cfa
448 .byte 0x90 # DW_CFA_offset, column 0x8
453 .long .LENDFDE-.LSTARTFDE # Length of the FDE.
455 .long .LSTARTFDE-.LSTARTFRAME # CIE pointer.
457 .long .LSTARTCODE-. # PC-relative start address
460 .long .LSTARTCODE # Start address of the code.
462 .long .LENDCODE-.LSTARTCODE # Length of the code.
464 .uleb128 0 # No augmentation data.
466 .byte 0x40+.Lpush_r12-.LSTARTCODE # DW_CFA_advance_loc+N
467 .byte 14 # DW_CFA_def_cfa_offset
469 .byte 0x8c # DW_CFA_offset %r12
471 .byte 0x40+.Lsubq-.Lpush_r12 # DW_CFA_advance_loc+N
472 .byte 14 # DW_CFA_def_cfa_offset
473 .uleb128 16+FRAME_SIZE
474 .byte 3 # DW_CFA_advance_loc2
476 .byte 14 # DW_CFA_def_cfa_offset
478 .byte 0x40+.Lpop_r12-.Laddq # DW_CFA_advance_loc+N
479 .byte 14 # DW_CFA_def_cfa_offset
481 .byte 0xcc # DW_CFA_restore %r12
482 .byte 0x40+.LSbl1-.Lpop_r12 # DW_CFA_advance_loc+N
483 .byte 14 # DW_CFA_def_cfa_offset
485 .byte 0x8c # DW_CFA_offset %r12