Release lock before waking up the waiters.
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / i486 / pthread_cond_broadcast.S
1 /* Copyright (C) 2002, 2003 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
24 #ifdef UP
25 # define LOCK
26 #else
27 # define LOCK lock
28 #endif
29
30 #define SYS_futex               240
31 #define FUTEX_WAIT              0
32 #define FUTEX_WAKE              1
33
34
35         .text
36
37         /* int pthread_cond_broadcast (pthread_cond_t *cond) */
38         .globl  __pthread_cond_broadcast
39         .type   __pthread_cond_broadcast, @function
40         .align  16
41 __pthread_cond_broadcast:
42
43         pushl   %esi
44         pushl   %ebx
45
46         movl    12(%esp), %ebx
47
48         /* Get internal lock.  */
49         movl    $1, %eax
50         LOCK
51 #if cond_lock == 0
52         xaddl   %eax, (%ebx)
53 #else
54         xaddl   %eax, cond_lock(%ebx)
55 #endif
56         testl   %eax, %eax
57         jne     1f
58
59 2:      addl    $wakeup_seq, %ebx
60         movl    total_seq+4-wakeup_seq(%ebx), %eax
61         movl    total_seq-wakeup_seq(%ebx), %ecx
62         cmpl    4(%ebx), %eax
63         ja      3f
64         jb      4f
65         cmpl    (%ebx), %ecx
66         jna     4f
67
68         /* Cause all currently waiting threads to recognize they are
69            woken up.  */
70 3:      movl    %ecx, (%ebx)
71         movl    %eax, 4(%ebx)
72
73         /* Unlock.  */
74         LOCK
75         decl    cond_lock-wakeup_seq(%ebx)
76         jne     7f
77
78         /* Wake up all threads.  */
79 8:      movl    $FUTEX_WAKE, %ecx
80         xorl    %esi, %esi
81         movl    $SYS_futex, %eax
82         movl    $0x7fffffff, %edx
83         ENTER_KERNEL
84
85         xorl    %eax, %eax
86         popl    %ebx
87         popl    %esi
88         ret
89
90         .align  16
91         /* Unlock.  */
92 4:      LOCK
93         decl    cond_lock-wakeup_seq(%ebx)
94         jne     5f
95
96 6:      xorl    %eax, %eax
97         popl    %ebx
98         popl    %esi
99         ret
100
101         /* Initial locking failed.  */
102 1:
103 #if cond_lock == 0
104         movl    %ebx, %ecx
105 #else
106         leal    cond_lock(%ebx), %ecx
107 #endif
108         call    __lll_mutex_lock_wait
109         jmp     2b
110
111         /* Unlock in loop requires waekup.  */
112 5:      leal    cond_lock-wakeup_seq(%ebx), %eax
113         call    __lll_mutex_unlock_wake
114         jmp     6b
115
116         /* Unlock in loop requires waekup.  */
117 7:      leal    cond_lock-wakeup_seq(%ebx), %eax
118         call    __lll_mutex_unlock_wake
119         jmp     8b
120         .size   __pthread_cond_broadcast, .-__pthread_cond_broadcast
121 versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
122                   GLIBC_2_3_2)