Extend x86-64 pthread_rwlock_timedwrlock to use futex syscall with absolute timeout.
[glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_rwlock_timedwrlock.S
blobbfc653da29a801b545431420b57ae3102ccc0aa5
1 /* Copyright (C) 2002, 2003, 2005, 2007, 2009 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_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         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, NR_READERS(%r12)
73         je      5f
75         /* Check the value of the timeout parameter.  */
76 3:      cmpq    $1000000000, 8(%r13)
77         jae     19f
79         incl    WRITERS_QUEUED(%r12)
80         je      4f
82         movl    WRITERS_WAKEUP(%r12), VALREG
84         LOCK
85 #if MUTEX == 0
86         decl    (%r12)
87 #else
88         decl    MUTEX(%r12)
89 #endif
90         jne     10f
92 11:
93 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
94 #  ifdef PIC
95         cmpl    $0, __have_futex_clock_realtime(%rip)
96 #  else
97         cmpl    $0, __have_futex_clock_realtime
98 #  endif
99         je      .Lreltmo
100 #endif
102         movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %esi
103         xorl    PSHARED(%r12), %esi
104         movq    %r13, %r10
105         movl    $0xffffffff, %r9d
106 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
107         movl    %r14d, %edx
108 #endif
109 21:     leaq    WRITERS_WAKEUP(%r12), %rdi
110         movl    $SYS_futex, %eax
111         syscall
112         movq    %rax, %rdx
114 #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
115         .subsection 2
116 .Lreltmo:
117         /* Get current time.  */
118         movq    %rsp, %rdi
119         xorl    %esi, %esi
120         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
121         callq   *%rax
123         /* Compute relative timeout.  */
124         movq    8(%rsp), %rax
125         movl    $1000, %edi
126         mul     %rdi            /* Milli seconds to nano seconds.  */
127         movq    (%r13), %rcx
128         movq    8(%r13), %rdi
129         subq    (%rsp), %rcx
130         subq    %rax, %rdi
131         jns     15f
132         addq    $1000000000, %rdi
133         decq    %rcx
134 15:     testq   %rcx, %rcx
135         js      16f             /* Time is already up.  */
137         /* Futex call.  */
138         movq    %rcx, (%rsp)    /* Store relative timeout.  */
139         movq    %rdi, 8(%rsp)
141 #ifdef __ASSUME_PRIVATE_FUTEX
142         movl    $FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi
143         xorl    PSHARED(%r12), %esi
144 #else
145 # if FUTEX_WAIT == 0
146         movl    PSHARED(%r12), %esi
147 # else
148         movl    $FUTEX_WAIT, %esi
149         orl     PSHARED(%r12), %esi
150 # endif
151         xorl    %fs:PRIVATE_FUTEX, %esi
152 #endif
153         movq    %rsp, %r10
154         movl    %r14d, %edx
156         jmp     21b
157         .previous
158 #endif
160 17:     /* Reget the lock.  */
161         movl    $1, %esi
162         xorl    %eax, %eax
163         LOCK
164 #if MUTEX == 0
165         cmpxchgl %esi, (%r12)
166 #else
167         cmpxchgl %esi, MUTEX(%r12)
168 #endif
169         jnz     12f
171 13:     decl    WRITERS_QUEUED(%r12)
172         cmpq    $-ETIMEDOUT, %rdx
173         jne     2b
175 18:     movl    $ETIMEDOUT, %edx
176         jmp     9f
179 5:      xorl    %edx, %edx
180         movl    %fs:TID, %eax
181         movl    %eax, WRITER(%r12)
182 9:      LOCK
183 #if MUTEX == 0
184         decl    (%r12)
185 #else
186         decl    MUTEX(%r12)
187 #endif
188         jne     6f
190 7:      movq    %rdx, %rax
192 #ifndef __ASSUME_PRIVATE_FUTEX
193         addq    $16, %rsp
194         cfi_adjust_cfa_offset(-16)
195         popq    %r14
196         cfi_adjust_cfa_offset(-8)
197         cfi_restore(%r14)
198 #endif
199         popq    %r13
200         cfi_adjust_cfa_offset(-8)
201         cfi_restore(%r13)
202         popq    %r12
203         cfi_adjust_cfa_offset(-8)
204         cfi_restore(%r12)
205         retq
207 #ifdef __ASSUME_PRIVATE_FUTEX
208         cfi_adjust_cfa_offset(16)
209         cfi_rel_offset(%r12, 8)
210         cfi_rel_offset(%r13, 0)
211 #else
212         cfi_adjust_cfa_offset(40)
213         cfi_offset(%r12, -16)
214         cfi_offset(%r13, -24)
215         cfi_offset(%r14, -32)
216 #endif
217 1:      movl    PSHARED(%rdi), %esi
218 #if MUTEX != 0
219         addq    $MUTEX, %rdi
220 #endif
221         callq   __lll_lock_wait
222         jmp     2b
224 14:     cmpl    %fs:TID, %eax
225         jne     3b
226 20:     movl    $EDEADLK, %edx
227         jmp     9b
229 6:      movl    PSHARED(%r12), %esi
230 #if MUTEX == 0
231         movq    %r12, %rdi
232 #else
233         leal    MUTEX(%r12), %rdi
234 #endif
235         callq   __lll_unlock_wake
236         jmp     7b
238         /* Overflow.  */
239 4:      decl    WRITERS_QUEUED(%r12)
240         movl    $EAGAIN, %edx
241         jmp     9b
243 10:     movl    PSHARED(%r12), %esi
244 #if MUTEX == 0
245         movq    %r12, %rdi
246 #else
247         leaq    MUTEX(%r12), %rdi
248 #endif
249         callq   __lll_unlock_wake
250         jmp     11b
252 12:     movl    PSHARED(%r12), %esi
253 #if MUTEX == 0
254         movq    %r12, %rdi
255 #else
256         leaq    MUTEX(%r12), %rdi
257 #endif
258         callq   __lll_lock_wait
259         jmp     13b
261 16:     movq    $-ETIMEDOUT, %rdx
262         jmp     17b
264 19:     movl    $EINVAL, %edx
265         jmp     9b
266         cfi_endproc
267         .size   pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock