2.9
[glibc/nacl-glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_barrier_wait.S
blob15ad534fa005a45c7a4339dcdbd697ef3ff254e4
1 /* Copyright (C) 2002, 2003, 2004, 2005, 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>
25         .text
27         .globl  pthread_barrier_wait
28         .type   pthread_barrier_wait,@function
29         .align  16
30 pthread_barrier_wait:
31         /* Get the mutex.  */
32         xorl    %eax, %eax
33         movl    $1, %esi
34         LOCK
35         cmpxchgl %esi, MUTEX(%rdi)
36         jnz     1f
38         /* One less waiter.  If this was the last one needed wake
39            everybody.  */
40 2:      decl    LEFT(%rdi)
41         je      3f
43         /* There are more threads to come.  */
44 #if CURR_EVENT == 0
45         movl    (%rdi), %edx
46 #else
47         movl    CURR_EVENT(%rdi), %edx
48 #endif
50         /* Release the mutex.  */
51         LOCK
52         decl    MUTEX(%rdi)
53         jne     6f
55         /* Wait for the remaining threads.  The call will return immediately
56            if the CURR_EVENT memory has meanwhile been changed.  */
58 #if FUTEX_WAIT == 0
59         movl    PRIVATE(%rdi), %esi
60 #else
61         movl    $FUTEX_WAIT, %esi
62         orl     PRIVATE(%rdi), %esi
63 #endif
64         xorq    %r10, %r10
65 8:      movl    $SYS_futex, %eax
66         syscall
68         /* Don't return on spurious wakeups.  The syscall does not change
69            any register except %eax so there is no need to reload any of
70            them.  */
71 #if CURR_EVENT == 0
72         cmpl    %edx, (%rdi)
73 #else
74         cmpl    %edx, CURR_EVENT(%rdi)
75 #endif
76         je      8b
78         /* Increment LEFT.  If this brings the count back to the
79            initial count unlock the object.  */
80         movl    $1, %edx
81         movl    INIT_COUNT(%rdi), %eax
82         LOCK
83         xaddl   %edx, LEFT(%rdi)
84         subl    $1, %eax
85         cmpl    %eax, %edx
86         jne,pt  10f
88         /* Release the mutex.  We cannot release the lock before
89            waking the waiting threads since otherwise a new thread might
90            arrive and gets waken up, too.  */
91         LOCK
92         decl    MUTEX(%rdi)
93         jne     9f
95 10:     xorl    %eax, %eax              /* != PTHREAD_BARRIER_SERIAL_THREAD */
97         retq
99         /* The necessary number of threads arrived.  */
101 #if CURR_EVENT == 0
102         incl    (%rdi)
103 #else
104         incl    CURR_EVENT(%rdi)
105 #endif
107         /* Wake up all waiters.  The count is a signed number in the kernel
108            so 0x7fffffff is the highest value.  */
109         movl    $0x7fffffff, %edx
110         movl    $FUTEX_WAKE, %esi
111         orl     PRIVATE(%rdi), %esi
112         movl    $SYS_futex, %eax
113         syscall
115         /* Increment LEFT.  If this brings the count back to the
116            initial count unlock the object.  */
117         movl    $1, %edx
118         movl    INIT_COUNT(%rdi), %eax
119         LOCK
120         xaddl   %edx, LEFT(%rdi)
121         subl    $1, %eax
122         cmpl    %eax, %edx
123         jne,pt  5f
125         /* Release the mutex.  We cannot release the lock before
126            waking the waiting threads since otherwise a new thread might
127            arrive and gets waken up, too.  */
128         LOCK
129         decl    MUTEX(%rdi)
130         jne     4f
132 5:      orl     $-1, %eax               /* == PTHREAD_BARRIER_SERIAL_THREAD */
134         retq
136 1:      movl    PRIVATE(%rdi), %esi
137         addq    $MUTEX, %rdi
138         xorl    $LLL_SHARED, %esi
139         callq   __lll_lock_wait
140         subq    $MUTEX, %rdi
141         jmp     2b
143 4:      movl    PRIVATE(%rdi), %esi
144         addq    $MUTEX, %rdi
145         xorl    $LLL_SHARED, %esi
146         callq   __lll_unlock_wake
147         jmp     5b
149 6:      movl    PRIVATE(%rdi), %esi
150         addq    $MUTEX, %rdi
151         xorl    $LLL_SHARED, %esi
152         callq   __lll_unlock_wake
153         subq    $MUTEX, %rdi
154         jmp     7b
156 9:      movl    PRIVATE(%rdi), %esi
157         addq    $MUTEX, %rdi
158         xorl    $LLL_SHARED, %esi
159         callq   __lll_unlock_wake
160         jmp     10b
161         .size   pthread_barrier_wait,.-pthread_barrier_wait