.
[glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / lowlevellock.S
blob394dec8d82a71b1dc748114ada96040464c62486
1 /* Copyright (C) 2002-2006, 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 <pthread-errnos.h>
23         .text
25 #ifndef LOCK
26 # ifdef UP
27 #  define LOCK
28 # else
29 #  define LOCK lock
30 # endif
31 #endif
33 #define SYS_futex               202
34 #define FUTEX_WAIT              0
35 #define FUTEX_WAKE              1
37 /* For the calculation see asm/vsyscall.h.  */
38 #define VSYSCALL_ADDR_vgettimeofday     0xffffffffff600000
41         .globl  __lll_mutex_lock_wait
42         .type   __lll_mutex_lock_wait,@function
43         .hidden __lll_mutex_lock_wait
44         .align  16
45 __lll_mutex_lock_wait:
46         cfi_startproc
47         pushq   %r10
48         cfi_adjust_cfa_offset(8)
49         pushq   %rdx
50         cfi_adjust_cfa_offset(8)
51         cfi_offset(%r10, -16)
52         cfi_offset(%rdx, -24)
53         xorq    %r10, %r10      /* No timeout.  */
54         movl    $2, %edx
55 #if FUTEX_WAIT == 0
56         xorl    %esi, %esi
57 #else
58         movl    $FUTEX_WAIT, %esi
59 #endif
61         cmpl    %edx, %eax      /* NB:   %edx == 2 */
62         jne     2f
64 1:      movl    $SYS_futex, %eax
65         syscall
67 2:      movl    %edx, %eax
68         xchgl   %eax, (%rdi)    /* NB:   lock is implied */
70         testl   %eax, %eax
71         jnz     1b
73         popq    %rdx
74         cfi_adjust_cfa_offset(-8)
75         cfi_restore(%rdx)
76         popq    %r10
77         cfi_adjust_cfa_offset(-8)
78         cfi_restore(%r10)
79         retq
80         cfi_endproc
81         .size   __lll_mutex_lock_wait,.-__lll_mutex_lock_wait
84 #ifdef NOT_IN_libc
85         .globl  __lll_mutex_timedlock_wait
86         .type   __lll_mutex_timedlock_wait,@function
87         .hidden __lll_mutex_timedlock_wait
88         .align  16
89 __lll_mutex_timedlock_wait:
90         cfi_startproc
91         /* Check for a valid timeout value.  */
92         cmpq    $1000000000, 8(%rdx)
93         jae     3f
95         pushq   %r8
96         cfi_adjust_cfa_offset(8)
97         pushq   %r9
98         cfi_adjust_cfa_offset(8)
99         pushq   %r12
100         cfi_adjust_cfa_offset(8)
101         pushq   %r13
102         cfi_adjust_cfa_offset(8)
103         pushq   %r14
104         cfi_adjust_cfa_offset(8)
105         cfi_offset(%r8, -16)
106         cfi_offset(%r9, -24)
107         cfi_offset(%r12, -32)
108         cfi_offset(%r13, -40)
109         cfi_offset(%r14, -48)
111         /* Stack frame for the timespec and timeval structs.  */
112         subq    $16, %rsp
113         cfi_adjust_cfa_offset(16)
115         movq    %rdi, %r12
116         movq    %rdx, %r13
119         /* Get current time.  */
120         movq    %rsp, %rdi
121         xorl    %esi, %esi
122         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
123         /* This is a regular function call, all caller-save registers
124            might be clobbered.  */
125         callq   *%rax
127         /* Compute relative timeout.  */
128         movq    8(%rsp), %rax
129         movl    $1000, %edi
130         mul     %rdi            /* Milli seconds to nano seconds.  */
131         movq    (%r13), %rdi
132         movq    8(%r13), %rsi
133         subq    (%rsp), %rdi
134         subq    %rax, %rsi
135         jns     4f
136         addq    $1000000000, %rsi
137         decq    %rdi
138 4:      testq   %rdi, %rdi
139         js      5f              /* Time is already up.  */
141         /* Futex call.  */
142         movq    %rdi, (%rsp)    /* Store relative timeout.  */
143         movq    %rsi, 8(%rsp)
145         movl    $1, %eax
146         movl    $2, %edx
147         LOCK
148         cmpxchgl %edx, (%r12)
150         testl   %eax, %eax
151         je      8f
153         movq    %rsp, %r10
154 #if FUTEX_WAIT == 0
155         xorl    %esi, %esi
156 #else
157         movl    $FUTEX_WAIT, %esi
158 #endif
159         movq    %r12, %rdi
160         movl    $SYS_futex, %eax
161         syscall
162         movq    %rax, %rcx
164 8:                              /* NB: %edx == 2 */
165         xorl    %eax, %eax
166         LOCK
167         cmpxchgl %edx, (%r12)
168         jnz     7f
170 6:      addq    $16, %rsp
171         cfi_adjust_cfa_offset(-16)
172         popq    %r14
173         cfi_adjust_cfa_offset(-8)
174         cfi_restore(%r14)
175         popq    %r13
176         cfi_adjust_cfa_offset(-8)
177         cfi_restore(%r13)
178         popq    %r12
179         cfi_adjust_cfa_offset(-8)
180         cfi_restore(%r12)
181         popq    %r9
182         cfi_adjust_cfa_offset(-8)
183         cfi_restore(%r9)
184         popq    %r8
185         cfi_adjust_cfa_offset(-8)
186         cfi_restore(%r8)
187         retq
189 3:      movl    $EINVAL, %eax
190         retq
192         cfi_adjust_cfa_offset(56)
193         cfi_offset(%r8, -16)
194         cfi_offset(%r9, -24)
195         cfi_offset(%r12, -32)
196         cfi_offset(%r13, -40)
197         cfi_offset(%r14, -48)
198         /* Check whether the time expired.  */
199 7:      cmpq    $-ETIMEDOUT, %rcx
200         je      5f
202         /* Make sure the current holder knows we are going to sleep.  */
203         movl    %edx, %eax
204         xchgl   %eax, (%rdi)
205         testl   %eax, %eax
206         jz      6b
207         jmp     1b
209 5:      movl    $ETIMEDOUT, %eax
210         jmp     6b
211         cfi_endproc
212         .size   __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait
213 #endif
216 #ifdef NOT_IN_libc
217         .globl  lll_unlock_wake_cb
218         .type   lll_unlock_wake_cb,@function
219         .hidden lll_unlock_wake_cb
220         .align  16
221 lll_unlock_wake_cb:
222         pushq   %rsi
223         pushq   %rdx
225         LOCK
226         addl    $1, (%rdi)
227         jng     1f
229         popq    %rdx
230         popq    %rsi
231         retq
232         .size   lll_unlock_wake_cb,.-lll_unlock_wake_cb
233 #endif
236         .globl  __lll_mutex_unlock_wake
237         .type   __lll_mutex_unlock_wake,@function
238         .hidden __lll_mutex_unlock_wake
239         .align  16
240 __lll_mutex_unlock_wake:
241         cfi_startproc
242         pushq   %rsi
243         cfi_adjust_cfa_offset(8)
244         pushq   %rdx
245         cfi_adjust_cfa_offset(8)
246         cfi_offset(%rsi, -16)
247         cfi_offset(%rdx, -24)
249         movl    $0, (%rdi)
250         movl    $FUTEX_WAKE, %esi
251         movl    $1, %edx        /* Wake one thread.  */
252         movl    $SYS_futex, %eax
253         syscall
255         popq    %rdx
256         cfi_adjust_cfa_offset(-8)
257         cfi_restore(%rdx)
258         popq    %rsi
259         cfi_adjust_cfa_offset(-8)
260         cfi_restore(%rsi)
261         retq
262         cfi_endproc
263         .size   __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake
266 #ifdef NOT_IN_libc
267         .globl  __lll_timedwait_tid
268         .type   __lll_timedwait_tid,@function
269         .hidden __lll_timedwait_tid
270         .align  16
271 __lll_timedwait_tid:
272         pushq   %r12
273         pushq   %r13
275         movq    %rdi, %r12
276         movq    %rsi, %r13
278         subq    $16, %rsp
280         /* Get current time.  */
281 2:      movq    %rsp, %rdi
282         xorl    %esi, %esi
283         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
284         callq   *%rax
286         /* Compute relative timeout.  */
287         movq    8(%rsp), %rax
288         movl    $1000, %edi
289         mul     %rdi            /* Milli seconds to nano seconds.  */
290         movq    (%r13), %rdi
291         movq    8(%r13), %rsi
292         subq    (%rsp), %rdi
293         subq    %rax, %rsi
294         jns     5f
295         addq    $1000000000, %rsi
296         decq    %rdi
297 5:      testq   %rdi, %rdi
298         js      6f              /* Time is already up.  */
300         movq    %rdi, (%rsp)    /* Store relative timeout.  */
301         movq    %rsi, 8(%rsp)
303         movl    (%r12), %edx
304         testl   %edx, %edx
305         jz      4f
307         movq    %rsp, %r10
308 #if FUTEX_WAIT == 0
309         xorl    %esi, %esi
310 #else
311         movl    $FUTEX_WAIT, %esi
312 #endif
313         movq    %r12, %rdi
314         movl    $SYS_futex, %eax
315         syscall
317         cmpl    $0, (%rdi)
318         jne     1f
319 4:      xorl    %eax, %eax
321 8:      addq    $16, %rsp
322         popq    %r13
323         popq    %r12
324         retq
326 1:      cmpq    $-ETIMEDOUT, %rax
327         jne     2b
329 6:      movl    $ETIMEDOUT, %eax
330         jmp     8b
331         .size   __lll_timedwait_tid,.-__lll_timedwait_tid
332 #endif