* csu/libc-start.c: Don't handle VDSO_SETUP here.
[glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_cond_timedwait.S
blobd730a7e12d55c25a1fefe48312d26f11c1695536
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         movq    __vdso_clock_gettime@GOTPCREL(%rip), %rax
138         movq    (%rax), %rax
139         PTR_DEMANGLE (%rax)
140         jz      26f
141         call    *%rax
142         jmp     27f
143 26:     movl    $__NR_clock_gettime, %eax
144         syscall
146 # ifndef __ASSUME_POSIX_TIMERS
147         cmpq    $-ENOSYS, %rax
148         je      19f
149 # endif
151         /* Compute relative timeout.  */
152         movq    (%r13), %rcx
153         movq    8(%r13), %rdx
154         subq    24(%rsp), %rcx
155         subq    32(%rsp), %rdx
156 #else
157         leaq    24(%rsp), %rdi
158         xorl    %esi, %esi
159         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
160         callq   *%rax
162         /* Compute relative timeout.  */
163         movq    32(%rsp), %rax
164         movl    $1000, %edx
165         mul     %rdx            /* Milli seconds to nano seconds.  */
166         movq    (%r13), %rcx
167         movq    8(%r13), %rdx
168         subq    24(%rsp), %rcx
169         subq    %rax, %rdx
170 #endif
171         jns     12f
172         addq    $1000000000, %rdx
173         decq    %rcx
174 12:     testq   %rcx, %rcx
175         movq    8(%rsp), %rdi
176         movq    $-ETIMEDOUT, %r14
177         js      6f
179         /* Store relative timeout.  */
180 21:     movq    %rcx, 24(%rsp)
181         movq    %rdx, 32(%rsp)
183         movl    cond_futex(%rdi), %r12d
185         /* Unlock.  */
186         LOCK
187 #if cond_lock == 0
188         decl    (%rdi)
189 #else
190         decl    cond_lock(%rdi)
191 #endif
192         jne     3f
194 4:      callq   __pthread_enable_asynccancel
195         movl    %eax, (%rsp)
197         leaq    24(%rsp), %r10
198         cmpq    $-1, dep_mutex(%rdi)
199         movq    %r12, %rdx
200 #ifdef __ASSUME_PRIVATE_FUTEX
201         movl    $FUTEX_WAIT, %eax
202         movl    $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
203         cmove   %eax, %esi
204 #else
205         movl    $0, %eax
206         movl    %fs:PRIVATE_FUTEX, %esi
207         cmove   %eax, %esi
208 # if FUTEX_WAIT != 0
209         orl     $FUTEX_WAIT, %esi
210 # endif
211 #endif
212         addq    $cond_futex, %rdi
213         movl    $SYS_futex, %eax
214         syscall
215         movq    %rax, %r14
217         movl    (%rsp), %edi
218         callq   __pthread_disable_asynccancel
220         /* Lock.  */
221         movq    8(%rsp), %rdi
222         movl    $1, %esi
223         xorl    %eax, %eax
224         LOCK
225 #if cond_lock == 0
226         cmpxchgl %esi, (%rdi)
227 #else
228         cmpxchgl %esi, cond_lock(%rdi)
229 #endif
230         jne     5f
232 6:      movl    broadcast_seq(%rdi), %edx
234         movq    woken_seq(%rdi), %rax
236         movq    wakeup_seq(%rdi), %r9
238         cmpl    4(%rsp), %edx
239         jne     23f
241         cmpq    40(%rsp), %r9
242         jbe     15f
244         cmpq    %rax, %r9
245         ja      9f
247 15:     cmpq    $-ETIMEDOUT, %r14
248         jne     8b
250 13:     incq    wakeup_seq(%rdi)
251         incl    cond_futex(%rdi)
252         movl    $ETIMEDOUT, %r14d
253         jmp     14f
255 23:     xorq    %r14, %r14
256         jmp     24f
258 9:      xorq    %r14, %r14
259 14:     incq    woken_seq(%rdi)
261 24:     subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
263         /* Wake up a thread which wants to destroy the condvar object.  */
264         cmpq    $0xffffffffffffffff, total_seq(%rdi)
265         jne     25f
266         movl    cond_nwaiters(%rdi), %eax
267         andl    $~((1 << nwaiters_shift) - 1), %eax
268         jne     25f
270         addq    $cond_nwaiters, %rdi
271         cmpq    $-1, dep_mutex-cond_nwaiters(%rdi)
272         movl    $1, %edx
273 #ifdef __ASSUME_PRIVATE_FUTEX
274         movl    $FUTEX_WAKE, %eax
275         movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
276         cmove   %eax, %esi
277 #else
278         movl    $0, %eax
279         movl    %fs:PRIVATE_FUTEX, %esi
280         cmove   %eax, %esi
281         orl     $FUTEX_WAKE, %esi
282 #endif
283         movl    $SYS_futex, %eax
284         syscall
285         subq    $cond_nwaiters, %rdi
287 25:     LOCK
288 #if cond_lock == 0
289         decl    (%rdi)
290 #else
291         decl    cond_lock(%rdi)
292 #endif
293         jne     10f
295         /* Remove cancellation handler.  */
296 11:     movq    48+CLEANUP_PREV(%rsp), %rdx
297         movq    %rdx, %fs:CLEANUP
299         movq    16(%rsp), %rdi
300         callq   __pthread_mutex_cond_lock
302         testq   %rax, %rax
303         cmoveq  %r14, %rax
305 18:     addq    $FRAME_SIZE, %rsp
306 .Laddq:
307         popq    %r14
308 .Lpop_r14:
309         popq    %r13
310 .Lpop_r13:
311         popq    %r12
312 .Lpop_r12:
314         retq
316         /* Initial locking failed.  */
318 .LSbl1:
319 #if cond_lock != 0
320         addq    $cond_lock, %rdi
321 #endif
322         cmpq    $-1, dep_mutex-cond_lock(%rdi)
323         movl    $LLL_PRIVATE, %eax
324         movl    $LLL_SHARED, %esi
325         cmovne  %eax, %esi
326         callq   __lll_lock_wait
327         jmp     2b
329         /* Unlock in loop requires wakeup.  */
331 #if cond_lock != 0
332         addq    $cond_lock, %rdi
333 #endif
334         cmpq    $-1, dep_mutex-cond_lock(%rdi)
335         movl    $LLL_PRIVATE, %eax
336         movl    $LLL_SHARED, %esi
337         cmovne  %eax, %esi
338         callq   __lll_unlock_wake
339         jmp     4b
341         /* Locking in loop failed.  */
343 #if cond_lock != 0
344         addq    $cond_lock, %rdi
345 #endif
346         cmpq    $-1, dep_mutex-cond_lock(%rdi)
347         movl    $LLL_PRIVATE, %eax
348         movl    $LLL_SHARED, %esi
349         cmovne  %eax, %esi
350         callq   __lll_lock_wait
351 #if cond_lock != 0
352         subq    $cond_lock, %rdi
353 #endif
354         jmp     6b
356         /* Unlock after loop requires wakeup.  */
358 #if cond_lock != 0
359         addq    $cond_lock, %rdi
360 #endif
361         cmpq    $-1, dep_mutex-cond_lock(%rdi)
362         movl    $LLL_PRIVATE, %eax
363         movl    $LLL_SHARED, %esi
364         cmovne  %eax, %esi
365         callq   __lll_unlock_wake
366         jmp     11b
368         /* The initial unlocking of the mutex failed.  */
369 16:     movq    8(%rsp), %rdi
370         movq    %rax, (%rsp)
371         LOCK
372 #if cond_lock == 0
373         decl    (%rdi)
374 #else
375         decl    cond_lock(%rdi)
376 #endif
377         jne     17f
379 #if cond_lock != 0
380         addq    $cond_lock, %rdi
381 #endif
382         cmpq    $-1, dep_mutex-cond_lock(%rdi)
383         movl    $LLL_PRIVATE, %eax
384         movl    $LLL_SHARED, %esi
385         cmovne  %eax, %esi
386         callq   __lll_unlock_wake
388 17:     movq    (%rsp), %rax
389         jmp     18b
391 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
392         /* clock_gettime not available.  */
393 19:     leaq    24(%rsp), %rdi
394         xorl    %esi, %esi
395         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
396         callq   *%rax
398         /* Compute relative timeout.  */
399         movq    32(%rsp), %rax
400         movl    $1000, %edx
401         mul     %rdx            /* Milli seconds to nano seconds.  */
402         movq    (%r13), %rcx
403         movq    8(%r13), %rdx
404         subq    24(%rsp), %rcx
405         subq    %rax, %rdx
406         jns     20f
407         addq    $1000000000, %rdx
408         decq    %rcx
409 20:     testq   %rcx, %rcx
410         movq    8(%rsp), %rdi
411         movq    $-ETIMEDOUT, %r14
412         js      6b
413         jmp     21b
414 #endif
415 .LENDCODE:
416         .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
417 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
418                   GLIBC_2_3_2)
421         .section .eh_frame,"a",@progbits
422 .LSTARTFRAME:
423         .long   L(ENDCIE)-L(STARTCIE)           # Length of the CIE.
424 .LSTARTCIE:
425         .long   0                               # CIE ID.
426         .byte   1                               # Version number.
427 #ifdef SHARED
428         .string "zR"                            # NUL-terminated augmentation
429                                                 # string.
430 #else
431         .ascii  "\0"                            # NUL-terminated augmentation
432                                                 # string.
433 #endif
434         .uleb128 1                              # Code alignment factor.
435         .sleb128 -8                             # Data alignment factor.
436         .byte   16                              # Return address register
437                                                 # column.
438 #ifdef SHARED
439         .uleb128 1                              # Augmentation value length.
440         .byte   0x1b                            # Encoding: DW_EH_PE_pcrel
441                                                 # + DW_EH_PE_sdata4.
442 #endif
443         .byte 0x0c                              # DW_CFA_def_cfa
444         .uleb128 7
445         .uleb128 8
446         .byte   0x90                            # DW_CFA_offset, column 0x8
447         .uleb128 1
448         .align 8
449 .LENDCIE:
451         .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
452 .LSTARTFDE:
453         .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
454 #ifdef SHARED
455         .long   .LSTARTCODE-.                   # PC-relative start address
456                                                 # of the code
457 #else
458         .long   .LSTARTCODE                     # Start address of the code.
459 #endif
460         .long   .LENDCODE-.LSTARTCODE           # Length of the code.
461 #ifdef SHARED
462         .uleb128 0                              # No augmentation data.
463 #endif
464         .byte   0x40+.Lpush_r12-.LSTARTCODE     # DW_CFA_advance_loc+N
465         .byte   14                              # DW_CFA_def_cfa_offset
466         .uleb128 16
467         .byte   0x8c                            # DW_CFA_offset %r12
468         .uleb128 2
469         .byte   0x40+.Lpush_r13-.Lpush_r12      # DW_CFA_advance_loc+N
470         .byte   14                              # DW_CFA_def_cfa_offset
471         .uleb128 24
472         .byte   0x8d                            # DW_CFA_offset %r13
473         .uleb128 3
474         .byte   0x40+.Lpush_r14-.Lpush_r13      # DW_CFA_advance_loc+N
475         .byte   14                              # DW_CFA_def_cfa_offset
476         .uleb128 32
477         .byte   0x84                            # DW_CFA_offset %r14
478         .uleb128 4
479         .byte   0x40+.Lsubq-.Lpush_r14          # DW_CFA_advance_loc+N
480         .byte   14                              # DW_CFA_def_cfa_offset
481         .uleb128 32+FRAME_SIZE
482         .byte   3                               # DW_CFA_advance_loc2
483         .2byte  .Laddq-.Lsubq
484         .byte   14                              # DW_CFA_def_cfa_offset
485         .uleb128 32
486         .byte   0x40+.Lpop_r14-.Laddq           # DW_CFA_advance_loc+N
487         .byte   14                              # DW_CFA_def_cfa_offset
488         .uleb128 24
489         .byte   0xce                            # DW_CFA_restore %r14
490         .byte   0x40+.Lpop_r13-.Lpop_r14        # DW_CFA_advance_loc+N
491         .byte   14                              # DW_CFA_def_cfa_offset
492         .uleb128 16
493         .byte   0xcd                            # DW_CFA_restore %r13
494         .byte   0x40+.Lpop_r12-.Lpop_r13        # DW_CFA_advance_loc+N
495         .byte   14                              # DW_CFA_def_cfa_offset
496         .uleb128 8
497         .byte   0xcc                            # DW_CFA_restore %r12
498         .byte   0x40+.LSbl1-.Lpop_r12           # DW_CFA_advance_loc+N
499         .byte   14                              # DW_CFA_def_cfa_offset
500         .uleb128 32+FRAME_SIZE
501         .byte   0x8c                            # DW_CFA_offset %r12
502         .uleb128 2
503         .byte   0x8d                            # DW_CFA_offset %r13
504         .uleb128 3
505         .byte   0x84                            # DW_CFA_offset %r14
506         .uleb128 4
507         .align  8
508 .LENDFDE: