* sysdeps/unix/sysv/linux/internaltypes.h: Introduce
[glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_cond_timedwait.S
blob2afd601b8c0ad7e077e2483c31065d7d8099b796
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 <lowlevelcond.h>
23 #include <pthread-errnos.h>
25 #ifdef UP
26 # define LOCK
27 #else
28 # define LOCK lock
29 #endif
31 #define SYS_futex               202
32 #define FUTEX_WAIT              0
33 #define FUTEX_WAKE              1
35 /* For the calculation see asm/vsyscall.h.  */
36 #define VSYSCALL_ADDR_vgettimeofday     0xffffffffff600000
39         .text
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
45         .align  16
46 __pthread_cond_timedwait:
47 .LSTARTCODE:
48         pushq   %r12
49 .Lpush_r12:
50         pushq   %r13
51 .Lpush_r13:
52         pushq   %r14
53 .Lpush_r14:
54 #define FRAME_SIZE 80
55         subq    $FRAME_SIZE, %rsp
56 .Lsubq:
58         cmpq    $1000000000, 8(%rdx)
59         movl    $EINVAL, %eax
60         jae     18f
62         /* Stack frame:
64            rsp + 80
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                     +--------------------------+
80         */
82         cmpq    $-1, dep_mutex(%rdi)
84         /* Prepare structure passed to cancellation handler.  */
85         movq    %rdi, 8(%rsp)
86         movq    %rsi, 16(%rsp)
87         movq    %rdx, %r13
89         je      22f
90         movq    %rsi, dep_mutex(%rdi)
92         /* Get internal lock.  */
93 22:     movl    $1, %esi
94         xorl    %eax, %eax
95         LOCK
96 #if cond_lock == 0
97         cmpxchgl %esi, (%rdi)
98 #else
99         cmpxchgl %esi, cond_lock(%rdi)
100 #endif
101         jnz     1f
103         /* Unlock the mutex.  */
104 2:      movq    16(%rsp), %rdi
105         xorl    %esi, %esi
106         callq   __pthread_mutex_unlock_usercnt
108         testl   %eax, %eax
109         jne     16f
111         movq    8(%rsp), %rdi
112         incq    total_seq(%rdi)
113         incl    cond_futex(%rdi)
114         addl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
116         /* Install cancellation handler.  */
117 #ifdef PIC
118         leaq    __condvar_cleanup(%rip), %rsi
119 #else
120         leaq    __condvar_cleanup, %rsi
121 #endif
122         leaq    48(%rsp), %rdi
123         movq    %rsp, %rdx
124         callq   __pthread_cleanup_push
126         /* Get and store current wakeup_seq value.  */
127         movq    8(%rsp), %rdi
128         movq    wakeup_seq(%rdi), %r9
129         movl    broadcast_seq(%rdi), %edx
130         movq    %r9, 40(%rsp)
131         movl    %edx, 4(%rsp)
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.  */
138         movq    8(%rsp), %rdi
139         movl    cond_nwaiters(%rdi), %edi
140         andl    $((1 << nwaiters_shift) - 1), %edi
141         /* Only clocks 0 and 1 are allowed so far.  Both are handled in the
142            kernel.  */
143         leaq    24(%rsp), %rsi
144         movl    $__NR_clock_gettime, %eax
145         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 #if FUTEX_WAIT == 0
199         xorl    %esi, %esi
200 #else
201         movl    $FUTEX_WAIT, %esi
202 #endif
203         movq    %r12, %rdx
204         addq    $cond_futex, %rdi
205         movl    $SYS_futex, %eax
206         syscall
207         movq    %rax, %r14
209         movl    (%rsp), %edi
210         callq   __pthread_disable_asynccancel
212         /* Lock.  */
213         movq    8(%rsp), %rdi
214         movl    $1, %esi
215         xorl    %eax, %eax
216         LOCK
217 #if cond_lock == 0
218         cmpxchgl %esi, (%rdi)
219 #else
220         cmpxchgl %esi, cond_lock(%rdi)
221 #endif
222         jne     5f
224 6:      movl    broadcast_seq(%rdi), %edx
226         movq    woken_seq(%rdi), %rax
228         movq    wakeup_seq(%rdi), %r9
230         cmpl    4(%rsp), %edx
231         jne     23f
233         cmpq    40(%rsp), %r9
234         jbe     15f
236         cmpq    %rax, %r9
237         ja      9f
239 15:     cmpq    $-ETIMEDOUT, %r14
240         jne     8b
242 13:     incq    wakeup_seq(%rdi)
243         incl    cond_futex(%rdi)
244         movl    $ETIMEDOUT, %r14d
245         jmp     14f
247 23:     xorq    %r14, %r14
248         jmp     24f
250 9:      xorq    %r14, %r14
251 14:     incq    woken_seq(%rdi)
253 24:     subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
255         /* Wake up a thread which wants to destroy the condvar object.  */
256         cmpq    $0xffffffffffffffff, total_seq(%rdi)
257         jne     25f
258         movl    cond_nwaiters(%rdi), %eax
259         andl    $~((1 << nwaiters_shift) - 1), %eax
260         jne     25f
262         addq    $cond_nwaiters, %rdi
263         movl    $SYS_futex, %eax
264         movl    $FUTEX_WAKE, %esi
265         movl    $1, %edx
266         syscall
267         subq    $cond_nwaiters, %rdi
269 25:     LOCK
270 #if cond_lock == 0
271         decl    (%rdi)
272 #else
273         decl    cond_lock(%rdi)
274 #endif
275         jne     10f
277         /* Remove cancellation handler.  */
278 11:     movq    48+CLEANUP_PREV(%rsp), %rdx
279         movq    %rdx, %fs:CLEANUP
281         movq    16(%rsp), %rdi
282         callq   __pthread_mutex_cond_lock
284         testq   %rax, %rax
285         cmoveq  %r14, %rax
287 18:     addq    $FRAME_SIZE, %rsp
288 .Laddq:
289         popq    %r14
290 .Lpop_r14:
291         popq    %r13
292 .Lpop_r13:
293         popq    %r12
294 .Lpop_r12:
296         retq
298         /* Initial locking failed.  */
300 .LSbl1:
301 #if cond_lock != 0
302         addq    $cond_lock, %rdi
303 #endif
304         callq   __lll_mutex_lock_wait
305         jmp     2b
307         /* Unlock in loop requires wakeup.  */
309 #if cond_lock != 0
310         addq    $cond_lock, %rdi
311 #endif
312         callq   __lll_mutex_unlock_wake
313         jmp     4b
315         /* Locking in loop failed.  */
317 #if cond_lock != 0
318         addq    $cond_lock, %rdi
319 #endif
320         callq   __lll_mutex_lock_wait
321 #if cond_lock != 0
322         subq    $cond_lock, %rdi
323 #endif
324         jmp     6b
326         /* Unlock after loop requires wakeup.  */
328 #if cond_lock != 0
329         addq    $cond_lock, %rdi
330 #endif
331         callq   __lll_mutex_unlock_wake
332         jmp     11b
334         /* The initial unlocking of the mutex failed.  */
335 16:     movq    8(%rsp), %rdi
336         movq    %rax, (%rsp)
337         LOCK
338 #if cond_lock == 0
339         decl    (%rdi)
340 #else
341         decl    cond_lock(%rdi)
342 #endif
343         jne     17f
345 #if cond_lock != 0
346         addq    $cond_lock, %rdi
347 #endif
348         callq   __lll_mutex_unlock_wake
350 17:     movq    (%rsp), %rax
351         jmp     18b
353 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
354         /* clock_gettime not available.  */
355 19:     leaq    24(%rsp), %rdi
356         xorl    %esi, %esi
357         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
358         callq   *%rax
360         /* Compute relative timeout.  */
361         movq    32(%rsp), %rax
362         movl    $1000, %edx
363         mul     %rdx            /* Milli seconds to nano seconds.  */
364         movq    (%r13), %rcx
365         movq    8(%r13), %rdx
366         subq    24(%rsp), %rcx
367         subq    %rax, %rdx
368         jns     20f
369         addq    $1000000000, %rdx
370         decq    %rcx
371 20:     testq   %rcx, %rcx
372         movq    8(%rsp), %rdi
373         movq    $-ETIMEDOUT, %r14
374         js      6b
375         jmp     21b
376 #endif
377 .LENDCODE:
378         .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
379 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
380                   GLIBC_2_3_2)
383         .section .eh_frame,"a",@progbits
384 .LSTARTFRAME:
385         .long   L(ENDCIE)-L(STARTCIE)           # Length of the CIE.
386 .LSTARTCIE:
387         .long   0                               # CIE ID.
388         .byte   1                               # Version number.
389 #ifdef SHARED
390         .string "zR"                            # NUL-terminated augmentation
391                                                 # string.
392 #else
393         .ascii  "\0"                            # NUL-terminated augmentation
394                                                 # string.
395 #endif
396         .uleb128 1                              # Code alignment factor.
397         .sleb128 -8                             # Data alignment factor.
398         .byte   16                              # Return address register
399                                                 # column.
400 #ifdef SHARED
401         .uleb128 1                              # Augmentation value length.
402         .byte   0x1b                            # Encoding: DW_EH_PE_pcrel
403                                                 # + DW_EH_PE_sdata4.
404 #endif
405         .byte 0x0c                              # DW_CFA_def_cfa
406         .uleb128 7
407         .uleb128 8
408         .byte   0x90                            # DW_CFA_offset, column 0x8
409         .uleb128 1
410         .align 8
411 .LENDCIE:
413         .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
414 .LSTARTFDE:
415         .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
416 #ifdef SHARED
417         .long   .LSTARTCODE-.                   # PC-relative start address
418                                                 # of the code
419 #else
420         .long   .LSTARTCODE                     # Start address of the code.
421 #endif
422         .long   .LENDCODE-.LSTARTCODE           # Length of the code.
423 #ifdef SHARED
424         .uleb128 0                              # No augmentation data.
425 #endif
426         .byte   0x40+.Lpush_r12-.LSTARTCODE     # DW_CFA_advance_loc+N
427         .byte   14                              # DW_CFA_def_cfa_offset
428         .uleb128 16
429         .byte   0x8c                            # DW_CFA_offset %r12
430         .uleb128 2
431         .byte   0x40+.Lpush_r13-.Lpush_r12      # DW_CFA_advance_loc+N
432         .byte   14                              # DW_CFA_def_cfa_offset
433         .uleb128 24
434         .byte   0x8d                            # DW_CFA_offset %r13
435         .uleb128 3
436         .byte   0x40+.Lpush_r14-.Lpush_r13      # DW_CFA_advance_loc+N
437         .byte   14                              # DW_CFA_def_cfa_offset
438         .uleb128 32
439         .byte   0x84                            # DW_CFA_offset %r14
440         .uleb128 4
441         .byte   0x40+.Lsubq-.Lpush_r14          # DW_CFA_advance_loc+N
442         .byte   14                              # DW_CFA_def_cfa_offset
443         .uleb128 32+FRAME_SIZE
444         .byte   3                               # DW_CFA_advance_loc2
445         .2byte  .Laddq-.Lsubq
446         .byte   14                              # DW_CFA_def_cfa_offset
447         .uleb128 32
448         .byte   0x40+.Lpop_r14-.Laddq           # DW_CFA_advance_loc+N
449         .byte   14                              # DW_CFA_def_cfa_offset
450         .uleb128 24
451         .byte   0xce                            # DW_CFA_restore %r14
452         .byte   0x40+.Lpop_r13-.Lpop_r14        # DW_CFA_advance_loc+N
453         .byte   14                              # DW_CFA_def_cfa_offset
454         .uleb128 16
455         .byte   0xcd                            # DW_CFA_restore %r13
456         .byte   0x40+.Lpop_r12-.Lpop_r13        # DW_CFA_advance_loc+N
457         .byte   14                              # DW_CFA_def_cfa_offset
458         .uleb128 8
459         .byte   0xcc                            # DW_CFA_restore %r12
460         .byte   0x40+.LSbl1-.Lpop_r12           # DW_CFA_advance_loc+N
461         .byte   14                              # DW_CFA_def_cfa_offset
462         .uleb128 32+FRAME_SIZE
463         .byte   0x8c                            # DW_CFA_offset %r12
464         .uleb128 2
465         .byte   0x8d                            # DW_CFA_offset %r13
466         .uleb128 3
467         .byte   0x84                            # DW_CFA_offset %r14
468         .uleb128 4
469         .align  8
470 .LENDFDE: