1 | /* Copyright (C) 2002-2016 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, see |
17 | <http://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <sysdep.h> |
20 | #include <shlib-compat.h> |
21 | #include <lowlevellock.h> |
22 | #include <lowlevelcond.h> |
23 | #include <kernel-features.h> |
24 | #include <pthread-pi-defines.h> |
25 | #include <pthread-errnos.h> |
26 | #include <stap-probe.h> |
27 | |
28 | .text |
29 | |
30 | /* int pthread_cond_broadcast (pthread_cond_t *cond) */ |
31 | ENTRY(__pthread_cond_broadcast) |
32 | |
33 | LIBC_PROBE (cond_broadcast, 1, %rdi) |
34 | |
35 | /* Get internal lock. */ |
36 | movl $1, %esi |
37 | xorl %eax, %eax |
38 | LOCK |
39 | #if cond_lock == 0 |
40 | cmpxchgl %esi, (%rdi) |
41 | #else |
42 | cmpxchgl %esi, cond_lock(%rdi) |
43 | #endif |
44 | jnz 1f |
45 | |
46 | 2: addq $cond_futex, %rdi |
47 | movq total_seq-cond_futex(%rdi), %r9 |
48 | cmpq wakeup_seq-cond_futex(%rdi), %r9 |
49 | jna 4f |
50 | |
51 | /* Cause all currently waiting threads to recognize they are |
52 | woken up. */ |
53 | movq %r9, wakeup_seq-cond_futex(%rdi) |
54 | movq %r9, woken_seq-cond_futex(%rdi) |
55 | addq %r9, %r9 |
56 | movl %r9d, (%rdi) |
57 | incl broadcast_seq-cond_futex(%rdi) |
58 | |
59 | /* Get the address of the mutex used. */ |
60 | mov dep_mutex-cond_futex(%rdi), %R8_LP |
61 | |
62 | /* Unlock. */ |
63 | LOCK |
64 | decl cond_lock-cond_futex(%rdi) |
65 | jne 7f |
66 | |
67 | 8: cmp $-1, %R8_LP |
68 | je 9f |
69 | |
70 | /* Do not use requeue for pshared condvars. */ |
71 | testl $PS_BIT, MUTEX_KIND(%r8) |
72 | jne 9f |
73 | |
74 | /* Requeue to a PI mutex if the PI bit is set. */ |
75 | movl MUTEX_KIND(%r8), %eax |
76 | andl $(ROBUST_BIT|PI_BIT), %eax |
77 | cmpl $PI_BIT, %eax |
78 | je 81f |
79 | |
80 | /* Wake up all threads. */ |
81 | #ifdef __ASSUME_PRIVATE_FUTEX |
82 | movl $(FUTEX_CMP_REQUEUE|FUTEX_PRIVATE_FLAG), %esi |
83 | #else |
84 | movl %fs:PRIVATE_FUTEX, %esi |
85 | orl $FUTEX_CMP_REQUEUE, %esi |
86 | #endif |
87 | movl $SYS_futex, %eax |
88 | movl $1, %edx |
89 | movl $0x7fffffff, %r10d |
90 | syscall |
91 | |
92 | /* For any kind of error, which mainly is EAGAIN, we try again |
93 | with WAKE. The general test also covers running on old |
94 | kernels. */ |
95 | cmpq $-4095, %rax |
96 | jae 9f |
97 | |
98 | 10: xorl %eax, %eax |
99 | retq |
100 | |
101 | /* Wake up all threads. */ |
102 | 81: movl $(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi |
103 | movl $SYS_futex, %eax |
104 | movl $1, %edx |
105 | movl $0x7fffffff, %r10d |
106 | syscall |
107 | |
108 | /* For any kind of error, which mainly is EAGAIN, we try again |
109 | with WAKE. The general test also covers running on old |
110 | kernels. */ |
111 | cmpq $-4095, %rax |
112 | jb 10b |
113 | jmp 9f |
114 | |
115 | .align 16 |
116 | /* Unlock. */ |
117 | 4: LOCK |
118 | decl cond_lock-cond_futex(%rdi) |
119 | jne 5f |
120 | |
121 | 6: xorl %eax, %eax |
122 | retq |
123 | |
124 | /* Initial locking failed. */ |
125 | 1: |
126 | #if cond_lock != 0 |
127 | addq $cond_lock, %rdi |
128 | #endif |
129 | LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi) |
130 | movl $LLL_PRIVATE, %eax |
131 | movl $LLL_SHARED, %esi |
132 | cmovne %eax, %esi |
133 | callq __lll_lock_wait |
134 | #if cond_lock != 0 |
135 | subq $cond_lock, %rdi |
136 | #endif |
137 | jmp 2b |
138 | |
139 | /* Unlock in loop requires wakeup. */ |
140 | 5: addq $cond_lock-cond_futex, %rdi |
141 | LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi) |
142 | movl $LLL_PRIVATE, %eax |
143 | movl $LLL_SHARED, %esi |
144 | cmovne %eax, %esi |
145 | callq __lll_unlock_wake |
146 | jmp 6b |
147 | |
148 | /* Unlock in loop requires wakeup. */ |
149 | 7: addq $cond_lock-cond_futex, %rdi |
150 | cmp $-1, %R8_LP |
151 | movl $LLL_PRIVATE, %eax |
152 | movl $LLL_SHARED, %esi |
153 | cmovne %eax, %esi |
154 | callq __lll_unlock_wake |
155 | subq $cond_lock-cond_futex, %rdi |
156 | jmp 8b |
157 | |
158 | 9: /* The futex requeue functionality is not available. */ |
159 | cmp $-1, %R8_LP |
160 | movl $0x7fffffff, %edx |
161 | #ifdef __ASSUME_PRIVATE_FUTEX |
162 | movl $FUTEX_WAKE, %eax |
163 | movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi |
164 | cmove %eax, %esi |
165 | #else |
166 | movl $0, %eax |
167 | movl %fs:PRIVATE_FUTEX, %esi |
168 | cmove %eax, %esi |
169 | orl $FUTEX_WAKE, %esi |
170 | #endif |
171 | movl $SYS_futex, %eax |
172 | syscall |
173 | jmp 10b |
174 | END(__pthread_cond_broadcast) |
175 | |
176 | versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, |
177 | GLIBC_2_3_2) |
178 | |