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