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