2.9
[glibc/nacl-glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_cond_timedwait.S
blob20bc59db9c80989cfbf6a0d710f90d2834edbe82
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
18    02111-1307 USA.  */
20 #include <sysdep.h>
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
32         .text
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
38         .align  16
39 __pthread_cond_timedwait:
40 .LSTARTCODE:
41         pushq   %r12
42 .Lpush_r12:
43         pushq   %r13
44 .Lpush_r13:
45         pushq   %r14
46 .Lpush_r14:
47 #define FRAME_SIZE 80
48         subq    $FRAME_SIZE, %rsp
49 .Lsubq:
51         cmpq    $1000000000, 8(%rdx)
52         movl    $EINVAL, %eax
53         jae     18f
55         /* Stack frame:
57            rsp + 80
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                     +--------------------------+
73         */
75         cmpq    $-1, dep_mutex(%rdi)
77         /* Prepare structure passed to cancellation handler.  */
78         movq    %rdi, 8(%rsp)
79         movq    %rsi, 16(%rsp)
80         movq    %rdx, %r13
82         je      22f
83         movq    %rsi, dep_mutex(%rdi)
85         /* Get internal lock.  */
86 22:     movl    $1, %esi
87         xorl    %eax, %eax
88         LOCK
89 #if cond_lock == 0
90         cmpxchgl %esi, (%rdi)
91 #else
92         cmpxchgl %esi, cond_lock(%rdi)
93 #endif
94         jnz     1f
96         /* Unlock the mutex.  */
97 2:      movq    16(%rsp), %rdi
98         xorl    %esi, %esi
99         callq   __pthread_mutex_unlock_usercnt
101         testl   %eax, %eax
102         jne     16f
104         movq    8(%rsp), %rdi
105         incq    total_seq(%rdi)
106         incl    cond_futex(%rdi)
107         addl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
109         /* Install cancellation handler.  */
110 #ifdef PIC
111         leaq    __condvar_cleanup(%rip), %rsi
112 #else
113         leaq    __condvar_cleanup, %rsi
114 #endif
115         leaq    48(%rsp), %rdi
116         movq    %rsp, %rdx
117         callq   __pthread_cleanup_push
119         /* Get and store current wakeup_seq value.  */
120         movq    8(%rsp), %rdi
121         movq    wakeup_seq(%rdi), %r9
122         movl    broadcast_seq(%rdi), %edx
123         movq    %r9, 40(%rsp)
124         movl    %edx, 4(%rsp)
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.  */
131         movq    8(%rsp), %rdi
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
135            kernel.  */
136         leaq    24(%rsp), %rsi
137 # ifdef SHARED
138         movq    __vdso_clock_gettime@GOTPCREL(%rip), %rax
139         movq    (%rax), %rax
140         PTR_DEMANGLE (%rax)
141         jz      26f
142         call    *%rax
143         jmp     27f
144 # endif
145 26:     movl    $__NR_clock_gettime, %eax
146         syscall
148 # ifndef __ASSUME_POSIX_TIMERS
149         cmpq    $-ENOSYS, %rax
150         je      19f
151 # endif
153         /* Compute relative timeout.  */
154         movq    (%r13), %rcx
155         movq    8(%r13), %rdx
156         subq    24(%rsp), %rcx
157         subq    32(%rsp), %rdx
158 #else
159         leaq    24(%rsp), %rdi
160         xorl    %esi, %esi
161         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
162         callq   *%rax
164         /* Compute relative timeout.  */
165         movq    32(%rsp), %rax
166         movl    $1000, %edx
167         mul     %rdx            /* Milli seconds to nano seconds.  */
168         movq    (%r13), %rcx
169         movq    8(%r13), %rdx
170         subq    24(%rsp), %rcx
171         subq    %rax, %rdx
172 #endif
173         jns     12f
174         addq    $1000000000, %rdx
175         decq    %rcx
176 12:     testq   %rcx, %rcx
177         movq    8(%rsp), %rdi
178         movq    $-ETIMEDOUT, %r14
179         js      6f
181         /* Store relative timeout.  */
182 21:     movq    %rcx, 24(%rsp)
183         movq    %rdx, 32(%rsp)
185         movl    cond_futex(%rdi), %r12d
187         /* Unlock.  */
188         LOCK
189 #if cond_lock == 0
190         decl    (%rdi)
191 #else
192         decl    cond_lock(%rdi)
193 #endif
194         jne     3f
196 4:      callq   __pthread_enable_asynccancel
197         movl    %eax, (%rsp)
199         leaq    24(%rsp), %r10
200         cmpq    $-1, dep_mutex(%rdi)
201         movq    %r12, %rdx
202 #ifdef __ASSUME_PRIVATE_FUTEX
203         movl    $FUTEX_WAIT, %eax
204         movl    $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
205         cmove   %eax, %esi
206 #else
207         movl    $0, %eax
208         movl    %fs:PRIVATE_FUTEX, %esi
209         cmove   %eax, %esi
210 # if FUTEX_WAIT != 0
211         orl     $FUTEX_WAIT, %esi
212 # endif
213 #endif
214         addq    $cond_futex, %rdi
215         movl    $SYS_futex, %eax
216         syscall
217         movq    %rax, %r14
219         movl    (%rsp), %edi
220         callq   __pthread_disable_asynccancel
222         /* Lock.  */
223         movq    8(%rsp), %rdi
224         movl    $1, %esi
225         xorl    %eax, %eax
226         LOCK
227 #if cond_lock == 0
228         cmpxchgl %esi, (%rdi)
229 #else
230         cmpxchgl %esi, cond_lock(%rdi)
231 #endif
232         jne     5f
234 6:      movl    broadcast_seq(%rdi), %edx
236         movq    woken_seq(%rdi), %rax
238         movq    wakeup_seq(%rdi), %r9
240         cmpl    4(%rsp), %edx
241         jne     23f
243         cmpq    40(%rsp), %r9
244         jbe     15f
246         cmpq    %rax, %r9
247         ja      9f
249 15:     cmpq    $-ETIMEDOUT, %r14
250         jne     8b
252 13:     incq    wakeup_seq(%rdi)
253         incl    cond_futex(%rdi)
254         movl    $ETIMEDOUT, %r14d
255         jmp     14f
257 23:     xorq    %r14, %r14
258         jmp     24f
260 9:      xorq    %r14, %r14
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)
267         jne     25f
268         movl    cond_nwaiters(%rdi), %eax
269         andl    $~((1 << nwaiters_shift) - 1), %eax
270         jne     25f
272         addq    $cond_nwaiters, %rdi
273         cmpq    $-1, dep_mutex-cond_nwaiters(%rdi)
274         movl    $1, %edx
275 #ifdef __ASSUME_PRIVATE_FUTEX
276         movl    $FUTEX_WAKE, %eax
277         movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
278         cmove   %eax, %esi
279 #else
280         movl    $0, %eax
281         movl    %fs:PRIVATE_FUTEX, %esi
282         cmove   %eax, %esi
283         orl     $FUTEX_WAKE, %esi
284 #endif
285         movl    $SYS_futex, %eax
286         syscall
287         subq    $cond_nwaiters, %rdi
289 25:     LOCK
290 #if cond_lock == 0
291         decl    (%rdi)
292 #else
293         decl    cond_lock(%rdi)
294 #endif
295         jne     10f
297         /* Remove cancellation handler.  */
298 11:     movq    48+CLEANUP_PREV(%rsp), %rdx
299         movq    %rdx, %fs:CLEANUP
301         movq    16(%rsp), %rdi
302         callq   __pthread_mutex_cond_lock
304         testq   %rax, %rax
305         cmoveq  %r14, %rax
307 18:     addq    $FRAME_SIZE, %rsp
308 .Laddq:
309         popq    %r14
310 .Lpop_r14:
311         popq    %r13
312 .Lpop_r13:
313         popq    %r12
314 .Lpop_r12:
316         retq
318         /* Initial locking failed.  */
320 .LSbl1:
321 #if cond_lock != 0
322         addq    $cond_lock, %rdi
323 #endif
324         cmpq    $-1, dep_mutex-cond_lock(%rdi)
325         movl    $LLL_PRIVATE, %eax
326         movl    $LLL_SHARED, %esi
327         cmovne  %eax, %esi
328         callq   __lll_lock_wait
329         jmp     2b
331         /* Unlock in loop requires wakeup.  */
333 #if cond_lock != 0
334         addq    $cond_lock, %rdi
335 #endif
336         cmpq    $-1, dep_mutex-cond_lock(%rdi)
337         movl    $LLL_PRIVATE, %eax
338         movl    $LLL_SHARED, %esi
339         cmovne  %eax, %esi
340         callq   __lll_unlock_wake
341         jmp     4b
343         /* Locking in loop failed.  */
345 #if cond_lock != 0
346         addq    $cond_lock, %rdi
347 #endif
348         cmpq    $-1, dep_mutex-cond_lock(%rdi)
349         movl    $LLL_PRIVATE, %eax
350         movl    $LLL_SHARED, %esi
351         cmovne  %eax, %esi
352         callq   __lll_lock_wait
353 #if cond_lock != 0
354         subq    $cond_lock, %rdi
355 #endif
356         jmp     6b
358         /* Unlock after loop requires wakeup.  */
360 #if cond_lock != 0
361         addq    $cond_lock, %rdi
362 #endif
363         cmpq    $-1, dep_mutex-cond_lock(%rdi)
364         movl    $LLL_PRIVATE, %eax
365         movl    $LLL_SHARED, %esi
366         cmovne  %eax, %esi
367         callq   __lll_unlock_wake
368         jmp     11b
370         /* The initial unlocking of the mutex failed.  */
371 16:     movq    8(%rsp), %rdi
372         movq    %rax, (%rsp)
373         LOCK
374 #if cond_lock == 0
375         decl    (%rdi)
376 #else
377         decl    cond_lock(%rdi)
378 #endif
379         jne     17f
381 #if cond_lock != 0
382         addq    $cond_lock, %rdi
383 #endif
384         cmpq    $-1, dep_mutex-cond_lock(%rdi)
385         movl    $LLL_PRIVATE, %eax
386         movl    $LLL_SHARED, %esi
387         cmovne  %eax, %esi
388         callq   __lll_unlock_wake
390 17:     movq    (%rsp), %rax
391         jmp     18b
393 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
394         /* clock_gettime not available.  */
395 19:     leaq    24(%rsp), %rdi
396         xorl    %esi, %esi
397         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
398         callq   *%rax
400         /* Compute relative timeout.  */
401         movq    32(%rsp), %rax
402         movl    $1000, %edx
403         mul     %rdx            /* Milli seconds to nano seconds.  */
404         movq    (%r13), %rcx
405         movq    8(%r13), %rdx
406         subq    24(%rsp), %rcx
407         subq    %rax, %rdx
408         jns     20f
409         addq    $1000000000, %rdx
410         decq    %rcx
411 20:     testq   %rcx, %rcx
412         movq    8(%rsp), %rdi
413         movq    $-ETIMEDOUT, %r14
414         js      6b
415         jmp     21b
416 #endif
417 .LENDCODE:
418         .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
419 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
420                   GLIBC_2_3_2)
423         .section .eh_frame,"a",@progbits
424 .LSTARTFRAME:
425         .long   L(ENDCIE)-L(STARTCIE)           # Length of the CIE.
426 .LSTARTCIE:
427         .long   0                               # CIE ID.
428         .byte   1                               # Version number.
429 #ifdef SHARED
430         .string "zR"                            # NUL-terminated augmentation
431                                                 # string.
432 #else
433         .ascii  "\0"                            # NUL-terminated augmentation
434                                                 # string.
435 #endif
436         .uleb128 1                              # Code alignment factor.
437         .sleb128 -8                             # Data alignment factor.
438         .byte   16                              # Return address register
439                                                 # column.
440 #ifdef SHARED
441         .uleb128 1                              # Augmentation value length.
442         .byte   0x1b                            # Encoding: DW_EH_PE_pcrel
443                                                 # + DW_EH_PE_sdata4.
444 #endif
445         .byte 0x0c                              # DW_CFA_def_cfa
446         .uleb128 7
447         .uleb128 8
448         .byte   0x90                            # DW_CFA_offset, column 0x8
449         .uleb128 1
450         .align 8
451 .LENDCIE:
453         .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
454 .LSTARTFDE:
455         .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
456 #ifdef SHARED
457         .long   .LSTARTCODE-.                   # PC-relative start address
458                                                 # of the code
459 #else
460         .long   .LSTARTCODE                     # Start address of the code.
461 #endif
462         .long   .LENDCODE-.LSTARTCODE           # Length of the code.
463 #ifdef SHARED
464         .uleb128 0                              # No augmentation data.
465 #endif
466         .byte   0x40+.Lpush_r12-.LSTARTCODE     # DW_CFA_advance_loc+N
467         .byte   14                              # DW_CFA_def_cfa_offset
468         .uleb128 16
469         .byte   0x8c                            # DW_CFA_offset %r12
470         .uleb128 2
471         .byte   0x40+.Lpush_r13-.Lpush_r12      # DW_CFA_advance_loc+N
472         .byte   14                              # DW_CFA_def_cfa_offset
473         .uleb128 24
474         .byte   0x8d                            # DW_CFA_offset %r13
475         .uleb128 3
476         .byte   0x40+.Lpush_r14-.Lpush_r13      # DW_CFA_advance_loc+N
477         .byte   14                              # DW_CFA_def_cfa_offset
478         .uleb128 32
479         .byte   0x84                            # DW_CFA_offset %r14
480         .uleb128 4
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
485         .2byte  .Laddq-.Lsubq
486         .byte   14                              # DW_CFA_def_cfa_offset
487         .uleb128 32
488         .byte   0x40+.Lpop_r14-.Laddq           # DW_CFA_advance_loc+N
489         .byte   14                              # DW_CFA_def_cfa_offset
490         .uleb128 24
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
494         .uleb128 16
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
498         .uleb128 8
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
504         .uleb128 2
505         .byte   0x8d                            # DW_CFA_offset %r13
506         .uleb128 3
507         .byte   0x84                            # DW_CFA_offset %r14
508         .uleb128 4
509         .align  8
510 .LENDFDE: