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