[BZ #163]
[platform/upstream/glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_cond_wait.S
1 /* Copyright (C) 2002, 2003 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 <tcb-offsets.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
35
36         .text
37
38         .align  16
39         .type   __condvar_cleanup, @function
40         .globl  __condvar_cleanup
41         .hidden __condvar_cleanup
42 __condvar_cleanup:
43         /* Get internal lock.  */
44         movq    %rdi, %r8
45         movq    8(%rdi), %rdi
46         movl    $1, %esi
47         xorl    %eax, %eax
48         LOCK
49 #if cond_lock == 0
50         cmpxchgl %esi, (%rdi)
51 #else
52         cmpxchgl %esi, cond_lock(%rdi)
53 #endif
54         jz      1f
55
56 #if cond_lock != 0
57         addq    $cond_lock, %rdi
58 #endif
59         callq   __lll_mutex_lock_wait
60 #if cond_lock != 0
61         subq    $cond_lock, %rdi
62 #endif
63
64 1:      movl    broadcast_seq(%rdi), %edx
65         cmpl    4(%r8), %edx
66         jne     3f
67
68         incq    wakeup_seq(%rdi)
69
70         incq    woken_seq(%rdi)
71
72 3:      LOCK
73 #if cond_lock == 0
74         decl    (%rdi)
75 #else
76         decl    cond_lock(%rdi)
77 #endif
78         je      2f
79 #if cond_lock != 0
80         addq    $cond_lock, %rdi
81 #endif
82         callq   __lll_mutex_unlock_wake
83
84         /* Wake up all waiters to make sure no signal gets lost.  */
85 2:      addq    $wakeup_seq, %rdi
86         movq    $FUTEX_WAKE, %rsi
87         movl    $0x7fffffff, %edx
88         movq    $SYS_futex, %rax
89         syscall
90
91         movq    16(%r8), %rdi
92         callq   __pthread_mutex_cond_lock
93
94         retq
95         .size   __condvar_cleanup, .-__condvar_cleanup
96
97
98 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */
99         .globl  __pthread_cond_wait
100         .type   __pthread_cond_wait, @function
101         .align  16
102 __pthread_cond_wait:
103 .LSTARTCODE:
104         pushq   %r12
105 .Lpush_r12:
106 #define FRAME_SIZE 64
107         subq    $FRAME_SIZE, %rsp
108 .Lsubq:
109         /* Stack frame:
110
111            rsp + 64
112                     +--------------------------+
113            rsp + 32 | cleanup buffer           |
114                     +--------------------------+
115            rsp + 24 | old wake_seq value       |
116                     +--------------------------+
117            rsp + 16 | mutex pointer            |
118                     +--------------------------+
119            rsp +  8 | condvar pointer          |
120                     +--------------------------+
121            rsp +  4 | old broadcast_seq value  |
122                     +--------------------------+
123            rsp +  0 | old cancellation mode    |
124                     +--------------------------+
125         */
126
127         cmpq    $-1, dep_mutex(%rdi)
128
129                 /* Prepare structure passed to cancellation handler.  */
130         movq    %rdi, 8(%rsp)
131         movq    %rsi, 16(%rsp)
132
133         je      15f
134         movq    %rsi, dep_mutex(%rdi)
135
136         /* Get internal lock.  */
137 15:     movl    $1, %esi
138         xorl    %eax, %eax
139         LOCK
140 #if cond_lock == 0
141         cmpxchgl %esi, (%rdi)
142 #else
143         cmpxchgl %esi, cond_lock(%rdi)
144 #endif
145         jne     1f
146
147         /* Unlock the mutex.  */
148 2:      movq    16(%rsp), %rdi
149         xorq    %rsi, %rsi
150         callq   __pthread_mutex_unlock_usercnt
151
152         testl   %eax, %eax
153         jne     12f
154
155         movq    8(%rsp), %rdi
156         incq    total_seq(%rdi)
157
158         /* Install cancellation handler.  */
159 #ifdef PIC
160         leaq    __condvar_cleanup(%rip), %rsi
161 #else
162         leaq    __condvar_cleanup, %rsi
163 #endif
164         leaq    32(%rsp), %rdi
165         movq    %rsp, %rdx
166         callq   __pthread_cleanup_push
167
168         /* Get and store current wakeup_seq value.  */
169         movq    8(%rsp), %rdi
170         movq    wakeup_seq(%rdi), %r12
171         movl    broadcast_seq(%rdi), %edx
172         movq    %r12, 24(%rsp)
173         movl    %edx, 4(%rsp)
174
175         /* Unlock.  */
176 8:      LOCK
177 #if cond_lock == 0
178         decl    (%rdi)
179 #else
180         decl    cond_lock(%rdi)
181 #endif
182         jne     3f
183
184 4:      callq   __pthread_enable_asynccancel
185         movl    %eax, (%rsp)
186
187         movq    8(%rsp), %rdi
188         xorq    %r10, %r10
189         movq    %r12, %rdx
190         addq    $wakeup_seq-cond_lock, %rdi
191         movq    $SYS_futex, %rax
192         movq    %r10, %rsi      /* movq $FUTEX_WAIT, %rsi */
193         syscall
194
195         movl    (%rsp), %edi
196         callq   __pthread_disable_asynccancel
197
198         /* Lock.  */
199         movq    8(%rsp), %rdi
200         movl    $1, %esi
201         xorl    %eax, %eax
202         LOCK
203 #if cond_lock == 0
204         cmpxchgl %esi, (%rdi)
205 #else
206         cmpxchgl %esi, cond_lock(%rdi)
207 #endif
208         jnz     5f
209
210 6:      movl    broadcast_seq(%rdi), %edx
211
212         movq    woken_seq(%rdi), %rax
213
214         movq    wakeup_seq(%rdi), %r12
215
216         cmpl    4(%rsp), %edx
217         jne     16f
218
219         cmpq    24(%rsp), %r12
220         jbe     8b
221
222         cmpq    %rax, %r12
223         jna     8b
224
225         incq    woken_seq(%rdi)
226
227         /* Unlock */
228 16:     LOCK
229 #if cond_lock == 0
230         decl    (%rdi)
231 #else
232         decl    cond_lock(%rdi)
233 #endif
234         jne     10f
235
236         /* Remove cancellation handler.  */
237 11:     movq    32+CLEANUP_PREV(%rsp), %rdx
238         movq    %rdx, %fs:CLEANUP
239
240         movq    16(%rsp), %rdi
241         callq   __pthread_mutex_cond_lock
242 14:     addq    $FRAME_SIZE, %rsp
243 .Laddq:
244
245         popq    %r12
246 .Lpop_r12:
247
248         /* We return the result of the mutex_lock operation.  */
249         retq
250
251         /* Initial locking failed.  */
252 1:
253 .LSbl1:
254 #if cond_lock != 0
255         addq    $cond_lock, %rdi
256 #endif
257         callq   __lll_mutex_lock_wait
258         jmp     2b
259
260         /* Unlock in loop requires wakeup.  */
261 3:
262 #if cond_lock != 0
263         addq    $cond_lock, %rdi
264 #endif
265         callq   __lll_mutex_unlock_wake
266         jmp     4b
267
268         /* Locking in loop failed.  */
269 5:
270 #if cond_lock != 0
271         addq    $cond_lock, %rdi
272 #endif
273         callq   __lll_mutex_lock_wait
274 #if cond_lock != 0
275         subq    $cond_lock, %rdi
276 #endif
277         jmp     6b
278
279         /* Unlock after loop requires wakeup.  */
280 10:
281 #if cond_lock != 0
282         addq    $cond_lock, %rdi
283 #endif
284         callq   __lll_mutex_unlock_wake
285         jmp     11b
286
287         /* The initial unlocking of the mutex failed.  */
288 12:     movq    %rax, %r10
289         movq    8(%rsp), %rdi
290         LOCK
291 #if cond_lock == 0
292         decl    (%rdi)
293 #else
294         decl    cond_lock(%rdi)
295 #endif
296         jne     13f
297
298 #if cond_lock != 0
299         addq    $cond_lock, %rdi
300 #endif
301         callq   __lll_mutex_unlock_wake
302
303 13:     movq    %r10, %rax
304         jmp     14b
305 .LENDCODE:
306         .size   __pthread_cond_wait, .-__pthread_cond_wait
307 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
308                   GLIBC_2_3_2)
309
310
311         .section .eh_frame,"a",@progbits
312 .LSTARTFRAME:
313         .long   L(ENDCIE)-L(STARTCIE)           # Length of the CIE.
314 .LSTARTCIE:
315         .long   0                               # CIE ID.
316         .byte   1                               # Version number.
317 #ifdef SHARED
318         .string "zR"                            # NUL-terminated augmentation
319                                                 # string.
320 #else
321         .ascii  "\0"                            # NUL-terminated augmentation
322                                                 # string.
323 #endif
324         .uleb128 1                              # Code alignment factor.
325         .sleb128 -8                             # Data alignment factor.
326         .byte   16                              # Return address register
327                                                 # column.
328 #ifdef SHARED
329         .uleb128 1                              # Augmentation value length.
330         .byte   0x1b                            # Encoding: DW_EH_PE_pcrel
331                                                 # + DW_EH_PE_sdata4.
332 #endif
333         .byte 0x0c                              # DW_CFA_def_cfa
334         .uleb128 7
335         .uleb128 8
336         .byte   0x90                            # DW_CFA_offset, column 0x8
337         .uleb128 1
338         .align 8
339 .LENDCIE:
340
341         .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
342 .LSTARTFDE:
343         .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
344 #ifdef SHARED
345         .long   .LSTARTCODE-.                   # PC-relative start address
346                                                 # of the code
347 #else
348         .long   .LSTARTCODE                     # Start address of the code.
349 #endif
350         .long   .LENDCODE-.LSTARTCODE           # Length of the code.
351 #ifdef SHARED
352         .uleb128 0                              # No augmentation data.
353 #endif
354         .byte   0x40+.Lpush_r12-.LSTARTCODE     # DW_CFA_advance_loc+N
355         .byte   14                              # DW_CFA_def_cfa_offset
356         .uleb128 16
357         .byte   0x8c                            # DW_CFA_offset %r12
358         .uleb128 2
359         .byte   0x40+.Lsubq-.Lpush_r12          # DW_CFA_advance_loc+N
360         .byte   14                              # DW_CFA_def_cfa_offset
361         .uleb128 16+FRAME_SIZE
362         .byte   2                               # DW_CFA_advance_loc1
363         .byte   .Laddq-.Lsubq
364         .byte   14                              # DW_CFA_def_cfa_offset
365         .uleb128 16
366         .byte   0x40+.Lpop_r12-.Laddq           # DW_CFA_advance_loc+N
367         .byte   14                              # DW_CFA_def_cfa_offset
368         .uleb128 8
369         .byte   0xcc                            # DW_CFA_restore %r12
370         .byte   0x40+.LSbl1-.Lpop_r12           # DW_CFA_advance_loc+N
371         .byte   14                              # DW_CFA_def_cfa_offset
372         .uleb128 80
373         .byte   0x8c                            # DW_CFA_offset %r12
374         .uleb128 2
375         .align  8
376 .LENDFDE: