At comment about lock position.
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / 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 #include <sysdep.h>
21
22 #ifndef UP
23 # define LOCK lock
24 #else
25 # define LOCK
26 #endif
27
28 #define SYS_futex       240
29 #define FUTEX_WAKE      1
30
31         .comm   __fork_generation, 4, 4
32
33         .text
34
35
36         .globl  __pthread_once
37         .type   __pthread_once,@function
38         .align  16
39 __pthread_once:
40         movl    4(%esp), %ecx
41         testl   $2, (%ecx)
42         jz      1f
43         xorl    %eax, %eax
44         ret
45
46 1:      pushl   %ebx
47         pushl   %esi
48         movl    %ecx, %ebx
49         xorl    %esi, %esi
50
51         /* Not yet initialized or initialization in progress.
52            Get the fork generation counter now.  */
53 6:      movl    (%ebx), %eax
54 #ifdef PIC
55         call    __i686.get_pc_thunk.cx
56         addl    $_GLOBAL_OFFSET_TABLE_, %ecx
57 #endif
58
59 5:      movl    %eax, %edx
60
61         testl   $2, %eax
62         jnz     4f
63
64         andl    $3, %edx
65 #ifdef PIC
66         orl     __fork_generation@GOTOFF(%ecx), %edx
67 #else
68         orl     __fork_generation, %edx
69 #endif
70         orl     $1, %edx
71
72         LOCK
73         cmpxchgl %edx, (%ebx)
74         jnz     5b
75
76         /* Check whether another thread already runs the initializer.  */
77         testl   $1, %eax
78         jz      3f      /* No -> do it.  */
79
80         /* Check whether the initializer execution was interrupted
81            by a fork.  */
82         xorl    %edx, %eax
83         testl   $0xfffffffc, %eax
84         jnz     3f      /* Different for generation -> run initializer.  */
85
86         /* Somebody else got here first.  Wait.  */
87         movl    %esi, %ecx              /* movl $FUTEX_WAIT, %ecx */
88         movl    $SYS_futex, %eax
89         ENTER_KERNEL
90         jmp     6b
91
92 3:      /* Call the initializer function after setting up the
93            cancellation handler.  */
94         subl    $16, %esp
95
96         /* Push the cleanup handler.  */
97 #ifdef PIC
98         leal    clear_once_control@GOTOFF(%ecx), %eax
99 #else
100         leal    clear_once_control, %eax
101 #endif
102         movl    %esp, %edx
103         pushl   %ebx
104         pushl   %eax
105         pushl   %edx
106         call    __pthread_cleanup_push  /* Note: no @PLT.  */
107
108         movl    44(%esp), %eax
109         call    *%eax
110
111         /* Pop the cleanup handler.  This code depends on the once
112            handler and _pthread_cleanup_push not touch the content
113            of the stack.  Otherwise the first parameter would have
114            to be reloaded.  */
115         movl    $0, 4(%esp)
116         call    __pthread_cleanup_pop   /* Note: no @PLT.  */
117
118         addl    $28, %esp
119
120         /* Sucessful run of the initializer.  Signal that we are done.  */
121         LOCK
122         incl    (%ebx)
123
124         /* Wake up all other threads.  */
125         movl    $0x7fffffff, %edx
126         movl    $FUTEX_WAKE, %ecx
127         movl    $SYS_futex, %eax
128         ENTER_KERNEL
129
130 4:      popl    %esi
131         popl    %ebx
132         xorl    %eax, %eax
133         ret
134
135         .size   __pthread_once,.-__pthread_once
136
137         .globl  __pthread_once_internal
138 __pthread_once_internal = __pthread_once
139
140         .globl  pthread_once
141 pthread_once = __pthread_once
142
143
144         .type   clear_once_control,@function
145         .align  16
146 clear_once_control:
147         pushl   %esi
148         pushl   %ebx
149
150         movl    12(%esp), %ebx
151         movl    $0, (%ebx)
152
153         xorl    %esi, %esi
154         movl    $0x7fffffff, %edx
155         movl    $FUTEX_WAKE, %ecx
156         movl    $SYS_futex, %eax
157         ENTER_KERNEL
158
159         popl    %ebx
160         popl    %esi
161         ret
162         .size   clear_once_control,.-clear_once_control
163
164
165 #ifdef PIC
166         .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
167         .globl  __i686.get_pc_thunk.cx
168         .hidden __i686.get_pc_thunk.cx
169         .type   __i686.get_pc_thunk.cx,@function
170 __i686.get_pc_thunk.cx:
171         movl (%esp), %ecx;
172         ret
173         .size   __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
174 #endif