* sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: Fix
[glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_rwlock_timedrdlock.S
blobf703eeb29f1c8052097ce250a3a60921284f6da1
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 <lowlevelrwlock.h>
22 #include <pthread-errnos.h>
23 #include <kernel-features.h>
26 #define SYS_futex               202
27 #define FUTEX_WAIT              0
28 #define FUTEX_WAKE              1
29 #define FUTEX_PRIVATE_FLAG      128
31 /* For the calculation see asm/vsyscall.h.  */
32 #define VSYSCALL_ADDR_vgettimeofday     0xffffffffff600000
35 #ifndef UP
36 # define LOCK lock
37 #else
38 # define LOCK
39 #endif
42         .text
44         .globl  pthread_rwlock_timedrdlock
45         .type   pthread_rwlock_timedrdlock,@function
46         .align  16
47 pthread_rwlock_timedrdlock:
48         pushq   %r12
49         pushq   %r13
50         pushq   %r14
51         subq    $16, %rsp
53         movq    %rdi, %r12
54         movq    %rsi, %r13
56         /* Get the lock.  */
57         movl    $1, %esi
58         xorl    %eax, %eax
59         LOCK
60 #if MUTEX == 0
61         cmpxchgl %esi, (%rdi)
62 #else
63         cmpxchgl %esi, MUTEX(%rdi)
64 #endif
65         jnz     1f
67 2:      movl    WRITER(%r12), %eax
68         testl   %eax, %eax
69         jne     14f
70         cmpl    $0, WRITERS_QUEUED(%r12)
71         je      5f
72         cmpl    $0, FLAGS(%r12)
73         je      5f
75         /* Check the value of the timeout parameter.  */
76 3:      cmpq    $1000000000, 8(%r13)
77         jae     19f
79         incl    READERS_QUEUED(%r12)
80         je      4f
82         movl    READERS_WAKEUP(%r12), %r14d
84         /* Unlock.  */
85         LOCK
86 #if MUTEX == 0
87         decl    (%r12)
88 #else
89         decl    MUTEX(%r12)
90 #endif
91         jne     10f
93         /* Get current time.  */
94 11:     movq    %rsp, %rdi
95         xorl    %esi, %esi
96         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
97         callq   *%rax
99         /* Compute relative timeout.  */
100         movq    8(%rsp), %rax
101         movl    $1000, %edi
102         mul     %rdi            /* Milli seconds to nano seconds.  */
103         movq    (%r13), %rcx
104         movq    8(%r13), %rdi
105         subq    (%rsp), %rcx
106         subq    %rax, %rdi
107         jns     15f
108         addq    $1000000000, %rdi
109         decq    %rcx
110 15:     testq   %rcx, %rcx
111         js      16f             /* Time is already up.  */
113         /* Futex call.  */
114         movq    %rcx, (%rsp)    /* Store relative timeout.  */
115         movq    %rdi, 8(%rsp)
117 #ifdef __ASSUME_PRIVATE_FUTEX
118         movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi
119         xorl    PSHARED(%r12), %esi
120 #else
121 # if FUTEX_WAIT == 0
122         movl    PSHARED(%r12), %esi
123 # else
124         movl    $FUTEX_WAIT, %esi
125         orl     PSHARED(%r12), %esi
126 # endif
127         xorl    %fs:PRIVATE_FUTEX, %esi
128 #endif
129         movq    %rsp, %r10
130         movl    %r14d, %edx
131         leaq    READERS_WAKEUP(%r12), %rdi
132         movl    $SYS_futex, %eax
133         syscall
134         movq    %rax, %rdx
137         /* Reget the lock.  */
138         movl    $1, %esi
139         xorl    %eax, %eax
140         LOCK
141 #if MUTEX == 0
142         cmpxchgl %esi, (%r12)
143 #else
144         cmpxchgl %esi, MUTEX(%r12)
145 #endif
146         jnz     12f
148 13:     decl    READERS_QUEUED(%r12)
149         cmpq    $-ETIMEDOUT, %rdx
150         jne     2b
152 18:     movl    $ETIMEDOUT, %edx
153         jmp     9f
156 5:      xorl    %edx, %edx
157         incl    NR_READERS(%r12)
158         je      8f
159 9:      LOCK
160 #if MUTEX == 0
161         decl    (%r12)
162 #else
163         decl    MUTEX(%r12)
164 #endif
165         jne     6f
167 7:      movq    %rdx, %rax
169         addq    $16, %rsp
170         popq    %r14
171         popq    %r13
172         popq    %r12
173         retq
176 #if MUTEX != 0
177         addq    $MUTEX, %rdi
178 #endif
179         callq   __lll_mutex_lock_wait
180         jmp     2b
182 14:     cmpl    %fs:TID, %eax
183         jne     3b
184         movl    $EDEADLK, %edx
185         jmp     9b
188 #if MUTEX == 0
189         movq    %r12, %rdi
190 #else
191         leal    MUTEX(%r12), %rdi
192 #endif
193         callq   __lll_mutex_unlock_wake
194         jmp     7b
196         /* Overflow.  */
197 8:      decl    NR_READERS(%r12)
198         movl    $EAGAIN, %edx
199         jmp     9b
201         /* Overflow.  */
202 4:      decl    READERS_QUEUED(%r12)
203         movl    $EAGAIN, %edx
204         jmp     9b
207 #if MUTEX == 0
208         movq    %r12, %rdi
209 #else
210         leaq    MUTEX(%r12), %rdi
211 #endif
212         callq   __lll_mutex_unlock_wake
213         jmp     11b
216 #if MUTEX == 0
217         movq    %r12, %rdi
218 #else
219         leaq    MUTEX(%r12), %rdi
220 #endif
221         callq   __lll_mutex_lock_wait
222         jmp     13b
224 16:     movq    $-ETIMEDOUT, %rdx
225         jmp     17b
227 19:     movl    $EINVAL, %edx
228         jmp     9b
229         .size   pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock