[BZ #163]
[platform/upstream/glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / i486 / pthread_cond_broadcast.S
1 /* Copyright (C) 2002, 2003, 2004 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 <lowlevelcond.h>
23 #include <kernel-features.h>
24
25 #ifdef UP
26 # define LOCK
27 #else
28 # define LOCK lock
29 #endif
30
31 #define SYS_futex               240
32 #define FUTEX_WAIT              0
33 #define FUTEX_WAKE              1
34 #define FUTEX_REQUEUE           3
35
36 #define EINVAL                  22
37
38
39         .text
40
41         /* int pthread_cond_broadcast (pthread_cond_t *cond) */
42         .globl  __pthread_cond_broadcast
43         .type   __pthread_cond_broadcast, @function
44         .align  16
45 __pthread_cond_broadcast:
46
47         pushl   %ebx
48         pushl   %esi
49         pushl   %edi
50
51         movl    16(%esp), %ebx
52
53         /* Get internal lock.  */
54         movl    $1, %edx
55         xorl    %eax, %eax
56         LOCK
57 #if cond_lock == 0
58         cmpxchgl %edx, (%ebx)
59 #else
60         cmpxchgl %edx, cond_lock(%ebx)
61 #endif
62         jnz     1f
63
64 2:      addl    $wakeup_seq, %ebx
65         movl    total_seq+4-wakeup_seq(%ebx), %eax
66         movl    total_seq-wakeup_seq(%ebx), %ecx
67         cmpl    4(%ebx), %eax
68         ja      3f
69         jb      4f
70         cmpl    (%ebx), %ecx
71         jna     4f
72
73         /* Cause all currently waiting threads to recognize they are
74            woken up.  */
75 3:      movl    %ecx, (%ebx)
76         movl    %eax, 4(%ebx)
77         movl    %ecx, woken_seq-wakeup_seq(%ebx)
78         movl    %eax, woken_seq-wakeup_seq+4(%ebx)
79         addl    $1, broadcast_seq-wakeup_seq(%ebx)
80
81         /* Get the address of the mutex used.  */
82         movl    dep_mutex-wakeup_seq(%ebx), %edi
83
84         /* Unlock.  */
85         LOCK
86         subl    $1, cond_lock-wakeup_seq(%ebx)
87         jne     7f
88
89         /* Don't use requeue for pshared condvars.  */
90 8:      cmpl    $-1, %edi
91         je      9f
92
93         /* Wake up all threads.  */
94         movl    $FUTEX_REQUEUE, %ecx
95         movl    $SYS_futex, %eax
96         movl    $0x7fffffff, %esi
97         movl    $1, %edx
98         /* Get the address of the futex involved.  */
99 # if MUTEX_FUTEX != 0
100         addl    $MUTEX_FUTEX, %edi
101 # endif
102         ENTER_KERNEL
103
104 #ifndef __ASSUME_FUTEX_REQUEUE
105         cmpl    $-EINVAL, %eax
106         je      9f
107 #endif
108
109 10:     xorl    %eax, %eax
110         popl    %edi
111         popl    %esi
112         popl    %ebx
113         ret
114
115         .align  16
116         /* Unlock.  */
117 4:      LOCK
118         subl    $1, cond_lock-wakeup_seq(%ebx)
119         jne     5f
120
121 6:      xorl    %eax, %eax
122         popl    %edi
123         popl    %esi
124         popl    %ebx
125         ret
126
127         /* Initial locking failed.  */
128 1:
129 #if cond_lock == 0
130         movl    %ebx, %ecx
131 #else
132         leal    cond_lock(%ebx), %ecx
133 #endif
134         call    __lll_mutex_lock_wait
135         jmp     2b
136
137         /* Unlock in loop requires waekup.  */
138 5:      leal    cond_lock-wakeup_seq(%ebx), %eax
139         call    __lll_mutex_unlock_wake
140         jmp     6b
141
142         /* Unlock in loop requires waekup.  */
143 7:      leal    cond_lock-wakeup_seq(%ebx), %eax
144         call    __lll_mutex_unlock_wake
145         jmp     8b
146
147 9:      /* The futex requeue functionality is not available.  */
148         movl    $0x7fffffff, %edx
149         movl    $FUTEX_WAKE, %ecx
150         movl    $SYS_futex, %eax
151         ENTER_KERNEL
152         jmp     10b
153         .size   __pthread_cond_broadcast, .-__pthread_cond_broadcast
154 versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
155                   GLIBC_2_3_2)