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 <pthread-pi-defines.h> |
24 | #include <kernel-features.h> |
25 | #include <pthread-errnos.h> |
26 | #include <stap-probe.h> |
27 | |
28 | |
29 | .text |
30 | |
31 | ENTRY(__pthread_cond_signal) |
32 | |
33 | LIBC_PROBE (cond_signal, 1, %rdi) |
34 | |
35 | /* Get internal lock. */ |
36 | movq %rdi, %r8 |
37 | movl $1, %esi |
38 | xorl %eax, %eax |
39 | LOCK |
40 | #if cond_lock == 0 |
41 | cmpxchgl %esi, (%rdi) |
42 | #else |
43 | cmpxchgl %esi, cond_lock(%rdi) |
44 | #endif |
45 | jnz 1f |
46 | |
47 | 2: addq $cond_futex, %rdi |
48 | movq total_seq(%r8), %rcx |
49 | cmpq wakeup_seq(%r8), %rcx |
50 | jbe 4f |
51 | |
52 | /* Bump the wakeup number. */ |
53 | addq $1, wakeup_seq(%r8) |
54 | addl $1, (%rdi) |
55 | |
56 | /* Wake up one thread. */ |
57 | LP_OP(cmp) $-1, dep_mutex(%r8) |
58 | movl $FUTEX_WAKE_OP, %esi |
59 | movl $1, %edx |
60 | movl $SYS_futex, %eax |
61 | je 8f |
62 | |
63 | /* Get the address of the mutex used. */ |
64 | mov dep_mutex(%r8), %RCX_LP |
65 | movl MUTEX_KIND(%rcx), %r11d |
66 | andl $(ROBUST_BIT|PI_BIT), %r11d |
67 | cmpl $PI_BIT, %r11d |
68 | je 9f |
69 | |
70 | #ifdef __ASSUME_PRIVATE_FUTEX |
71 | movl $(FUTEX_WAKE_OP|FUTEX_PRIVATE_FLAG), %esi |
72 | #else |
73 | orl %fs:PRIVATE_FUTEX, %esi |
74 | #endif |
75 | |
76 | 8: movl $1, %r10d |
77 | #if cond_lock != 0 |
78 | addq $cond_lock, %r8 |
79 | #endif |
80 | movl $FUTEX_OP_CLEAR_WAKE_IF_GT_ONE, %r9d |
81 | syscall |
82 | #if cond_lock != 0 |
83 | subq $cond_lock, %r8 |
84 | #endif |
85 | /* For any kind of error, we try again with WAKE. |
86 | The general test also covers running on old kernels. */ |
87 | cmpq $-4095, %rax |
88 | jae 7f |
89 | |
90 | xorl %eax, %eax |
91 | retq |
92 | |
93 | /* Wake up one thread and requeue none in the PI Mutex case. */ |
94 | 9: movl $(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi |
95 | movq %rcx, %r8 |
96 | xorq %r10, %r10 |
97 | movl (%rdi), %r9d // XXX Can this be right? |
98 | syscall |
99 | |
100 | leaq -cond_futex(%rdi), %r8 |
101 | |
102 | /* For any kind of error, we try again with WAKE. |
103 | The general test also covers running on old kernels. */ |
104 | cmpq $-4095, %rax |
105 | jb 4f |
106 | |
107 | 7: |
108 | #ifdef __ASSUME_PRIVATE_FUTEX |
109 | andl $FUTEX_PRIVATE_FLAG, %esi |
110 | #else |
111 | andl %fs:PRIVATE_FUTEX, %esi |
112 | #endif |
113 | orl $FUTEX_WAKE, %esi |
114 | movl $SYS_futex, %eax |
115 | /* %rdx should be 1 already from $FUTEX_WAKE_OP syscall. |
116 | movl $1, %edx */ |
117 | syscall |
118 | |
119 | /* Unlock. */ |
120 | 4: LOCK |
121 | #if cond_lock == 0 |
122 | decl (%r8) |
123 | #else |
124 | decl cond_lock(%r8) |
125 | #endif |
126 | jne 5f |
127 | |
128 | 6: xorl %eax, %eax |
129 | retq |
130 | |
131 | /* Initial locking failed. */ |
132 | 1: |
133 | #if cond_lock != 0 |
134 | addq $cond_lock, %rdi |
135 | #endif |
136 | LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi) |
137 | movl $LLL_PRIVATE, %eax |
138 | movl $LLL_SHARED, %esi |
139 | cmovne %eax, %esi |
140 | callq __lll_lock_wait |
141 | #if cond_lock != 0 |
142 | subq $cond_lock, %rdi |
143 | #endif |
144 | jmp 2b |
145 | |
146 | /* Unlock in loop requires wakeup. */ |
147 | 5: |
148 | movq %r8, %rdi |
149 | #if cond_lock != 0 |
150 | addq $cond_lock, %rdi |
151 | #endif |
152 | LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi) |
153 | movl $LLL_PRIVATE, %eax |
154 | movl $LLL_SHARED, %esi |
155 | cmovne %eax, %esi |
156 | callq __lll_unlock_wake |
157 | jmp 6b |
158 | END(__pthread_cond_signal) |
159 | |
160 | versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, |
161 | GLIBC_2_3_2) |
162 | |