Updated to fedora-glibc-20041006T0900
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / lowlevellock.S
1 /* Copyright (C) 2002, 2003, 2004 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 <pthread-errnos.h>
22
23         .text
24
25 #ifndef LOCK
26 # ifdef UP
27 #  define LOCK
28 # else
29 #  define LOCK lock
30 # endif
31 #endif
32
33 #define SYS_futex               202
34 #define FUTEX_WAIT              0
35 #define FUTEX_WAKE              1
36
37 /* For the calculation see asm/vsyscall.h.  */
38 #define VSYSCALL_ADDR_vgettimeofday     0xffffffffff600000
39
40
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         pushq   %r10
47         pushq   %rdx
48
49         xorq    %r10, %r10      /* No timeout.  */
50         movl    $2, %edx
51         movq    %r10, %rsi      /* movq $FUTEX_WAIT, %rsi */
52
53         cmpl    %edx, %eax      /* NB:   %edx == 2 */
54         jne     2f
55
56 1:      movq    $SYS_futex, %rax
57         syscall
58
59 2:      movl    %edx, %eax
60         xchgl   %eax, (%rdi)    /* NB:   lock is implied */
61
62         testl   %eax, %eax
63         jnz     1b
64
65         popq    %rdx
66         popq    %r10
67         retq
68         .size   __lll_mutex_lock_wait,.-__lll_mutex_lock_wait
69
70
71 #ifdef NOT_IN_libc
72         .globl  __lll_mutex_timedlock_wait
73         .type   __lll_mutex_timedlock_wait,@function
74         .hidden __lll_mutex_timedlock_wait
75         .align  16
76 __lll_mutex_timedlock_wait:
77         /* Check for a valid timeout value.  */
78         cmpq    $1000000000, 8(%rdx)
79         jae     3f
80
81         pushq   %r8
82         pushq   %r9
83         pushq   %r12
84         pushq   %r13
85         pushq   %r14
86
87         /* Stack frame for the timespec and timeval structs.  */
88         subq    $16, %rsp
89
90         movq    %rdi, %r12
91         movq    %rdx, %r13
92
93 1:
94         /* Get current time.  */
95         movq    %rsp, %rdi
96         xorq    %rsi, %rsi
97         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
98         /* This is a regular function call, all caller-save registers
99            might be clobbered.  */
100         callq   *%rax
101
102         /* Compute relative timeout.  */
103         movq    8(%rsp), %rax
104         movq    $1000, %rdi
105         mul     %rdi            /* Milli seconds to nano seconds.  */
106         movq    (%r13), %rdi
107         movq    8(%r13), %rsi
108         subq    (%rsp), %rdi
109         subq    %rax, %rsi
110         jns     4f
111         addq    $1000000000, %rsi
112         decq    %rdi
113 4:      testq   %rdi, %rdi
114         js      5f              /* Time is already up.  */
115
116         /* Futex call.  */
117         movq    %rdi, (%rsp)    /* Store relative timeout.  */
118         movq    %rsi, 8(%rsp)
119
120         movl    $1, %eax
121         movl    $2, %edx
122         LOCK
123         cmpxchgl %edx, (%r12)
124
125         testl   %eax, %eax
126         je      8f
127
128         movq    %rsp, %r10
129         xorq    %rsi, %rsi      /* movq $FUTEX_WAIT, %rsi */
130         movq    %r12, %rdi
131         movq    $SYS_futex, %rax
132         syscall
133         movq    %rax, %rcx
134
135 8:                              /* NB: %edx == 2 */
136         xorl    %eax, %eax
137         LOCK
138         cmpxchgl %edx, (%rdi)
139         jnz     7f
140
141 6:      addq    $16, %rsp
142         popq    %r14
143         popq    %r13
144         popq    %r12
145         popq    %r9
146         popq    %r8
147         retq
148
149         /* Check whether the time expired.  */
150 7:      cmpq    $-ETIMEDOUT, %rcx
151         je      5f
152
153         /* Make sure the current holder knows we are going to sleep.  */
154         movl    %edx, %eax
155         xchgl   %eax, (%rdi)
156         testl   %eax, %eax
157         jz      6b
158         jmp     1b
159
160 3:      movl    $EINVAL, %eax
161         retq
162
163 5:      movl    $ETIMEDOUT, %eax
164         jmp     6b
165         .size   __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait
166 #endif
167
168
169 #ifdef NOT_IN_libc
170         .globl  lll_unlock_wake_cb
171         .type   lll_unlock_wake_cb,@function
172         .hidden lll_unlock_wake_cb
173         .align  16
174 lll_unlock_wake_cb:
175         pushq   %rsi
176         pushq   %rdx
177
178         LOCK
179         addl    $1, (%rdi)
180         jng     1f
181
182         popq    %rdx
183         popq    %rsi
184         retq
185         .size   lll_unlock_wake_cb,.-lll_unlock_wake_cb
186 #endif
187
188
189         .globl  __lll_mutex_unlock_wake
190         .type   __lll_mutex_unlock_wake,@function
191         .hidden __lll_mutex_unlock_wake
192         .align  16
193 __lll_mutex_unlock_wake:
194         pushq   %rsi
195         pushq   %rdx
196
197         movl    $0, (%rdi)
198         movq    $FUTEX_WAKE, %rsi
199         movl    $1, %edx        /* Wake one thread.  */
200         movq    $SYS_futex, %rax
201         syscall
202
203         popq    %rdx
204         popq    %rsi
205         retq
206         .size   __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake
207
208
209 #ifdef NOT_IN_libc
210         .globl  __lll_timedwait_tid
211         .type   __lll_timedwait_tid,@function
212         .hidden __lll_timedwait_tid
213         .align  16
214 __lll_timedwait_tid:
215         pushq   %r12
216         pushq   %r13
217
218         movq    %rdi, %r12
219         movq    %rsi, %r13
220
221         subq    $16, %rsp
222
223         /* Get current time.  */
224 2:      movq    %rsp, %rdi
225         xorq    %rsi, %rsi
226         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
227         callq   *%rax
228
229         /* Compute relative timeout.  */
230         movq    8(%rsp), %rax
231         movq    $1000, %rdi
232         mul     %rdi            /* Milli seconds to nano seconds.  */
233         movq    (%r13), %rdi
234         movq    8(%r13), %rsi
235         subq    (%rsp), %rdi
236         subq    %rax, %rsi
237         jns     5f
238         addq    $1000000000, %rsi
239         decq    %rdi
240 5:      testq   %rdi, %rdi
241         js      6f              /* Time is already up.  */
242
243         movq    %rdi, (%rsp)    /* Store relative timeout.  */
244         movq    %rsi, 8(%rsp)
245
246         movl    (%r12), %edx
247         testl   %edx, %edx
248         jz      4f
249
250         movq    %rsp, %r10
251         xorq    %rsi, %rsi      /* movq $FUTEX_WAIT, %rsi */
252         movq    %r12, %rdi
253         movq    $SYS_futex, %rax
254         syscall
255
256         cmpl    $0, (%rdi)
257         jne     1f
258 4:      xorl    %eax, %eax
259
260 8:      addq    $16, %rsp
261         popq    %r13
262         popq    %r12
263         retq
264
265 1:      cmpq    $-ETIMEDOUT, %rax
266         jne     2b
267
268 6:      movl    $ETIMEDOUT, %eax
269         jmp     8b
270         .size   __lll_timedwait_tid,.-__lll_timedwait_tid
271 #endif