]> git.ipfire.org Git - thirdparty/glibc.git/blob - nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
.
[thirdparty/glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / lowlevellock.S
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.
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 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
60
61 cmpl %edx, %eax /* NB: %edx == 2 */
62 jne 2f
63
64 1: movl $SYS_futex, %eax
65 syscall
66
67 2: movl %edx, %eax
68 xchgl %eax, (%rdi) /* NB: lock is implied */
69
70 testl %eax, %eax
71 jnz 1b
72
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
82
83
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
94
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)
110
111 /* Stack frame for the timespec and timeval structs. */
112 subq $16, %rsp
113 cfi_adjust_cfa_offset(16)
114
115 movq %rdi, %r12
116 movq %rdx, %r13
117
118 1:
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
126
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. */
140
141 /* Futex call. */
142 movq %rdi, (%rsp) /* Store relative timeout. */
143 movq %rsi, 8(%rsp)
144
145 movl $1, %eax
146 movl $2, %edx
147 LOCK
148 cmpxchgl %edx, (%r12)
149
150 testl %eax, %eax
151 je 8f
152
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
163
164 8: /* NB: %edx == 2 */
165 xorl %eax, %eax
166 LOCK
167 cmpxchgl %edx, (%r12)
168 jnz 7f
169
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
188
189 3: movl $EINVAL, %eax
190 retq
191
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
201
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
208
209 5: movl $ETIMEDOUT, %eax
210 jmp 6b
211 cfi_endproc
212 .size __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait
213 #endif
214
215
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
224
225 LOCK
226 addl $1, (%rdi)
227 jng 1f
228
229 popq %rdx
230 popq %rsi
231 retq
232 .size lll_unlock_wake_cb,.-lll_unlock_wake_cb
233 #endif
234
235
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)
248
249 movl $0, (%rdi)
250 movl $FUTEX_WAKE, %esi
251 movl $1, %edx /* Wake one thread. */
252 movl $SYS_futex, %eax
253 syscall
254
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
264
265
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
274
275 movq %rdi, %r12
276 movq %rsi, %r13
277
278 subq $16, %rsp
279
280 /* Get current time. */
281 2: movq %rsp, %rdi
282 xorl %esi, %esi
283 movq $VSYSCALL_ADDR_vgettimeofday, %rax
284 callq *%rax
285
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. */
299
300 movq %rdi, (%rsp) /* Store relative timeout. */
301 movq %rsi, 8(%rsp)
302
303 movl (%r12), %edx
304 testl %edx, %edx
305 jz 4f
306
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
316
317 cmpl $0, (%rdi)
318 jne 1f
319 4: xorl %eax, %eax
320
321 8: addq $16, %rsp
322 popq %r13
323 popq %r12
324 retq
325
326 1: cmpq $-ETIMEDOUT, %rax
327 jne 2b
328
329 6: movl $ETIMEDOUT, %eax
330 jmp 8b
331 .size __lll_timedwait_tid,.-__lll_timedwait_tid
332 #endif