Work around kernel rejecting valid absolute timestamps
[glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_rwlock_timedrdlock.S
blobf5d055c77ec9f35fb3809e26427130df2daf26f0
1 /* Copyright (C) 2002-2005, 2007, 2009, 2010 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 <lowlevellock.h>
22 #include <lowlevelrwlock.h>
23 #include <pthread-errnos.h>
24 #include <kernel-features.h>
27 /* For the calculation see asm/vsyscall.h.  */
28 #define VSYSCALL_ADDR_vgettimeofday     0xffffffffff600000
30         .text
32         .globl  pthread_rwlock_timedrdlock
33         .type   pthread_rwlock_timedrdlock,@function
34         .align  16
35 pthread_rwlock_timedrdlock:
36         cfi_startproc
37         pushq   %r12
38         cfi_adjust_cfa_offset(8)
39         cfi_rel_offset(%r12, 0)
40         pushq   %r13
41         cfi_adjust_cfa_offset(8)
42         cfi_rel_offset(%r13, 0)
43 #ifdef __ASSUME_FUTEX_CLOCK_REALTIME
44 # define VALREG %edx
45 #else
46         pushq   %r14
47         cfi_adjust_cfa_offset(8)
48         cfi_rel_offset(%r14, 0)
50         subq    $16, %rsp
51         cfi_adjust_cfa_offset(16)
52 # define VALREG %r14d
53 #endif
55         movq    %rdi, %r12
56         movq    %rsi, %r13
58         /* Get the lock.  */
59         movl    $1, %esi
60         xorl    %eax, %eax
61         LOCK
62 #if MUTEX == 0
63         cmpxchgl %esi, (%rdi)
64 #else
65         cmpxchgl %esi, MUTEX(%rdi)
66 #endif
67         jnz     1f
69 2:      movl    WRITER(%r12), %eax
70         testl   %eax, %eax
71         jne     14f
72         cmpl    $0, WRITERS_QUEUED(%r12)
73         je      5f
74         cmpl    $0, FLAGS(%r12)
75         je      5f
77         /* Check the value of the timeout parameter.  */
78 3:      cmpq    $1000000000, 8(%r13)
79         jae     19f
81         incl    READERS_QUEUED(%r12)
82         je      4f
84         movl    READERS_WAKEUP(%r12), VALREG
86         /* Unlock.  */
87         LOCK
88 #if MUTEX == 0
89         decl    (%r12)
90 #else
91         decl    MUTEX(%r12)
92 #endif
93         jne     10f
95 11:
96 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
97 #  ifdef PIC
98         cmpl    $0, __have_futex_clock_realtime(%rip)
99 #  else
100         cmpl    $0, __have_futex_clock_realtime
101 #  endif
102         je      .Lreltmo
103 #endif
105         cmpq    $0, (%r13)
106         js      16f             /* Time is already up.  */
108         movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %esi
109         xorl    PSHARED(%r12), %esi
110         movq    %r13, %r10
111         movl    $0xffffffff, %r9d
112 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
113         movl    %r14d, %edx
114 #endif
115 21:     leaq    READERS_WAKEUP(%r12), %rdi
116         movl    $SYS_futex, %eax
117         syscall
118         movq    %rax, %rdx
120 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
121         .subsection 2
122 .Lreltmo:
123         /* Get current time.  */
124         movq    %rsp, %rdi
125         xorl    %esi, %esi
126         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
127         callq   *%rax
129         /* Compute relative timeout.  */
130         movq    8(%rsp), %rax
131         movl    $1000, %edi
132         mul     %rdi            /* Milli seconds to nano seconds.  */
133         movq    (%r13), %rcx
134         movq    8(%r13), %rdi
135         subq    (%rsp), %rcx
136         subq    %rax, %rdi
137         jns     15f
138         addq    $1000000000, %rdi
139         decq    %rcx
140 15:     testq   %rcx, %rcx
141         js      16f             /* Time is already up.  */
143         /* Futex call.  */
144         movq    %rcx, (%rsp)    /* Store relative timeout.  */
145         movq    %rdi, 8(%rsp)
147 # ifdef __ASSUME_PRIVATE_FUTEX
148         movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi
149         xorl    PSHARED(%r12), %esi
150 # else
151 #  if FUTEX_WAIT == 0
152         movl    PSHARED(%r12), %esi
153 #  else
154         movl    $FUTEX_WAIT, %esi
155         orl     PSHARED(%r12), %esi
156 #  endif
157         xorl    %fs:PRIVATE_FUTEX, %esi
158 # endif
159         movq    %rsp, %r10
160         movl    %r14d, %edx
162         jmp     21b
163         .previous
164 #endif
166 17:     /* Reget the lock.  */
167         movl    $1, %esi
168         xorl    %eax, %eax
169         LOCK
170 #if MUTEX == 0
171         cmpxchgl %esi, (%r12)
172 #else
173         cmpxchgl %esi, MUTEX(%r12)
174 #endif
175         jnz     12f
177 13:     decl    READERS_QUEUED(%r12)
178         cmpq    $-ETIMEDOUT, %rdx
179         jne     2b
181 18:     movl    $ETIMEDOUT, %edx
182         jmp     9f
185 5:      xorl    %edx, %edx
186         incl    NR_READERS(%r12)
187         je      8f
188 9:      LOCK
189 #if MUTEX == 0
190         decl    (%r12)
191 #else
192         decl    MUTEX(%r12)
193 #endif
194         jne     6f
196 7:      movq    %rdx, %rax
198 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
199         addq    $16, %rsp
200         cfi_adjust_cfa_offset(-16)
201         popq    %r14
202         cfi_adjust_cfa_offset(-8)
203         cfi_restore(%r14)
204 #endif
205         popq    %r13
206         cfi_adjust_cfa_offset(-8)
207         cfi_restore(%r13)
208         popq    %r12
209         cfi_adjust_cfa_offset(-8)
210         cfi_restore(%r12)
211         retq
213 #ifdef __ASSUME_PRIVATE_FUTEX
214         cfi_adjust_cfa_offset(16)
215         cfi_rel_offset(%r12, 8)
216         cfi_rel_offset(%r13, 0)
217 #else
218         cfi_adjust_cfa_offset(40)
219         cfi_offset(%r12, -16)
220         cfi_offset(%r13, -24)
221         cfi_offset(%r14, -32)
222 #endif
223 1:      movl    PSHARED(%rdi), %esi
224 #if MUTEX != 0
225         addq    $MUTEX, %rdi
226 #endif
227         callq   __lll_lock_wait
228         jmp     2b
230 14:     cmpl    %fs:TID, %eax
231         jne     3b
232         movl    $EDEADLK, %edx
233         jmp     9b
235 6:      movl    PSHARED(%r12), %esi
236 #if MUTEX == 0
237         movq    %r12, %rdi
238 #else
239         leal    MUTEX(%r12), %rdi
240 #endif
241         callq   __lll_unlock_wake
242         jmp     7b
244         /* Overflow.  */
245 8:      decl    NR_READERS(%r12)
246         movl    $EAGAIN, %edx
247         jmp     9b
249         /* Overflow.  */
250 4:      decl    READERS_QUEUED(%r12)
251         movl    $EAGAIN, %edx
252         jmp     9b
254 10:     movl    PSHARED(%r12), %esi
255 #if MUTEX == 0
256         movq    %r12, %rdi
257 #else
258         leaq    MUTEX(%r12), %rdi
259 #endif
260         callq   __lll_unlock_wake
261         jmp     11b
263 12:     movl    PSHARED(%r12), %esi
264 #if MUTEX == 0
265         movq    %r12, %rdi
266 #else
267         leaq    MUTEX(%r12), %rdi
268 #endif
269         callq   __lll_lock_wait
270         jmp     13b
272 16:     movq    $-ETIMEDOUT, %rdx
273         jmp     17b
275 19:     movl    $EINVAL, %edx
276         jmp     9b
277         cfi_endproc
278         .size   pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock