pthread_once implementation on Linux/SH.
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / sh / pthread_once.S
1 /* Copyright (C) 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <sysdep.h>
20 #include "lowlevel-atomic.h"
21
22 #define SYS_futex       240
23 #define FUTEX_WAIT      0
24 #define FUTEX_WAKE      1
25
26         .comm   __fork_generation, 4, 4
27
28         .text
29         .globl  __pthread_once
30         .type   __pthread_once,@function
31         .align  5
32 __pthread_once:
33         mov.l   @r4, r0
34         tst     #2, r0
35         bt      1f
36         rts
37          mov    #0, r0
38
39 1:
40         mov.l   r12, @-r15
41         mov.l   r9, @-r15
42         mov.l   r8, @-r15
43         sts.l   pr, @-r15
44         mov     r5, r8
45
46         /* Not yet initialized or initialization in progress.
47            Get the fork generation counter now.  */
48 6:
49         mov.l   @r4, r1
50 #ifdef PIC
51         mova    .Lgot, r0
52         mov.l   .Lgot, r12
53         add     r0, r12
54 #endif
55
56 5:
57         mov     r1, r0
58
59         tst     #2, r0
60         bf      4f
61
62         and     #3, r0
63         mov.l   .Lfgen, r2
64 #ifdef PIC
65         add     r12, r2
66 #endif
67         mov.l   @r2, r3
68         or      r3, r0  
69         or      #1, r0
70         mov     r0, r3
71         mov     r1, r5
72
73         CMPXCHG (r5, @r4, r3, r2)
74         bf      5b
75
76         /* Check whether another thread already runs the initializer.  */
77         mov     r2, r0
78         tst     #1, r0
79         bt      3f      /* No -> do it.  */
80
81         /* Check whether the initializer execution was interrupted
82            by a fork.  */
83         xor     r3, r0
84         mov     #-4, r1 /* -4 = 0xfffffffc */
85         tst     r1, r0
86         bf      3f      /* Different for generation -> run initializer.  */
87
88         /* Somebody else got here first.  Wait.  */
89         mov     #FUTEX_WAIT, r5
90         mov     r3, r6
91         mov     #0, r7
92         mov     #SYS_futex, r3
93         extu.b  r3, r3
94         trapa   #0x14
95         SYSCALL_INST_PAD
96         bra     6b
97          nop
98
99         .align  2
100 #ifdef PIC
101 .Lgot:
102         .long   _GLOBAL_OFFSET_TABLE_
103 .Lfgen: 
104         .long   __fork_generation@GOTOFF
105 #else
106 .Lfgen: 
107         .long   __fork_generation
108 #endif
109
110 3:
111         /* Call the initializer function after setting up the
112            cancellation handler.  */
113         /* Allocate a _pthread_cleanup_buffer on stack.  */
114         add     #-16, r15
115
116         /* Push the cleanup handler.  */
117         mov     r4, r9
118         mov     r15, r4
119         mov.l   .Lconce, r5
120 #ifdef PIC
121         add     r12, r5
122 #endif
123         mov.l   .Lcpush, r1
124         bsrf    r1
125          mov    r3, r6
126 .Lcpush0:
127         jsr     @r8
128          nop
129
130         /* Pop the cleanup handler.  */
131         mov     r15, r4
132         mov.l   .Lcpop, r1
133         bsrf    r1
134          mov    #0, r5
135 .Lcpop0:
136         add     #16, r15
137
138         /* Sucessful run of the initializer.  Signal that we are done.  */
139         INC (@r9, r2)
140         /* Wake up all other threads.  */
141         mov     r9, r4
142         mov     #FUTEX_WAKE, r5
143         mov     #-1, r6
144         shlr    r6              /* r6 = 0x7fffffff */
145         mov     #0, r7
146         mov     #SYS_futex, r3
147         extu.b  r3, r3
148         trapa   #0x14
149         SYSCALL_INST_PAD
150
151 4:
152         lds.l   @r15+, pr
153         mov.l   @r15+, r8
154         mov.l   @r15+, r9
155         mov.l   @r15+, r12
156         rts
157          mov    #0, r0
158
159         .align  2
160 .Lconce:
161 #ifdef PIC
162         .long   clear_once_control@GOTOFF
163 #else
164         .long   clear_once_control
165 #endif
166 .Lcpush:
167         .long   __pthread_cleanup_push - .Lcpush0       /* Note: no @PLT.  */
168 .Lcpop:
169         .long   __pthread_cleanup_pop - .Lcpop0         /* Note: no @PLT.  */
170
171         .size   __pthread_once,.-__pthread_once
172
173         .globl  __pthread_once_internal
174 __pthread_once_internal = __pthread_once
175
176         .globl  pthread_once
177 pthread_once = __pthread_once
178
179
180         .type   clear_once_control,@function
181         .align  5
182 clear_once_control:
183         mov     #0, r0
184         mov.l   r0, @r4
185
186         mov     #FUTEX_WAKE, r5
187         mov     #-1, r6
188         shlr    r6              /* r6 = 0x7fffffff */
189         mov     #0, r7
190         mov     #SYS_futex, r3
191         extu.b  r3, r3
192         trapa   #0x14
193         SYSCALL_INST_PAD
194
195         rts
196          nop
197         .size   clear_once_control,.-clear_once_control