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