* init.c (__pthread_initialize_minimal_internal): Check for
[glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / lowlevellock.S
blob72c3858238689e178fd9c235db955d917b50990a
1 /* Copyright (C) 2002-2006, 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 <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_WAIT_ABS(reg) \
35         xorl    $(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg
36 # define LOAD_FUTEX_WAKE(reg) \
37         xorl    $(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg
38 #else
39 # if FUTEX_WAIT == 0
40 #  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
41         movl    %fs:PRIVATE_FUTEX, reg
42 # else
43 #  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
44         movl    %fs:PRIVATE_FUTEX, reg ; \
45         orl     $FUTEX_WAIT, reg
46 # endif
47 # define LOAD_PRIVATE_FUTEX_WAKE(reg) \
48         movl    %fs:PRIVATE_FUTEX, reg ; \
49         orl     $FUTEX_WAKE, reg
50 # if FUTEX_WAIT == 0
51 #  define LOAD_FUTEX_WAIT(reg) \
52         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
53         andl    %fs:PRIVATE_FUTEX, reg
54 # else
55 #  define LOAD_FUTEX_WAIT(reg) \
56         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
57         andl    %fs:PRIVATE_FUTEX, reg ; \
58         orl     $FUTEX_WAIT, reg
59 # endif
60 # define LOAD_FUTEX_WAIT_ABS(reg) \
61         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
62         andl    %fs:PRIVATE_FUTEX, reg ; \
63         orl     $FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg
64 # define LOAD_FUTEX_WAKE(reg) \
65         xorl    $FUTEX_PRIVATE_FLAG, reg ; \
66         andl    %fs:PRIVATE_FUTEX, reg ; \
67         orl     $FUTEX_WAKE, reg
68 #endif
71 /* For the calculation see asm/vsyscall.h.  */
72 #define VSYSCALL_ADDR_vgettimeofday     0xffffffffff600000
75         .globl  __lll_lock_wait_private
76         .type   __lll_lock_wait_private,@function
77         .hidden __lll_lock_wait_private
78         .align  16
79 __lll_lock_wait_private:
80         cfi_startproc
81         pushq   %r10
82         cfi_adjust_cfa_offset(8)
83         pushq   %rdx
84         cfi_adjust_cfa_offset(8)
85         cfi_offset(%r10, -16)
86         cfi_offset(%rdx, -24)
87         xorq    %r10, %r10      /* No timeout.  */
88         movl    $2, %edx
89         LOAD_PRIVATE_FUTEX_WAIT (%esi)
91         cmpl    %edx, %eax      /* NB:   %edx == 2 */
92         jne     2f
94 1:      movl    $SYS_futex, %eax
95         syscall
97 2:      movl    %edx, %eax
98         xchgl   %eax, (%rdi)    /* NB:   lock is implied */
100         testl   %eax, %eax
101         jnz     1b
103         popq    %rdx
104         cfi_adjust_cfa_offset(-8)
105         cfi_restore(%rdx)
106         popq    %r10
107         cfi_adjust_cfa_offset(-8)
108         cfi_restore(%r10)
109         retq
110         cfi_endproc
111         .size   __lll_lock_wait_private,.-__lll_lock_wait_private
113 #ifdef NOT_IN_libc
114         .globl  __lll_lock_wait
115         .type   __lll_lock_wait,@function
116         .hidden __lll_lock_wait
117         .align  16
118 __lll_lock_wait:
119         cfi_startproc
120         pushq   %r10
121         cfi_adjust_cfa_offset(8)
122         pushq   %rdx
123         cfi_adjust_cfa_offset(8)
124         cfi_offset(%r10, -16)
125         cfi_offset(%rdx, -24)
126         xorq    %r10, %r10      /* No timeout.  */
127         movl    $2, %edx
128         LOAD_FUTEX_WAIT (%esi)
130         cmpl    %edx, %eax      /* NB:   %edx == 2 */
131         jne     2f
133 1:      movl    $SYS_futex, %eax
134         syscall
136 2:      movl    %edx, %eax
137         xchgl   %eax, (%rdi)    /* NB:   lock is implied */
139         testl   %eax, %eax
140         jnz     1b
142         popq    %rdx
143         cfi_adjust_cfa_offset(-8)
144         cfi_restore(%rdx)
145         popq    %r10
146         cfi_adjust_cfa_offset(-8)
147         cfi_restore(%r10)
148         retq
149         cfi_endproc
150         .size   __lll_lock_wait,.-__lll_lock_wait
152         /*      %rdi: futex
153                 %rsi: flags
154                 %rdx: timeout
155                 %eax: futex value
156         */
157         .globl  __lll_timedlock_wait
158         .type   __lll_timedlock_wait,@function
159         .hidden __lll_timedlock_wait
160         .align  16
161 __lll_timedlock_wait:
162         cfi_startproc
163 # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
164 #  ifdef PIC
165         cmpl    $0, __have_futex_clock_realtime(%rip)
166 #  else
167         cmpl    $0, __have_futex_clock_realtime
168 #  endif
169         je      .Lreltmo
170 # endif
172         pushq   %r9
173         cfi_adjust_cfa_offset(9)
174         cfi_offset(%r9, -16)
175         movq    %rdx, %r10
176         movl    $0xffffffff, %r9d
177         LOAD_FUTEX_WAIT_ABS (%esi)
179         movl    $2, %edx
180         cmpl    %edx, %eax
181         jne     2f
183 1:      movl    $SYS_futex, %eax
184         movl    $2, %edx
185         syscall
187 2:      xchgl   %edx, (%rdi)    /* NB:   lock is implied */
189         testl   %edx, %edx
190         jz      3f
192         cmpl    $-ETIMEDOUT, %eax
193         je      4f
194         cmpl    $-EINVAL, %eax
195         jne     1b
196 4:      movl    %eax, %edx
197         negl    %edx
199 3:      movl    %edx, %eax
200         popq    %r9
201         cfi_adjust_cfa_offset(-8)
202         cfi_restore(%r9)
203         retq
205 # ifndef __ASSUME_FUTEX_CLOCK_REALTIME
206 .Lreltmo:
207         /* Check for a valid timeout value.  */
208         cmpq    $1000000000, 8(%rdx)
209         jae     3f
211         pushq   %r8
212         cfi_adjust_cfa_offset(8)
213         pushq   %r9
214         cfi_adjust_cfa_offset(8)
215         pushq   %r12
216         cfi_adjust_cfa_offset(8)
217         pushq   %r13
218         cfi_adjust_cfa_offset(8)
219         pushq   %r14
220         cfi_adjust_cfa_offset(8)
221         cfi_offset(%r8, -16)
222         cfi_offset(%r9, -24)
223         cfi_offset(%r12, -32)
224         cfi_offset(%r13, -40)
225         cfi_offset(%r14, -48)
226         pushq   %rsi
227         cfi_adjust_cfa_offset(8)
229         /* Stack frame for the timespec and timeval structs.  */
230         subq    $24, %rsp
231         cfi_adjust_cfa_offset(24)
233         movq    %rdi, %r12
234         movq    %rdx, %r13
236         movl    $2, %edx
237         xchgl   %edx, (%r12)
239         testl   %edx, %edx
240         je      6f
243         /* Get current time.  */
244         movq    %rsp, %rdi
245         xorl    %esi, %esi
246         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
247         /* This is a regular function call, all caller-save registers
248            might be clobbered.  */
249         callq   *%rax
251         /* Compute relative timeout.  */
252         movq    8(%rsp), %rax
253         movl    $1000, %edi
254         mul     %rdi            /* Milli seconds to nano seconds.  */
255         movq    (%r13), %rdi
256         movq    8(%r13), %rsi
257         subq    (%rsp), %rdi
258         subq    %rax, %rsi
259         jns     4f
260         addq    $1000000000, %rsi
261         decq    %rdi
262 4:      testq   %rdi, %rdi
263         js      2f              /* Time is already up.  */
265         /* Store relative timeout.  */
266         movq    %rdi, (%rsp)
267         movq    %rsi, 8(%rsp)
269         /* Futex call.  */
270         movl    $2, %edx
271         movl    $1, %eax
272         movq    %rsp, %r10
273         movl    24(%rsp), %esi
274         LOAD_FUTEX_WAIT (%esi)
275         movq    %r12, %rdi
276         movl    $SYS_futex, %eax
277         syscall
279         /* NB: %edx == 2 */
280         xchgl   %edx, (%r12)
282         testl   %edx, %edx
283         je      6f
285         cmpl    $-ETIMEDOUT, %eax
286         jne     1b
287 2:      movl    $ETIMEDOUT, %edx
289 6:      addq    $32, %rsp
290         cfi_adjust_cfa_offset(-32)
291         popq    %r14
292         cfi_adjust_cfa_offset(-8)
293         cfi_restore(%r14)
294         popq    %r13
295         cfi_adjust_cfa_offset(-8)
296         cfi_restore(%r13)
297         popq    %r12
298         cfi_adjust_cfa_offset(-8)
299         cfi_restore(%r12)
300         popq    %r9
301         cfi_adjust_cfa_offset(-8)
302         cfi_restore(%r9)
303         popq    %r8
304         cfi_adjust_cfa_offset(-8)
305         cfi_restore(%r8)
306         movl    %edx, %eax
307         retq
309 3:      movl    $EINVAL, %eax
310         retq
311 # endif
312         cfi_endproc
313         .size   __lll_timedlock_wait,.-__lll_timedlock_wait
314 #endif
317         .globl  __lll_unlock_wake_private
318         .type   __lll_unlock_wake_private,@function
319         .hidden __lll_unlock_wake_private
320         .align  16
321 __lll_unlock_wake_private:
322         cfi_startproc
323         pushq   %rsi
324         cfi_adjust_cfa_offset(8)
325         pushq   %rdx
326         cfi_adjust_cfa_offset(8)
327         cfi_offset(%rsi, -16)
328         cfi_offset(%rdx, -24)
330         movl    $0, (%rdi)
331         LOAD_PRIVATE_FUTEX_WAKE (%esi)
332         movl    $1, %edx        /* Wake one thread.  */
333         movl    $SYS_futex, %eax
334         syscall
336         popq    %rdx
337         cfi_adjust_cfa_offset(-8)
338         cfi_restore(%rdx)
339         popq    %rsi
340         cfi_adjust_cfa_offset(-8)
341         cfi_restore(%rsi)
342         retq
343         cfi_endproc
344         .size   __lll_unlock_wake_private,.-__lll_unlock_wake_private
346 #ifdef NOT_IN_libc
347         .globl  __lll_unlock_wake
348         .type   __lll_unlock_wake,@function
349         .hidden __lll_unlock_wake
350         .align  16
351 __lll_unlock_wake:
352         cfi_startproc
353         pushq   %rsi
354         cfi_adjust_cfa_offset(8)
355         pushq   %rdx
356         cfi_adjust_cfa_offset(8)
357         cfi_offset(%rsi, -16)
358         cfi_offset(%rdx, -24)
360         movl    $0, (%rdi)
361         LOAD_FUTEX_WAKE (%esi)
362         movl    $1, %edx        /* Wake one thread.  */
363         movl    $SYS_futex, %eax
364         syscall
366         popq    %rdx
367         cfi_adjust_cfa_offset(-8)
368         cfi_restore(%rdx)
369         popq    %rsi
370         cfi_adjust_cfa_offset(-8)
371         cfi_restore(%rsi)
372         retq
373         cfi_endproc
374         .size   __lll_unlock_wake,.-__lll_unlock_wake
376         .globl  __lll_timedwait_tid
377         .type   __lll_timedwait_tid,@function
378         .hidden __lll_timedwait_tid
379         .align  16
380 __lll_timedwait_tid:
381         cfi_startproc
382         pushq   %r12
383         cfi_adjust_cfa_offset(8)
384         pushq   %r13
385         cfi_adjust_cfa_offset(8)
386         cfi_offset(%r12, -16)
387         cfi_offset(%r13, -24)
389         movq    %rdi, %r12
390         movq    %rsi, %r13
392         subq    $16, %rsp
393         cfi_adjust_cfa_offset(16)
395         /* Get current time.  */
396 2:      movq    %rsp, %rdi
397         xorl    %esi, %esi
398         movq    $VSYSCALL_ADDR_vgettimeofday, %rax
399         callq   *%rax
401         /* Compute relative timeout.  */
402         movq    8(%rsp), %rax
403         movl    $1000, %edi
404         mul     %rdi            /* Milli seconds to nano seconds.  */
405         movq    (%r13), %rdi
406         movq    8(%r13), %rsi
407         subq    (%rsp), %rdi
408         subq    %rax, %rsi
409         jns     5f
410         addq    $1000000000, %rsi
411         decq    %rdi
412 5:      testq   %rdi, %rdi
413         js      6f              /* Time is already up.  */
415         movq    %rdi, (%rsp)    /* Store relative timeout.  */
416         movq    %rsi, 8(%rsp)
418         movl    (%r12), %edx
419         testl   %edx, %edx
420         jz      4f
422         movq    %rsp, %r10
423         /* XXX The kernel so far uses global futex for the wakeup at
424            all times.  */
425 #if FUTEX_WAIT == 0
426         xorl    %esi, %esi
427 #else
428         movl    $FUTEX_WAIT, %esi
429 #endif
430         movq    %r12, %rdi
431         movl    $SYS_futex, %eax
432         syscall
434         cmpl    $0, (%rdi)
435         jne     1f
436 4:      xorl    %eax, %eax
438 8:      addq    $16, %rsp
439         cfi_adjust_cfa_offset(-16)
440         popq    %r13
441         cfi_adjust_cfa_offset(-8)
442         cfi_restore(%r13)
443         popq    %r12
444         cfi_adjust_cfa_offset(-8)
445         cfi_restore(%r12)
446         retq
448         cfi_adjust_cfa_offset(32)
449 1:      cmpq    $-ETIMEDOUT, %rax
450         jne     2b
452 6:      movl    $ETIMEDOUT, %eax
453         jmp     8b
454         cfi_endproc
455         .size   __lll_timedwait_tid,.-__lll_timedwait_tid
456 #endif