2.9
[glibc/nacl-glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / lowlevellock.S
blob4505e2cec6a3da4081ae7023c486d25516ca3e3f
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>
22 #include <kernel-features.h>
23 #include <lowlevellock.h>
25         .text
27 #ifdef __ASSUME_PRIVATE_FUTEX
28 # define LOAD_PRIVATE_FUTEX_WAIT(reg) \
29         movl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
30 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
31         movl    $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
32 # define LOAD_FUTEX_WAIT(reg) \
33         xorl    $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
34 # define LOAD_FUTEX_WAKE(reg) \
35         xorl    $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
36 #else
37 # if FUTEX_WAIT == 0
38 #  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
39         movl    %fs:PRIVATE_FUTEX, reg
40 # else
41 #  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
42         movl    %fs:PRIVATE_FUTEX, reg ; \
43         orl     $FUTEX_WAIT, reg
44 # endif
45 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
46         movl    %fs:PRIVATE_FUTEX, reg ; \
47         orl     $FUTEX_WAKE, reg
48 # if FUTEX_WAIT == 0
49 #  define LOAD_FUTEX_WAIT(reg) \
50         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
51         andl    %fs:PRIVATE_FUTEX, reg
52 # else
53 #  define LOAD_FUTEX_WAIT(reg) \
54         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
55         andl    %fs:PRIVATE_FUTEX, reg ; \
56         orl     $FUTEX_WAIT, reg
57 # endif
58 # define LOAD_FUTEX_WAKE(reg) \
59         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
60         andl    %fs:PRIVATE_FUTEX, reg ; \
61         orl     $FUTEX_WAKE, reg
62 #endif
65 /* For the calculation see asm/vsyscall.h.  */
66 #define VSYSCALL_ADDR_vgettimeofday     0xffffffffff600000
69         .globl  __lll_lock_wait_private
70         .type   __lll_lock_wait_private,@function
71         .hidden __lll_lock_wait_private
72         .align  16
73 __lll_lock_wait_private:
74         cfi_startproc
75         pushq   %r10
76         cfi_adjust_cfa_offset(8)
77         pushq   %rdx
78         cfi_adjust_cfa_offset(8)
79         cfi_offset(%r10, -16)
80         cfi_offset(%rdx, -24)
81         xorq    %r10, %r10      /* No timeout.  */
82         movl    $2, %edx
83         LOAD_PRIVATE_FUTEX_WAIT (%esi)
85         cmpl    %edx, %eax      /* NB:   %edx == 2 */
86         jne     2f
88 1:      movl    $SYS_futex, %eax
89         syscall
91 2:      movl    %edx, %eax
92         xchgl   %eax, (%rdi)    /* NB:   lock is implied */
94         testl   %eax, %eax
95         jnz     1b
97         popq    %rdx
98         cfi_adjust_cfa_offset(-8)
99         cfi_restore(%rdx)
100         popq    %r10
101         cfi_adjust_cfa_offset(-8)
102         cfi_restore(%r10)
103         retq
104         cfi_endproc
105         .size   __lll_lock_wait_private,.-__lll_lock_wait_private
107 #ifdef NOT_IN_libc
108         .globl  __lll_lock_wait
109         .type   __lll_lock_wait,@function
110         .hidden __lll_lock_wait
111         .align  16
112 __lll_lock_wait:
113         cfi_startproc
114         pushq   %r10
115         cfi_adjust_cfa_offset(8)
116         pushq   %rdx
117         cfi_adjust_cfa_offset(8)
118         cfi_offset(%r10, -16)
119         cfi_offset(%rdx, -24)
120         xorq    %r10, %r10      /* No timeout.  */
121         movl    $2, %edx
122         LOAD_FUTEX_WAIT (%esi)
124         cmpl    %edx, %eax      /* NB:   %edx == 2 */
125         jne     2f
127 1:      movl    $SYS_futex, %eax
128         syscall
130 2:      movl    %edx, %eax
131         xchgl   %eax, (%rdi)    /* NB:   lock is implied */
133         testl   %eax, %eax
134         jnz     1b
136         popq    %rdx
137         cfi_adjust_cfa_offset(-8)
138         cfi_restore(%rdx)
139         popq    %r10
140         cfi_adjust_cfa_offset(-8)
141         cfi_restore(%r10)
142         retq
143         cfi_endproc
144         .size   __lll_lock_wait,.-__lll_lock_wait
146         .globl  __lll_timedlock_wait
147         .type   __lll_timedlock_wait,@function
148         .hidden __lll_timedlock_wait
149         .align  16
150 __lll_timedlock_wait:
151         cfi_startproc
152         /* Check for a valid timeout value.  */
153         cmpq    $1000000000, 8(%rdx)
154         jae     3f
156         pushq   %r8
157         cfi_adjust_cfa_offset(8)
158         pushq   %r9
159         cfi_adjust_cfa_offset(8)
160         pushq   %r12
161         cfi_adjust_cfa_offset(8)
162         pushq   %r13
163         cfi_adjust_cfa_offset(8)
164         pushq   %r14
165         cfi_adjust_cfa_offset(8)
166         cfi_offset(%r8, -16)
167         cfi_offset(%r9, -24)
168         cfi_offset(%r12, -32)
169         cfi_offset(%r13, -40)
170         cfi_offset(%r14, -48)
171         pushq   %rsi
172         cfi_adjust_cfa_offset(8)
174         /* Stack frame for the timespec and timeval structs.  */
175         subq    $24, %rsp
176         cfi_adjust_cfa_offset(24)
178         movq    %rdi, %r12
179         movq    %rdx, %r13
181         movl    $2, %edx
182         xchgl   %edx, (%r12)
184         testl   %edx, %edx
185         je      6f
188         /* Get current time.  */
189         movq    %rsp, %rdi
190         xorl    %esi, %esi
191         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
192         /* This is a regular function call, all caller-save registers
193            might be clobbered.  */
194         callq   *%rax
196         /* Compute relative timeout.  */
197         movq    8(%rsp), %rax
198         movl    $1000, %edi
199         mul     %rdi            /* Milli seconds to nano seconds.  */
200         movq    (%r13), %rdi
201         movq    8(%r13), %rsi
202         subq    (%rsp), %rdi
203         subq    %rax, %rsi
204         jns     4f
205         addq    $1000000000, %rsi
206         decq    %rdi
207 4:      testq   %rdi, %rdi
208         js      2f              /* Time is already up.  */
210         /* Store relative timeout.  */
211         movq    %rdi, (%rsp)
212         movq    %rsi, 8(%rsp)
214         /* Futex call.  */
215         movl    $2, %edx
216         movl    $1, %eax
217         movq    %rsp, %r10
218         movl    24(%rsp), %esi
219         LOAD_FUTEX_WAIT (%esi)
220         movq    %r12, %rdi
221         movl    $SYS_futex, %eax
222         syscall
224         /* NB: %edx == 2 */
225         xchgl   %edx, (%r12)
227         testl   %edx, %edx
228         je      6f
230         cmpl    $-ETIMEDOUT, %eax
231         jne     1b
232 2:      movl    $ETIMEDOUT, %edx
234 6:      addq    $32, %rsp
235         cfi_adjust_cfa_offset(-32)
236         popq    %r14
237         cfi_adjust_cfa_offset(-8)
238         cfi_restore(%r14)
239         popq    %r13
240         cfi_adjust_cfa_offset(-8)
241         cfi_restore(%r13)
242         popq    %r12
243         cfi_adjust_cfa_offset(-8)
244         cfi_restore(%r12)
245         popq    %r9
246         cfi_adjust_cfa_offset(-8)
247         cfi_restore(%r9)
248         popq    %r8
249         cfi_adjust_cfa_offset(-8)
250         cfi_restore(%r8)
251         movl    %edx, %eax
252         retq
254 3:      movl    $EINVAL, %eax
255         retq
256         cfi_endproc
257         .size   __lll_timedlock_wait,.-__lll_timedlock_wait
258 #endif
261         .globl  __lll_unlock_wake_private
262         .type   __lll_unlock_wake_private,@function
263         .hidden __lll_unlock_wake_private
264         .align  16
265 __lll_unlock_wake_private:
266         cfi_startproc
267         pushq   %rsi
268         cfi_adjust_cfa_offset(8)
269         pushq   %rdx
270         cfi_adjust_cfa_offset(8)
271         cfi_offset(%rsi, -16)
272         cfi_offset(%rdx, -24)
274         movl    $0, (%rdi)
275         LOAD_PRIVATE_FUTEX_WAKE (%esi)
276         movl    $1, %edx        /* Wake one thread.  */
277         movl    $SYS_futex, %eax
278         syscall
280         popq    %rdx
281         cfi_adjust_cfa_offset(-8)
282         cfi_restore(%rdx)
283         popq    %rsi
284         cfi_adjust_cfa_offset(-8)
285         cfi_restore(%rsi)
286         retq
287         cfi_endproc
288         .size   __lll_unlock_wake_private,.-__lll_unlock_wake_private
290 #ifdef NOT_IN_libc
291         .globl  __lll_unlock_wake
292         .type   __lll_unlock_wake,@function
293         .hidden __lll_unlock_wake
294         .align  16
295 __lll_unlock_wake:
296         cfi_startproc
297         pushq   %rsi
298         cfi_adjust_cfa_offset(8)
299         pushq   %rdx
300         cfi_adjust_cfa_offset(8)
301         cfi_offset(%rsi, -16)
302         cfi_offset(%rdx, -24)
304         movl    $0, (%rdi)
305         LOAD_FUTEX_WAKE (%esi)
306         movl    $1, %edx        /* Wake one thread.  */
307         movl    $SYS_futex, %eax
308         syscall
310         popq    %rdx
311         cfi_adjust_cfa_offset(-8)
312         cfi_restore(%rdx)
313         popq    %rsi
314         cfi_adjust_cfa_offset(-8)
315         cfi_restore(%rsi)
316         retq
317         cfi_endproc
318         .size   __lll_unlock_wake,.-__lll_unlock_wake
320         .globl  __lll_timedwait_tid
321         .type   __lll_timedwait_tid,@function
322         .hidden __lll_timedwait_tid
323         .align  16
324 __lll_timedwait_tid:
325         cfi_startproc
326         pushq   %r12
327         cfi_adjust_cfa_offset(8)
328         pushq   %r13
329         cfi_adjust_cfa_offset(8)
330         cfi_offset(%r12, -16)
331         cfi_offset(%r13, -24)
333         movq    %rdi, %r12
334         movq    %rsi, %r13
336         subq    $16, %rsp
337         cfi_adjust_cfa_offset(16)
339         /* Get current time.  */
340 2:      movq    %rsp, %rdi
341         xorl    %esi, %esi
342         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
343         callq   *%rax
345         /* Compute relative timeout.  */
346         movq    8(%rsp), %rax
347         movl    $1000, %edi
348         mul     %rdi            /* Milli seconds to nano seconds.  */
349         movq    (%r13), %rdi
350         movq    8(%r13), %rsi
351         subq    (%rsp), %rdi
352         subq    %rax, %rsi
353         jns     5f
354         addq    $1000000000, %rsi
355         decq    %rdi
356 5:      testq   %rdi, %rdi
357         js      6f              /* Time is already up.  */
359         movq    %rdi, (%rsp)    /* Store relative timeout.  */
360         movq    %rsi, 8(%rsp)
362         movl    (%r12), %edx
363         testl   %edx, %edx
364         jz      4f
366         movq    %rsp, %r10
367         /* XXX The kernel so far uses global futex for the wakeup at
368            all times.  */
369 #if FUTEX_WAIT == 0
370         xorl    %esi, %esi
371 #else
372         movl    $FUTEX_WAIT, %esi
373 #endif
374         movq    %r12, %rdi
375         movl    $SYS_futex, %eax
376         syscall
378         cmpl    $0, (%rdi)
379         jne     1f
380 4:      xorl    %eax, %eax
382 8:      addq    $16, %rsp
383         cfi_adjust_cfa_offset(-16)
384         popq    %r13
385         cfi_adjust_cfa_offset(-8)
386         cfi_restore(%r13)
387         popq    %r12
388         cfi_adjust_cfa_offset(-8)
389         cfi_restore(%r12)
390         retq
392         cfi_adjust_cfa_offset(32)
393 1:      cmpq    $-ETIMEDOUT, %rax
394         jne     2b
396 6:      movl    $ETIMEDOUT, %eax
397         jmp     8b
398         cfi_endproc
399         .size   __lll_timedwait_tid,.-__lll_timedwait_tid
400 #endif