[BZ #163]
[platform/upstream/glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / 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               202
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         /* Get internal lock.  */
48         movl    $1, %esi
49         xorl    %eax, %eax
50         LOCK
51 #if cond_lock == 0
52         cmpxchgl %esi, (%rdi)
53 #else
54         cmpxchgl %esi, cond_lock(%rdi)
55 #endif
56         jnz     1f
57
58 2:      addq    $wakeup_seq, %rdi
59         movq    total_seq-wakeup_seq(%rdi), %rcx
60         cmpq    (%rdi), %rcx
61         jna     4f
62
63         /* Cause all currently waiting threads to recognize they are
64            woken up.  */
65         movq    %rcx, (%rdi)
66         movq    %rcx, woken_seq-wakeup_seq(%rdi)
67         incl    broadcast_seq-wakeup_seq(%rdi)
68
69         /* Get the address of the mutex used.  */
70         movq    dep_mutex-wakeup_seq(%rdi), %r8
71
72         /* Unlock.  */
73         LOCK
74         decl    cond_lock-wakeup_seq(%rdi)
75         jne     7f
76
77 8:      cmpq    $-1, %r8
78         je      9f
79
80         /* Wake up all threads.  */
81         movq    $FUTEX_REQUEUE, %rsi
82         movq    $SYS_futex, %rax
83         movl    $1, %edx
84         movq    $0x7fffffff, %r10
85         syscall
86
87 #ifndef __ASSUME_FUTEX_REQUEUE
88         cmpq    $-EINVAL, %rax
89         je      9f
90 #endif
91
92 10:     xorl    %eax, %eax
93         retq
94
95         .align  16
96         /* Unlock.  */
97 4:      LOCK
98         decl    cond_lock-wakeup_seq(%rdi)
99         jne     5f
100
101 6:      xorl    %eax, %eax
102         retq
103
104         /* Initial locking failed.  */
105 1:
106 #if cond_lock != 0
107         addq    $cond_lock, %rdi
108 #endif
109         callq   __lll_mutex_lock_wait
110 #if cond_lock != 0
111         subq    $cond_lock, %rdi
112 #endif
113         jmp     2b
114
115         /* Unlock in loop requires wakeup.  */
116 5:      addq    $cond_lock-wakeup_seq, %rdi
117         callq   __lll_mutex_unlock_wake
118         jmp     6b
119
120         /* Unlock in loop requires wakeup.  */
121 7:      addq    $cond_lock-wakeup_seq, %rdi
122         callq   __lll_mutex_unlock_wake
123         subq    $cond_lock-wakeup_seq, %rdi
124         jmp     8b
125
126 9:      /* The futex requeue functionality is not available.  */
127         movq    $0x7fffffff, %rdx
128         movq    $FUTEX_WAKE, %rsi
129         movq    $SYS_futex, %rax
130         syscall
131         jmp     10b
132         .size   __pthread_cond_broadcast, .-__pthread_cond_broadcast
133 versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
134                   GLIBC_2_3_2)