chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_once.S
1 /* Copyright (C) 2002, 2003, 2005, 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.
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 <kernel-features.h>
22 #include <tcb-offsets.h>
23 #include <lowlevellock.h>
24
25
26         .comm   __fork_generation, 4, 4
27
28         .text
29
30
31         .globl  __pthread_once
32         .type   __pthread_once,@function
33         .align  16
34 __pthread_once:
35 .LSTARTCODE:
36         cfi_startproc
37 #ifdef SHARED
38         cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
39                         DW.ref.__gcc_personality_v0)
40         cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
41 #else
42         cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
43         cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
44 #endif
45         testl   $2, (%rdi)
46         jz      1f
47         xorl    %eax, %eax
48         retq
49
50         /* Preserve the function pointer.  */
51 1:      pushq   %rsi
52         cfi_adjust_cfa_offset(8)
53         xorq    %r10, %r10
54
55         /* Not yet initialized or initialization in progress.
56            Get the fork generation counter now.  */
57 6:      movl    (%rdi), %eax
58
59 5:      movl    %eax, %edx
60
61         testl   $2, %eax
62         jnz     4f
63
64         andl    $3, %edx
65         orl     __fork_generation(%rip), %edx
66         orl     $1, %edx
67
68         LOCK
69         cmpxchgl %edx, (%rdi)
70         jnz     5b
71
72         /* Check whether another thread already runs the initializer.  */
73         testl   $1, %eax
74         jz      3f      /* No -> do it.  */
75
76         /* Check whether the initializer execution was interrupted
77            by a fork.  */
78         xorl    %edx, %eax
79         testl   $0xfffffffc, %eax
80         jnz     3f      /* Different for generation -> run initializer.  */
81
82         /* Somebody else got here first.  Wait.  */
83 #ifdef __ASSUME_PRIVATE_FUTEX
84         movl    $FUTEX_WAIT|FUTEX_PRIVATE_FLAG, %esi
85 #else
86 # if FUTEX_WAIT == 0
87         movl    %fs:PRIVATE_FUTEX, %esi
88 # else
89         movl    $FUTEX_WAIT, %esi
90         orl     %fs:PRIVATE_FUTEX, %esi
91 # endif
92 #endif
93         movl    $SYS_futex, %eax
94         syscall
95         jmp     6b
96
97         /* Preserve the pointer to the control variable.  */
98 3:      pushq   %rdi
99         cfi_adjust_cfa_offset(8)
100         pushq   %rdi
101         cfi_adjust_cfa_offset(8)
102
103 .LcleanupSTART:
104         callq   *16(%rsp)
105 .LcleanupEND:
106
107         /* Get the control variable address back.  */
108         popq    %rdi
109         cfi_adjust_cfa_offset(-8)
110
111         /* Sucessful run of the initializer.  Signal that we are done.  */
112         LOCK
113         incl    (%rdi)
114
115         addq    $8, %rsp
116         cfi_adjust_cfa_offset(-8)
117
118         /* Wake up all other threads.  */
119         movl    $0x7fffffff, %edx
120 #ifdef __ASSUME_PRIVATE_FUTEX
121         movl    $FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %esi
122 #else
123         movl    $FUTEX_WAKE, %esi
124         orl     %fs:PRIVATE_FUTEX, %esi
125 #endif
126         movl    $SYS_futex, %eax
127         syscall
128
129 4:      addq    $8, %rsp
130         cfi_adjust_cfa_offset(-8)
131         xorl    %eax, %eax
132         retq
133         .size   __pthread_once,.-__pthread_once
134
135
136         .globl  __pthread_once_internal
137 __pthread_once_internal = __pthread_once
138
139         .globl  pthread_once
140 pthread_once = __pthread_once
141
142
143         .type   clear_once_control,@function
144         .align  16
145 clear_once_control:
146         cfi_adjust_cfa_offset(3 * 8)
147         movq    (%rsp), %rdi
148         movq    %rax, %r8
149         movl    $0, (%rdi)
150
151         movl    $0x7fffffff, %edx
152 #ifdef __ASSUME_PRIVATE_FUTEX
153         movl    $FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %esi
154 #else
155         movl    $FUTEX_WAKE, %esi
156         orl     %fs:PRIVATE_FUTEX, %esi
157 #endif
158         movl    $SYS_futex, %eax
159         syscall
160
161         movq    %r8, %rdi
162 .LcallUR:
163         call    _Unwind_Resume@PLT
164         hlt
165 .LENDCODE:
166         cfi_endproc
167         .size   clear_once_control,.-clear_once_control
168
169
170         .section .gcc_except_table,"a",@progbits
171 .LexceptSTART:
172         .byte   DW_EH_PE_omit                   # @LPStart format
173         .byte   DW_EH_PE_omit                   # @TType format
174         .byte   DW_EH_PE_uleb128                # call-site format
175         .uleb128 .Lcstend-.Lcstbegin
176 .Lcstbegin:
177         .uleb128 .LcleanupSTART-.LSTARTCODE
178         .uleb128 .LcleanupEND-.LcleanupSTART
179         .uleb128 clear_once_control-.LSTARTCODE
180         .uleb128  0
181         .uleb128 .LcallUR-.LSTARTCODE
182         .uleb128 .LENDCODE-.LcallUR
183         .uleb128 0
184         .uleb128  0
185 .Lcstend:
186
187
188 #ifdef SHARED
189         .hidden DW.ref.__gcc_personality_v0
190         .weak   DW.ref.__gcc_personality_v0
191         .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
192         .align  8
193         .type   DW.ref.__gcc_personality_v0, @object
194         .size   DW.ref.__gcc_personality_v0, 8
195 DW.ref.__gcc_personality_v0:
196         .quad   __gcc_personality_v0
197 #endif