1 /* Copyright (C) 2002, 2003, 2004, 2005, 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 <pthread-errnos.h>
26 #include <kernel-features.h>
28 /* For the calculation see asm/vsyscall.h. */
29 #define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
34 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
35 const struct timespec *abstime) */
36 .globl __pthread_cond_timedwait
37 .type __pthread_cond_timedwait, @function
39 __pthread_cond_timedwait:
48 subq $FRAME_SIZE, %rsp
51 cmpq $1000000000, 8(%rdx)
58 +--------------------------+
59 rsp + 48 | cleanup buffer |
60 +--------------------------+
61 rsp + 40 | old wake_seq value |
62 +--------------------------+
63 rsp + 24 | timeout value |
64 +--------------------------+
65 rsp + 16 | mutex pointer |
66 +--------------------------+
67 rsp + 8 | condvar pointer |
68 +--------------------------+
69 rsp + 4 | old broadcast_seq value |
70 +--------------------------+
71 rsp + 0 | old cancellation mode |
72 +--------------------------+
75 cmpq $-1, dep_mutex(%rdi)
77 /* Prepare structure passed to cancellation handler. */
83 movq %rsi, dep_mutex(%rdi)
85 /* Get internal lock. */
92 cmpxchgl %esi, cond_lock(%rdi)
96 /* Unlock the mutex. */
97 2: movq 16(%rsp), %rdi
99 callq __pthread_mutex_unlock_usercnt
106 incl cond_futex(%rdi)
107 addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
109 /* Install cancellation handler. */
111 leaq __condvar_cleanup(%rip), %rsi
113 leaq __condvar_cleanup, %rsi
117 callq __pthread_cleanup_push
119 /* Get and store current wakeup_seq value. */
121 movq wakeup_seq(%rdi), %r9
122 movl broadcast_seq(%rdi), %edx
126 /* Get the current time. */
128 #ifdef __NR_clock_gettime
129 /* Get the clock number. Note that the field in the condvar
130 structure stores the number minus 1. */
132 movl cond_nwaiters(%rdi), %edi
133 andl $((1 << nwaiters_shift) - 1), %edi
134 /* Only clocks 0 and 1 are allowed so far. Both are handled in the
138 movq __vdso_clock_gettime@GOTPCREL(%rip), %rax
145 26: movl $__NR_clock_gettime, %eax
148 # ifndef __ASSUME_POSIX_TIMERS
153 /* Compute relative timeout. */
161 movq $VSYSCALL_ADDR_vgettimeofday, %rax
164 /* Compute relative timeout. */
167 mul %rdx /* Milli seconds to nano seconds. */
174 addq $1000000000, %rdx
178 movq $-ETIMEDOUT, %r14
181 /* Store relative timeout. */
182 21: movq %rcx, 24(%rsp)
185 movl cond_futex(%rdi), %r12d
196 4: callq __pthread_enable_asynccancel
200 cmpq $-1, dep_mutex(%rdi)
202 #ifdef __ASSUME_PRIVATE_FUTEX
203 movl $FUTEX_WAIT, %eax
204 movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
208 movl %fs:PRIVATE_FUTEX, %esi
211 orl $FUTEX_WAIT, %esi
214 addq $cond_futex, %rdi
215 movl $SYS_futex, %eax
220 callq __pthread_disable_asynccancel
228 cmpxchgl %esi, (%rdi)
230 cmpxchgl %esi, cond_lock(%rdi)
234 6: movl broadcast_seq(%rdi), %edx
236 movq woken_seq(%rdi), %rax
238 movq wakeup_seq(%rdi), %r9
249 15: cmpq $-ETIMEDOUT, %r14
252 13: incq wakeup_seq(%rdi)
253 incl cond_futex(%rdi)
254 movl $ETIMEDOUT, %r14d
261 14: incq woken_seq(%rdi)
263 24: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
265 /* Wake up a thread which wants to destroy the condvar object. */
266 cmpq $0xffffffffffffffff, total_seq(%rdi)
268 movl cond_nwaiters(%rdi), %eax
269 andl $~((1 << nwaiters_shift) - 1), %eax
272 addq $cond_nwaiters, %rdi
273 cmpq $-1, dep_mutex-cond_nwaiters(%rdi)
275 #ifdef __ASSUME_PRIVATE_FUTEX
276 movl $FUTEX_WAKE, %eax
277 movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
281 movl %fs:PRIVATE_FUTEX, %esi
283 orl $FUTEX_WAKE, %esi
285 movl $SYS_futex, %eax
287 subq $cond_nwaiters, %rdi
297 /* Remove cancellation handler. */
298 11: movq 48+CLEANUP_PREV(%rsp), %rdx
299 movq %rdx, %fs:CLEANUP
302 callq __pthread_mutex_cond_lock
307 18: addq $FRAME_SIZE, %rsp
318 /* Initial locking failed. */
322 addq $cond_lock, %rdi
324 cmpq $-1, dep_mutex-cond_lock(%rdi)
325 movl $LLL_PRIVATE, %eax
326 movl $LLL_SHARED, %esi
328 callq __lll_lock_wait
331 /* Unlock in loop requires wakeup. */
334 addq $cond_lock, %rdi
336 cmpq $-1, dep_mutex-cond_lock(%rdi)
337 movl $LLL_PRIVATE, %eax
338 movl $LLL_SHARED, %esi
340 callq __lll_unlock_wake
343 /* Locking in loop failed. */
346 addq $cond_lock, %rdi
348 cmpq $-1, dep_mutex-cond_lock(%rdi)
349 movl $LLL_PRIVATE, %eax
350 movl $LLL_SHARED, %esi
352 callq __lll_lock_wait
354 subq $cond_lock, %rdi
358 /* Unlock after loop requires wakeup. */
361 addq $cond_lock, %rdi
363 cmpq $-1, dep_mutex-cond_lock(%rdi)
364 movl $LLL_PRIVATE, %eax
365 movl $LLL_SHARED, %esi
367 callq __lll_unlock_wake
370 /* The initial unlocking of the mutex failed. */
371 16: movq 8(%rsp), %rdi
382 addq $cond_lock, %rdi
384 cmpq $-1, dep_mutex-cond_lock(%rdi)
385 movl $LLL_PRIVATE, %eax
386 movl $LLL_SHARED, %esi
388 callq __lll_unlock_wake
390 17: movq (%rsp), %rax
393 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
394 /* clock_gettime not available. */
395 19: leaq 24(%rsp), %rdi
397 movq $VSYSCALL_ADDR_vgettimeofday, %rax
400 /* Compute relative timeout. */
403 mul %rdx /* Milli seconds to nano seconds. */
409 addq $1000000000, %rdx
413 movq $-ETIMEDOUT, %r14
418 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
419 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
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+.Lpush_r13-.Lpush_r12 # DW_CFA_advance_loc+N
472 .byte 14 # DW_CFA_def_cfa_offset
474 .byte 0x8d # DW_CFA_offset %r13
476 .byte 0x40+.Lpush_r14-.Lpush_r13 # DW_CFA_advance_loc+N
477 .byte 14 # DW_CFA_def_cfa_offset
479 .byte 0x84 # DW_CFA_offset %r14
481 .byte 0x40+.Lsubq-.Lpush_r14 # DW_CFA_advance_loc+N
482 .byte 14 # DW_CFA_def_cfa_offset
483 .uleb128 32+FRAME_SIZE
484 .byte 3 # DW_CFA_advance_loc2
486 .byte 14 # DW_CFA_def_cfa_offset
488 .byte 0x40+.Lpop_r14-.Laddq # DW_CFA_advance_loc+N
489 .byte 14 # DW_CFA_def_cfa_offset
491 .byte 0xce # DW_CFA_restore %r14
492 .byte 0x40+.Lpop_r13-.Lpop_r14 # DW_CFA_advance_loc+N
493 .byte 14 # DW_CFA_def_cfa_offset
495 .byte 0xcd # DW_CFA_restore %r13
496 .byte 0x40+.Lpop_r12-.Lpop_r13 # DW_CFA_advance_loc+N
497 .byte 14 # DW_CFA_def_cfa_offset
499 .byte 0xcc # DW_CFA_restore %r12
500 .byte 0x40+.LSbl1-.Lpop_r12 # DW_CFA_advance_loc+N
501 .byte 14 # DW_CFA_def_cfa_offset
502 .uleb128 32+FRAME_SIZE
503 .byte 0x8c # DW_CFA_offset %r12
505 .byte 0x8d # DW_CFA_offset %r13
507 .byte 0x84 # DW_CFA_offset %r14