4909f49107f954e33734cae2109107579cbee8a4
[glibc/nacl-glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / i486 / pthread_cond_signal.S
blob4909f49107f954e33734cae2109107579cbee8a4
1 /* Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
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.
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.
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.  */
20 #include <sysdep.h>
21 #include <shlib-compat.h>
22 #include <lowlevellock.h>
23 #include <lowlevelcond.h>
24 #include <kernel-features.h>
25 #include <pthread-errnos.h>
28         .text
30         /* int pthread_cond_signal (pthread_cond_t *cond) */
31         .globl  __pthread_cond_signal
32         .type   __pthread_cond_signal, @function
33         .align  16
34 __pthread_cond_signal:
36         cfi_startproc
37         pushl   %ebx
38         cfi_adjust_cfa_offset(4)
39         pushl   %edi
40         cfi_adjust_cfa_offset(4)
41         cfi_offset(%ebx, -8)
42         cfi_offset(%edi, -12)
44         movl    12(%esp), %edi
46         /* Get internal lock.  */
47         movl    $1, %edx
48         xorl    %eax, %eax
49         LOCK
50 #if cond_lock == 0
51         cmpxchgl %edx, (%edi)
52 #else
53         cmpxchgl %edx, cond_lock(%edi)
54 #endif
55         jnz     1f
57 2:      leal    cond_futex(%edi), %ebx
58         movl    total_seq+4(%edi), %eax
59         movl    total_seq(%edi), %ecx
60         cmpl    wakeup_seq+4(%edi), %eax
61 #if cond_lock != 0
62         /* Must use leal to preserve the flags.  */
63         leal    cond_lock(%edi), %edi
64 #endif
65         ja      3f
66         jb      4f
67         cmpl    wakeup_seq-cond_futex(%ebx), %ecx
68         jbe     4f
70         /* Bump the wakeup number.  */
71 3:      addl    $1, wakeup_seq-cond_futex(%ebx)
72         adcl    $0, wakeup_seq-cond_futex+4(%ebx)
73         addl    $1, (%ebx)
75         /* Wake up one thread.  */
76         pushl   %esi
77         cfi_adjust_cfa_offset(4)
78         pushl   %ebp
79         cfi_adjust_cfa_offset(4)
80         cfi_offset(%esi, -16)
81         cfi_offset(%ebp, -20)
83 #if FUTEX_PRIVATE_FLAG > 255
84         xorl    %ecx, %ecx
85 #endif
86         cmpl    $-1, dep_mutex-cond_futex(%ebx)
87         sete    %cl
88         subl    $1, %ecx
89 #ifdef __ASSUME_PRIVATE_FUTEX
90         andl    $FUTEX_PRIVATE_FLAG, %ecx
91 #else
92         andl    %gs:PRIVATE_FUTEX, %ecx
93 #endif
94         addl    $FUTEX_WAKE_OP, %ecx
95         movl    $SYS_futex, %eax
96         movl    $1, %edx
97         movl    $1, %esi
98         movl    $FUTEX_OP_CLEAR_WAKE_IF_GT_ONE, %ebp
99         /* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for
100            sysenter.
101         ENTER_KERNEL  */
102         int     $0x80
103         popl    %ebp
104         cfi_adjust_cfa_offset(-4)
105         cfi_restore(%ebp)
106         popl    %esi
107         cfi_adjust_cfa_offset(-4)
108         cfi_restore(%esi)
110         /* For any kind of error, we try again with WAKE.
111            The general test also covers running on old kernels.  */
112         cmpl    $-4095, %eax
113         jae     7f
115 6:      xorl    %eax, %eax
116         popl    %edi
117         cfi_adjust_cfa_offset(-4)
118         cfi_restore(%edi)
119         popl    %ebx
120         cfi_adjust_cfa_offset(-4)
121         cfi_restore(%ebx)
122         ret
124         cfi_adjust_cfa_offset(8)
125         cfi_offset(%ebx, -8)
126         cfi_offset(%edi, -12)
128 7:      /* %ecx should be either FUTEX_WAKE_OP or
129            FUTEX_WAKE_OP|FUTEX_PRIVATE_FLAG from the previous syscall.  */
130         xorl    $(FUTEX_WAKE ^ FUTEX_WAKE_OP), %ecx
131         movl    $SYS_futex, %eax
132         /* %edx should be 1 already from $FUTEX_WAKE_OP syscall.
133         movl    $1, %edx  */
134         ENTER_KERNEL
136         /* Unlock.  Note that at this point %edi always points to
137            cond_lock.  */
138 4:      LOCK
139         subl    $1, (%edi)
140         je      6b
142         /* Unlock in loop requires wakeup.  */
143 5:      movl    %edi, %eax
144 #if (LLL_SHARED-LLL_PRIVATE) > 255
145         xorl    %ecx, %ecx
146 #endif
147         cmpl    $-1, dep_mutex-cond_futex(%ebx)
148         setne   %cl
149         subl    $1, %ecx
150         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
151 #if LLL_PRIVATE != 0
152         addl    $LLL_PRIVATE, %ecx
153 #endif
154         call    __lll_unlock_wake
155         jmp     6b
157         /* Initial locking failed.  */
159 #if cond_lock == 0
160         movl    %edi, %edx
161 #else
162         leal    cond_lock(%edi), %edx
163 #endif
164 #if (LLL_SHARED-LLL_PRIVATE) > 255
165         xorl    %ecx, %ecx
166 #endif
167         cmpl    $-1, dep_mutex(%edi)
168         setne   %cl
169         subl    $1, %ecx
170         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
171 #if LLL_PRIVATE != 0
172         addl    $LLL_PRIVATE, %ecx
173 #endif
174         call    __lll_lock_wait
175         jmp     2b
177         cfi_endproc
178         .size   __pthread_cond_signal, .-__pthread_cond_signal
179 versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal,
180                   GLIBC_2_3_2)