1 /* Copyright (C) 2002, 2003, 2004 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 <lowlevelcond.h>
23 #include <pthread-errnos.h>
35 /* For the calculation see asm/vsyscall.h. */
36 #define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
41 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
42 const struct timespec *abstime) */
43 .globl __pthread_cond_timedwait
44 .type __pthread_cond_timedwait, @function
46 __pthread_cond_timedwait:
55 subq $FRAME_SIZE, %rsp
58 cmpq $1000000000, 8(%rdx)
65 +--------------------------+
66 rsp + 48 | cleanup buffer |
67 +--------------------------+
68 rsp + 40 | old wake_seq value |
69 +--------------------------+
70 rsp + 24 | timeout value |
71 +--------------------------+
72 rsp + 16 | mutex pointer |
73 +--------------------------+
74 rsp + 8 | condvar pointer |
75 +--------------------------+
76 rsp + 4 | old broadcast_seq value |
77 +--------------------------+
78 rsp + 0 | old cancellation mode |
79 +--------------------------+
82 cmpq $-1, dep_mutex(%rdi)
84 /* Prepare structure passed to cancellation handler. */
90 movq %rsi, dep_mutex(%rdi)
92 /* Get internal lock. */
99 cmpxchgl %esi, cond_lock(%rdi)
103 /* Unlock the mutex. */
104 2: movq 16(%rsp), %rdi
106 callq __pthread_mutex_unlock_usercnt
113 incl cond_futex(%rdi)
114 addl $(1 << clock_bits), cond_nwaiters(%rdi)
116 /* Install cancellation handler. */
118 leaq __condvar_cleanup(%rip), %rsi
120 leaq __condvar_cleanup, %rsi
124 callq __pthread_cleanup_push
126 /* Get and store current wakeup_seq value. */
128 movq wakeup_seq(%rdi), %r9
129 movl broadcast_seq(%rdi), %edx
133 /* Get the current time. */
135 #ifdef __NR_clock_gettime
136 /* Get the clock number. Note that the field in the condvar
137 structure stores the number minus 1. */
139 movl cond_nwaiters(%rdi), %edi
140 andl $((1 << clock_bits) - 1), %edi
141 /* Only clocks 0 and 1 are allowed so far. Both are handled in the
144 movq $__NR_clock_gettime, %rax
146 # ifndef __ASSUME_POSIX_TIMERS
151 /* Compute relative timeout. */
159 movq $VSYSCALL_ADDR_vgettimeofday, %rax
162 /* Compute relative timeout. */
165 mul %rdx /* Milli seconds to nano seconds. */
172 addq $1000000000, %rdx
176 movq $-ETIMEDOUT, %r14
179 /* Store relative timeout. */
180 21: movq %rcx, 24(%rsp)
183 movl cond_futex(%rdi), %r12d
194 4: callq __pthread_enable_asynccancel
198 xorq %rsi, %rsi /* movq $FUTEX_WAIT, %rsi */
200 addq $cond_futex, %rdi
201 movq $SYS_futex, %rax
206 callq __pthread_disable_asynccancel
214 cmpxchgl %esi, (%rdi)
216 cmpxchgl %esi, cond_lock(%rdi)
220 6: movl broadcast_seq(%rdi), %edx
222 movq woken_seq(%rdi), %rax
224 movq wakeup_seq(%rdi), %r9
235 15: cmpq $-ETIMEDOUT, %r14
238 13: incq wakeup_seq(%rdi)
239 incl cond_futex(%rdi)
240 movq $ETIMEDOUT, %r14
247 14: incq woken_seq(%rdi)
249 24: subl $(1 << clock_bits), cond_nwaiters(%rdi)
251 /* Wake up a thread which wants to destroy the condvar object. */
252 cmpq $0xffffffffffffffff, total_seq(%rdi)
254 movl cond_nwaiters(%rdi), %eax
255 andl $~((1 << clock_bits) - 1), %eax
258 addq $cond_nwaiters, %rdi
259 movq $SYS_futex, %rax
260 movq $FUTEX_WAKE, %rsi
263 subq $cond_nwaiters, %rdi
273 /* Remove cancellation handler. */
274 11: movq 48+CLEANUP_PREV(%rsp), %rdx
275 movq %rdx, %fs:CLEANUP
278 callq __pthread_mutex_cond_lock
283 18: addq $FRAME_SIZE, %rsp
294 /* Initial locking failed. */
298 addq $cond_lock, %rdi
300 callq __lll_mutex_lock_wait
303 /* Unlock in loop requires wakeup. */
306 addq $cond_lock, %rdi
308 callq __lll_mutex_unlock_wake
311 /* Locking in loop failed. */
314 addq $cond_lock, %rdi
316 callq __lll_mutex_lock_wait
318 subq $cond_lock, %rdi
322 /* Unlock after loop requires wakeup. */
325 addq $cond_lock, %rdi
327 callq __lll_mutex_unlock_wake
330 /* The initial unlocking of the mutex failed. */
331 16: movq 8(%rsp), %rdi
342 addq $cond_lock, %rdi
344 callq __lll_mutex_unlock_wake
346 17: movq (%rsp), %rax
349 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
350 /* clock_gettime not available. */
351 19: leaq 24(%rsp), %rdi
353 movq $VSYSCALL_ADDR_vgettimeofday, %rax
356 /* Compute relative timeout. */
359 mul %rdx /* Milli seconds to nano seconds. */
365 addq $1000000000, %rdx
369 movq $-ETIMEDOUT, %r14
374 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
375 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
379 .section .eh_frame,"a",@progbits
381 .long L(ENDCIE)-L(STARTCIE) # Length of the CIE.
384 .byte 1 # Version number.
386 .string "zR" # NUL-terminated augmentation
389 .ascii "\0" # NUL-terminated augmentation
392 .uleb128 1 # Code alignment factor.
393 .sleb128 -8 # Data alignment factor.
394 .byte 16 # Return address register
397 .uleb128 1 # Augmentation value length.
398 .byte 0x1b # Encoding: DW_EH_PE_pcrel
401 .byte 0x0c # DW_CFA_def_cfa
404 .byte 0x90 # DW_CFA_offset, column 0x8
409 .long .LENDFDE-.LSTARTFDE # Length of the FDE.
411 .long .LSTARTFDE-.LSTARTFRAME # CIE pointer.
413 .long .LSTARTCODE-. # PC-relative start address
416 .long .LSTARTCODE # Start address of the code.
418 .long .LENDCODE-.LSTARTCODE # Length of the code.
420 .uleb128 0 # No augmentation data.
422 .byte 0x40+.Lpush_r12-.LSTARTCODE # DW_CFA_advance_loc+N
423 .byte 14 # DW_CFA_def_cfa_offset
425 .byte 0x8c # DW_CFA_offset %r12
427 .byte 0x40+.Lpush_r13-.Lpush_r12 # DW_CFA_advance_loc+N
428 .byte 14 # DW_CFA_def_cfa_offset
430 .byte 0x8d # DW_CFA_offset %r13
432 .byte 0x40+.Lpush_r14-.Lpush_r13 # DW_CFA_advance_loc+N
433 .byte 14 # DW_CFA_def_cfa_offset
435 .byte 0x84 # DW_CFA_offset %r14
437 .byte 0x40+.Lsubq-.Lpush_r14 # DW_CFA_advance_loc+N
438 .byte 14 # DW_CFA_def_cfa_offset
439 .uleb128 32+FRAME_SIZE
440 .byte 3 # DW_CFA_advance_loc2
442 .byte 14 # DW_CFA_def_cfa_offset
444 .byte 0x40+.Lpop_r14-.Laddq # DW_CFA_advance_loc+N
445 .byte 14 # DW_CFA_def_cfa_offset
447 .byte 0xce # DW_CFA_restore %r14
448 .byte 0x40+.Lpop_r13-.Lpop_r14 # DW_CFA_advance_loc+N
449 .byte 14 # DW_CFA_def_cfa_offset
451 .byte 0xcd # DW_CFA_restore %r13
452 .byte 0x40+.Lpop_r12-.Lpop_r13 # DW_CFA_advance_loc+N
453 .byte 14 # DW_CFA_def_cfa_offset
455 .byte 0xcc # DW_CFA_restore %r12
456 .byte 0x40+.LSbl1-.Lpop_r12 # DW_CFA_advance_loc+N
457 .byte 14 # DW_CFA_def_cfa_offset
458 .uleb128 32+FRAME_SIZE
459 .byte 0x8c # DW_CFA_offset %r12
461 .byte 0x8d # DW_CFA_offset %r13
463 .byte 0x84 # DW_CFA_offset %r14