OSDN Git Service

ff3197ba0564841245f17d9f87c9c78bd7c3aa2d
[uclinux-h8/uClibc.git] / libpthread / nptl / sysdeps / unix / sysv / linux / sh / pthread_barrier_wait.S
1 /* Copyright (C) 2003, 2004 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 <lowlevelbarrier.h>
21 #include "lowlevel-atomic.h"
22
23 #define FUTEX_WAIT      0
24 #define FUTEX_WAKE      1
25
26
27         .text
28
29         .globl  pthread_barrier_wait
30         .type   pthread_barrier_wait,@function
31         .align  5
32 pthread_barrier_wait:
33         mov.l   r9, @-r15
34         mov.l   r8, @-r15
35         sts.l   pr, @-r15
36         mov     r4, r8
37
38         /* Get the mutex.  */
39         mov     #0, r3
40         mov     #1, r4
41         CMPXCHG (r3, @(MUTEX,r8), r4, r2)
42         bf      1f
43
44         /* One less waiter.  If this was the last one needed wake
45            everybody.  */
46 2:
47         mov.l   @(LEFT,r8), r0
48         add     #-1, r0
49         mov.l   r0, @(LEFT,r8)
50         tst     r0, r0
51         bt      3f
52
53         /* There are more threads to come.  */
54         mov.l   @(CURR_EVENT,r8), r6
55
56         /* Release the mutex.  */
57         DEC (@(MUTEX,r8), r2)
58         tst     r2, r2
59         bf      6f
60 7:
61         /* Wait for the remaining threads.  The call will return immediately
62            if the CURR_EVENT memory has meanwhile been changed.  */
63         mov     r8, r4
64 #if CURR_EVENT != 0
65         add     #CURR_EVENT, r4
66 #endif
67         mov     #FUTEX_WAIT, r5
68         mov     #0, r7
69 8:
70         mov     #SYS_futex, r3
71         extu.b  r3, r3
72         trapa   #0x14
73         SYSCALL_INST_PAD
74
75         /* Don't return on spurious wakeups.  The syscall does not change
76            any register except r0 so there is no need to reload any of
77            them.  */
78         mov.l   @(CURR_EVENT,r8), r0
79         cmp/eq  r0, r6
80         bt      8b
81
82         /* Increment LEFT.  If this brings the count back to the
83            initial count unlock the object.  */
84         INC     (@(LEFT,r8), r2)
85         mov.l   @(INIT_COUNT,r8), r4
86         cmp/eq  r2, r4
87         bf      10f
88
89         /* Release the mutex.  We cannot release the lock before
90            waking the waiting threads since otherwise a new thread might
91            arrive and gets waken up, too.  */
92         DEC (@(MUTEX,r8), r2)
93         tst     r2, r2
94         bf      9f
95
96 10:
97         mov     #0, r0          /* != PTHREAD_BARRIER_SERIAL_THREAD */
98         lds.l   @r15+, pr
99         mov.l   @r15+, r8
100         rts
101          mov.l  @r15+, r9
102
103 3:
104         /* The necessary number of threads arrived.  */
105         mov.l   @(CURR_EVENT,r8), r1
106         add     #1, r1
107         mov.l   r1, @(CURR_EVENT,r8)
108
109         /* Wake up all waiters.  The count is a signed number in the kernel
110            so 0x7fffffff is the highest value.  */
111         mov.l   .Lall, r6
112         mov     r8, r4
113 #if CURR_EVENT != 0
114         add     #CURR_EVENT, r4
115 #endif
116         mov     #0, r7
117         mov     #FUTEX_WAKE, r5
118         mov     #SYS_futex, r3
119         extu.b  r3, r3
120         trapa   #0x14
121         SYSCALL_INST_PAD
122
123         /* Increment LEFT.  If this brings the count back to the
124            initial count unlock the object.  */
125         INC     (@(LEFT,r8), r2)
126         mov.l   @(INIT_COUNT,r8), r4
127         cmp/eq  r2, r4
128         bf      5f
129
130         /* Release the mutex.  */
131         DEC (@(MUTEX,r8), r2)
132         tst     r2, r2
133         bf      4f
134 5:
135         mov     #-1, r0         /* == PTHREAD_BARRIER_SERIAL_THREAD */
136         lds.l   @r15+, pr
137         mov.l   @r15+, r8
138         rts
139          mov.l  @r15+, r9
140
141 1:
142         mov     r2, r4
143         mov     r8, r5
144         mov.l   .Lwait0, r1
145         bsrf    r1
146          add    #MUTEX, r5
147 .Lwait0b:
148         bra     2b
149          nop
150
151 4:
152         mov     r8, r4
153         mov.l   .Lwake0, r1
154         bsrf    r1
155          add    #MUTEX, r4
156 .Lwake0b:
157         bra     5b
158          nop
159
160 6:
161         mov     r6, r9
162         mov     r8, r4
163         mov.l   .Lwake1, r1
164         bsrf    r1
165          add    #MUTEX, r4
166 .Lwake1b:
167         bra     7b
168          mov    r9, r6
169
170 9:      
171         mov     r6, r9
172         mov     r8, r4
173         mov.l   .Lwake2, r1
174         bsrf    r1
175          add    #MUTEX, r4
176 .Lwake2b:
177         bra     10b
178          mov    r9, r6
179
180         .align  2
181 .Lall:
182         .long   0x7fffffff
183 .Lwait0:
184         .long   __lll_mutex_lock_wait-.Lwait0b
185 .Lwake0:
186         .long   __lll_mutex_unlock_wake-.Lwake0b
187 .Lwake1:
188         .long   __lll_mutex_unlock_wake-.Lwake1b
189 .Lwake2:
190         .long   __lll_mutex_unlock_wake-.Lwake2b
191         .size   pthread_barrier_wait,.-pthread_barrier_wait