2.9
[glibc/nacl-glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / i486 / pthread_barrier_wait.S
blob040d7f8c33a8b2dd87edf410d54dc03ba78a40b8
1 /* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
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.
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.
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.  */
20 #include <sysdep.h>
21 #include <lowlevellock.h>
22 #include <lowlevelbarrier.h>
24         .text
26         .globl  pthread_barrier_wait
27         .type   pthread_barrier_wait,@function
28         .align  16
29 pthread_barrier_wait:
30         cfi_startproc
31         pushl   %ebx
32         cfi_adjust_cfa_offset(4)
33         cfi_offset(%ebx, -8)
35         movl    8(%esp), %ebx
37         /* Get the mutex.  */
38         movl    $1, %edx
39         xorl    %eax, %eax
40         LOCK
41         cmpxchgl %edx, MUTEX(%ebx)
42         jnz     1f
44         /* One less waiter.  If this was the last one needed wake
45            everybody.  */
46 2:      subl    $1, LEFT(%ebx)
47         je      3f
49         /* There are more threads to come.  */
50         pushl   %esi
51         cfi_adjust_cfa_offset(4)
52         cfi_offset(%esi, -12)
54 #if CURR_EVENT == 0
55         movl    (%ebx), %edx
56 #else
57         movl    CURR_EVENT(%ebx), %edx
58 #endif
60         /* Release the mutex.  */
61         LOCK
62         subl    $1, MUTEX(%ebx)
63         jne     6f
65         /* Wait for the remaining threads.  The call will return immediately
66            if the CURR_EVENT memory has meanwhile been changed.  */
68 #if FUTEX_WAIT == 0
69         movl    PRIVATE(%ebx), %ecx
70 #else
71         movl    $FUTEX_WAIT, %ecx
72         orl     PRIVATE(%ebx), %ecx
73 #endif
74         xorl    %esi, %esi
75 8:      movl    $SYS_futex, %eax
76         ENTER_KERNEL
78         /* Don't return on spurious wakeups.  The syscall does not change
79            any register except %eax so there is no need to reload any of
80            them.  */
81 #if CURR_EVENT == 0
82         cmpl    %edx, (%ebx)
83 #else
84         cmpl    %edx, CURR_EVENT(%ebx)
85 #endif
86         je      8b
88         /* Increment LEFT.  If this brings the count back to the
89            initial count unlock the object.  */
90         movl    $1, %edx
91         movl    INIT_COUNT(%ebx), %ecx
92         LOCK
93         xaddl   %edx, LEFT(%ebx)
94         subl    $1, %ecx
95         cmpl    %ecx, %edx
96         jne     10f
98         /* Release the mutex.  We cannot release the lock before
99            waking the waiting threads since otherwise a new thread might
100            arrive and gets waken up, too.  */
101         LOCK
102         subl    $1, MUTEX(%ebx)
103         jne     9f
105         /* Note: %esi is still zero.  */
106 10:     movl    %esi, %eax              /* != PTHREAD_BARRIER_SERIAL_THREAD */
108         popl    %esi
109         cfi_adjust_cfa_offset(-4)
110         cfi_restore(%esi)
111         popl    %ebx
112         cfi_adjust_cfa_offset(-4)
113         cfi_restore(%ebx)
114         ret
116         cfi_adjust_cfa_offset(4)
117         cfi_offset(%ebx, -8)
118         
119         /* The necessary number of threads arrived.  */
121 #if CURR_EVENT == 0
122         addl    $1, (%ebx)
123 #else
124         addl    $1, CURR_EVENT(%ebx)
125 #endif
127         /* Wake up all waiters.  The count is a signed number in the kernel
128            so 0x7fffffff is the highest value.  */
129         movl    $0x7fffffff, %edx
130         movl    $FUTEX_WAKE, %ecx
131         orl     PRIVATE(%ebx), %ecx
132         movl    $SYS_futex, %eax
133         ENTER_KERNEL
135         /* Increment LEFT.  If this brings the count back to the
136            initial count unlock the object.  */
137         movl    $1, %edx
138         movl    INIT_COUNT(%ebx), %ecx
139         LOCK
140         xaddl   %edx, LEFT(%ebx)
141         subl    $1, %ecx
142         cmpl    %ecx, %edx
143         jne     5f
145         /* Release the mutex.  We cannot release the lock before
146            waking the waiting threads since otherwise a new thread might
147            arrive and gets waken up, too.  */
148         LOCK
149         subl    $1, MUTEX(%ebx)
150         jne     4f
152 5:      orl     $-1, %eax               /* == PTHREAD_BARRIER_SERIAL_THREAD */
154         popl    %ebx
155         cfi_adjust_cfa_offset(-4)
156         cfi_restore(%ebx)
157         ret
159         cfi_adjust_cfa_offset(4)
160         cfi_offset(%ebx, -8)
161 1:      movl    PRIVATE(%ebx), %ecx
162         leal    MUTEX(%ebx), %edx
163         xorl    $LLL_SHARED, %ecx
164         call    __lll_lock_wait
165         jmp     2b
167 4:      movl    PRIVATE(%ebx), %ecx
168         leal    MUTEX(%ebx), %eax
169         xorl    $LLL_SHARED, %ecx
170         call    __lll_unlock_wake
171         jmp     5b
173         cfi_adjust_cfa_offset(4)
174         cfi_offset(%esi, -12)
175 6:      movl    PRIVATE(%ebx), %ecx
176         leal    MUTEX(%ebx), %eax
177         xorl    $LLL_SHARED, %ecx
178         call    __lll_unlock_wake
179         jmp     7b
181 9:      movl    PRIVATE(%ebx), %ecx
182         leal    MUTEX(%ebx), %eax
183         xorl    $LLL_SHARED, %ecx
184         call    __lll_unlock_wake
185         jmp     10b
186         cfi_endproc
187         .size   pthread_barrier_wait,.-pthread_barrier_wait