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
31ENTRY(__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
472: 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
768: 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. */
949: 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
1077:
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. */
1204: LOCK
121#if cond_lock == 0
122 decl (%r8)
123#else
124 decl cond_lock(%r8)
125#endif
126 jne 5f
127
1286: xorl %eax, %eax
129 retq
130
131 /* Initial locking failed. */
1321:
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. */
1475:
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
158END(__pthread_cond_signal)
159
160versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal,
161 GLIBC_2_3_2)
162