(pthread_barrier_wait): Don't save, load, and restore %esi for last thread.
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_once.S
1 /* Copyright (C) 2002, 2003 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 #ifndef UP
21 # define LOCK lock
22 #else
23 # define LOCK
24 #endif
25
26 #define SYS_futex       202
27 #define FUTEX_WAKE      1
28
29         .comm   __fork_generation, 4, 4
30
31         .text
32
33
34         .globl  __pthread_once
35         .type   __pthread_once,@function
36         .align  16
37 __pthread_once:
38         testl   $2, (%rdi)
39         jz      1f
40         xorl    %eax, %eax
41 0:      ret
42
43 1:      xorq    %rsi, %rsi
44
45         /* Not yet initialized or initialization in progress.
46            Get the fork generation counter now.  */
47 6:      movl    (%rdi), %eax
48
49 5:      movq    %rax, %rdx
50
51         testl   $2, %eax
52         jnz     0b
53
54         andl    $3, %edx
55         orl     __fork_generation(%rip), %edx
56         orl     $1, %edx
57
58         LOCK
59         cmpxchgl %edx, (%rdi)
60         jnz     5b
61
62         /* Check whether another thread already runs the initializer.  */
63         testl   $1, %eax
64         jz      3f      /* No -> do it.  */
65
66         /* Check whether the initializer execution was interrupted
67            by a fork.  */
68         xorl    %edx, %eax
69         testl   $0xfffffffc, %eax
70         jnz     3f      /* Different for generation -> run initializer.  */
71
72         /* Somebody else got here first.  Wait.  */
73         movq    %rsi, %rcx              /* movl $FUTEX_WAIT, %ecx */
74         movl    $SYS_futex, %eax
75         syscall
76         jmp     6b
77
78         /* Preserve the pointer to the control variable.  */
79 3:      pushq   %rdi
80
81         /* Call the initializer function after setting up the
82            cancellation handler.  */
83         subq    $32, %rsp
84
85         /* Push the cleanup handler.  */
86         leaq    clear_once_control(%rip), %rsi
87         movq    %rdi, %rdx
88         movq    %rsp, %rdi
89         call    __pthread_cleanup_push  /* Note: no @PLT.  */
90
91         movq    48(%rsp), %rax
92         call    *%rax
93
94         /* Pop the cleanup handler.  This code depends on the once
95            handler and _pthread_cleanup_push not touch the content
96            of the stack.  Otherwise the first parameter would have
97            to be reloaded.  */
98         xorq    %rdi, %rdi
99         call    __pthread_cleanup_pop   /* Note: no @PLT.  */
100
101         addq    $32, %rsp
102
103         /* Get the control variable address back.  */
104         popq    %rdi
105
106         /* Sucessful run of the initializer.  Signal that we are done.  */
107         LOCK
108         incl    (%rdi)
109
110         /* Wake up all other threads.  */
111         movl    $0x7fffffff, %edx
112         movl    $FUTEX_WAKE, %esi
113         xorq    %rcx, %rcx
114         movl    $SYS_futex, %eax
115         syscall
116
117 4:      xorq    %rax, %rax
118         ret
119
120         .size   __pthread_once,.-__pthread_once
121
122         .globl  pthread_once
123 pthread_once = __pthread_once
124
125
126         .type   clear_once_control,@function
127         .align  16
128 clear_once_control:
129         movl    $0, (%rdi)
130
131         xorq    %rcx, %rcx
132         movl    $0x7fffffff, %edx
133         movl    $FUTEX_WAKE, %esi
134         movl    $SYS_futex, %eax
135         syscall
136
137         ret
138         .size   clear_once_control,.-clear_once_control