776c47f6cc557c914cacac1dad407c1c932a23db
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / i486 / pthread_cond_broadcast.S
1 /* Copyright (C) 2002, 2003, 2004, 2006, 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 <shlib-compat.h>
22 #include <lowlevellock.h>
23 #include <lowlevelcond.h>
24 #include <kernel-features.h>
25 #include <pthread-pi-defines.h>
26 #include <pthread-errnos.h>
27
28         .text
29
30         /* int pthread_cond_broadcast (pthread_cond_t *cond) */
31         .globl  __pthread_cond_broadcast
32         .type   __pthread_cond_broadcast, @function
33         .align  16
34 __pthread_cond_broadcast:
35
36         pushl   %ebx
37         pushl   %esi
38         pushl   %edi
39         pushl   %ebp
40
41         movl    20(%esp), %ebx
42
43         /* Get internal lock.  */
44         movl    $1, %edx
45         xorl    %eax, %eax
46         LOCK
47 #if cond_lock == 0
48         cmpxchgl %edx, (%ebx)
49 #else
50         cmpxchgl %edx, cond_lock(%ebx)
51 #endif
52         jnz     1f
53
54 2:      addl    $cond_futex, %ebx
55         movl    total_seq+4-cond_futex(%ebx), %eax
56         movl    total_seq-cond_futex(%ebx), %ebp
57         cmpl    wakeup_seq+4-cond_futex(%ebx), %eax
58         ja      3f
59         jb      4f
60         cmpl    wakeup_seq-cond_futex(%ebx), %ebp
61         jna     4f
62
63         /* Cause all currently waiting threads to recognize they are
64            woken up.  */
65 3:      movl    %ebp, wakeup_seq-cond_futex(%ebx)
66         movl    %eax, wakeup_seq-cond_futex+4(%ebx)
67         movl    %ebp, woken_seq-cond_futex(%ebx)
68         movl    %eax, woken_seq-cond_futex+4(%ebx)
69         addl    %ebp, %ebp
70         addl    $1, broadcast_seq-cond_futex(%ebx)
71         movl    %ebp, (%ebx)
72
73         /* Get the address of the mutex used.  */
74         movl    dep_mutex-cond_futex(%ebx), %edi
75
76         /* Unlock.  */
77         LOCK
78         subl    $1, cond_lock-cond_futex(%ebx)
79         jne     7f
80
81         /* Don't use requeue for pshared condvars.  */
82 8:      cmpl    $-1, %edi
83         je      9f
84
85         /* XXX: The kernel so far doesn't support requeue to PI futex.  */
86         /* XXX: The kernel only supports FUTEX_CMP_REQUEUE to the same
87            type of futex (private resp. shared).  */
88         testl   $(PI_BIT | PS_BIT), MUTEX_KIND(%edi)
89         jne     9f
90
91         /* Wake up all threads.  */
92 #ifdef __ASSUME_PRIVATE_FUTEX
93         movl    $(FUTEX_CMP_REQUEUE|FUTEX_PRIVATE_FLAG), %ecx
94 #else
95         movl    %gs:PRIVATE_FUTEX, %ecx
96         orl     $FUTEX_CMP_REQUEUE, %ecx
97 #endif
98         movl    $SYS_futex, %eax
99         movl    $0x7fffffff, %esi
100         movl    $1, %edx
101         /* Get the address of the futex involved.  */
102 # if MUTEX_FUTEX != 0
103         addl    $MUTEX_FUTEX, %edi
104 # endif
105 /* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for sysenter.
106         ENTER_KERNEL  */
107         int     $0x80
108
109         /* For any kind of error, which mainly is EAGAIN, we try again
110            with WAKE.  The general test also covers running on old
111            kernels.  */
112         cmpl    $0xfffff001, %eax
113         jae     9f
114
115 10:     xorl    %eax, %eax
116         popl    %ebp
117         popl    %edi
118         popl    %esi
119         popl    %ebx
120         ret
121
122         .align  16
123         /* Unlock.  */
124 4:      LOCK
125         subl    $1, cond_lock-cond_futex(%ebx)
126         jne     5f
127
128 6:      xorl    %eax, %eax
129         popl    %ebp
130         popl    %edi
131         popl    %esi
132         popl    %ebx
133         ret
134
135         /* Initial locking failed.  */
136 1:
137 #if cond_lock == 0
138         movl    %ebx, %edx
139 #else
140         leal    cond_lock(%ebx), %edx
141 #endif
142 #if (LLL_SHARED-LLL_PRIVATE) > 255
143         xorl    %ecx, %ecx
144 #endif
145         cmpl    $-1, dep_mutex(%ebx)
146         setne   %cl
147         subl    $1, %ecx
148         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
149 #if LLL_PRIVATE != 0
150         addl    $LLL_PRIVATE, %ecx
151 #endif
152         call    __lll_lock_wait
153         jmp     2b
154
155         /* Unlock in loop requires waekup.  */
156 5:      leal    cond_lock-cond_futex(%ebx), %eax
157 #if (LLL_SHARED-LLL_PRIVATE) > 255
158         xorl    %ecx, %ecx
159 #endif
160         cmpl    $-1, dep_mutex-cond_futex(%ebx)
161         setne   %cl
162         subl    $1, %ecx
163         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
164 #if LLL_PRIVATE != 0
165         addl    $LLL_PRIVATE, %ecx
166 #endif
167         call    __lll_unlock_wake
168         jmp     6b
169
170         /* Unlock in loop requires waekup.  */
171 7:      leal    cond_lock-cond_futex(%ebx), %eax
172 #if (LLL_SHARED-LLL_PRIVATE) > 255
173         xorl    %ecx, %ecx
174 #endif
175         cmpl    $-1, dep_mutex-cond_futex(%ebx)
176         setne   %cl
177         subl    $1, %ecx
178         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
179 #if LLL_PRIVATE != 0
180         addl    $LLL_PRIVATE, %ecx
181 #endif
182         call    __lll_unlock_wake
183         jmp     8b
184
185 9:      /* The futex requeue functionality is not available.  */
186         movl    $0x7fffffff, %edx
187 #if FUTEX_PRIVATE_FLAG > 255
188         xorl    %ecx, %ecx
189 #endif
190         cmpl    $-1, dep_mutex-cond_futex(%ebx)
191         sete    %cl
192         subl    $1, %ecx
193 #ifdef __ASSUME_PRIVATE_FUTEX
194         andl    $FUTEX_PRIVATE_FLAG, %ecx
195 #else
196         andl    %gs:PRIVATE_FUTEX, %ecx
197 #endif
198         addl    $FUTEX_WAKE, %ecx
199         movl    $SYS_futex, %eax
200         ENTER_KERNEL
201         jmp     10b
202         .size   __pthread_cond_broadcast, .-__pthread_cond_broadcast
203 versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
204                   GLIBC_2_3_2)