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