2.9
[glibc/nacl-glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_cond_wait.S
blobe5e802d53127582e3940885b44af3ef24fd9a341
1 /* Copyright (C) 2002,2003,2004,2005,2006,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 <tcb-offsets.h>
26 #include <kernel-features.h>
29         .text
31         .align  16
32         .type   __condvar_cleanup, @function
33         .globl  __condvar_cleanup
34         .hidden __condvar_cleanup
35 __condvar_cleanup:
36         pushq   %r12
38         /* Get internal lock.  */
39         movq    %rdi, %r8
40         movq    8(%rdi), %rdi
41         movl    $1, %esi
42         xorl    %eax, %eax
43         LOCK
44 #if cond_lock == 0
45         cmpxchgl %esi, (%rdi)
46 #else
47         cmpxchgl %esi, cond_lock(%rdi)
48 #endif
49         jz      1f
51 #if cond_lock != 0
52         addq    $cond_lock, %rdi
53 #endif
54         cmpq    $-1, dep_mutex-cond_lock(%rdi)
55         movl    $LLL_PRIVATE, %eax
56         movl    $LLL_SHARED, %esi
57         cmovne  %eax, %esi
58         callq   __lll_lock_wait
59 #if cond_lock != 0
60         subq    $cond_lock, %rdi
61 #endif
63 1:      movl    broadcast_seq(%rdi), %edx
64         cmpl    4(%r8), %edx
65         jne     3f
67         /* We increment the wakeup_seq counter only if it is lower than
68            total_seq.  If this is not the case the thread was woken and
69            then canceled.  In this case we ignore the signal.  */
70         movq    total_seq(%rdi), %rax
71         cmpq    wakeup_seq(%rdi), %rax
72         jbe     6f
73         incq    wakeup_seq(%rdi)
74         incl    cond_futex(%rdi)
75 6:      incq    woken_seq(%rdi)
77 3:      subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
79         /* Wake up a thread which wants to destroy the condvar object.  */
80         xorq    %r12, %r12
81         cmpq    $0xffffffffffffffff, total_seq(%rdi)
82         jne     4f
83         movl    cond_nwaiters(%rdi), %eax
84         andl    $~((1 << nwaiters_shift) - 1), %eax
85         jne     4f
87         addq    $cond_nwaiters, %rdi
88         cmpq    $-1, dep_mutex-cond_nwaiters(%rdi)
89         movl    $1, %edx
90 #ifdef __ASSUME_PRIVATE_FUTEX
91         movl    $FUTEX_WAKE, %eax
92         movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
93         cmove   %eax, %esi
94 #else
95         movl    $0, %eax
96         movl    %fs:PRIVATE_FUTEX, %esi
97         cmove   %eax, %esi
98         orl     $FUTEX_WAKE, %esi
99 #endif
100         movl    $SYS_futex, %eax
101         syscall
102         subq    $cond_nwaiters, %rdi
103         movl    $1, %r12d
105 4:      LOCK
106 #if cond_lock == 0
107         decl    (%rdi)
108 #else
109         decl    cond_lock(%rdi)
110 #endif
111         je      2f
112 #if cond_lock != 0
113         addq    $cond_lock, %rdi
114 #endif
115         cmpq    $-1, dep_mutex-cond_lock(%rdi)
116         movl    $LLL_PRIVATE, %eax
117         movl    $LLL_SHARED, %esi
118         cmovne  %eax, %esi
119         callq   __lll_unlock_wake
121         /* Wake up all waiters to make sure no signal gets lost.  */
122 2:      testq   %r12, %r12
123         jnz     5f
124         addq    $cond_futex, %rdi
125         cmpq    $-1, dep_mutex-cond_futex(%rdi)
126         movl    $0x7fffffff, %edx
127 #ifdef __ASSUME_PRIVATE_FUTEX
128         movl    $FUTEX_WAKE, %eax
129         movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
130         cmove   %eax, %esi
131 #else
132         movl    $0, %eax
133         movl    %fs:PRIVATE_FUTEX, %esi
134         cmove   %eax, %esi
135         orl     $FUTEX_WAKE, %esi
136 #endif
137         movl    $SYS_futex, %eax
138         syscall
140 5:      movq    16(%r8), %rdi
141         callq   __pthread_mutex_cond_lock
143         popq    %r12
145         retq
146         .size   __condvar_cleanup, .-__condvar_cleanup
149 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */
150         .globl  __pthread_cond_wait
151         .type   __pthread_cond_wait, @function
152         .align  16
153 __pthread_cond_wait:
154 .LSTARTCODE:
155         pushq   %r12
156 .Lpush_r12:
157 #define FRAME_SIZE 64
158         subq    $FRAME_SIZE, %rsp
159 .Lsubq:
160         /* Stack frame:
162            rsp + 64
163                     +--------------------------+
164            rsp + 32 | cleanup buffer           |
165                     +--------------------------+
166            rsp + 24 | old wake_seq value       |
167                     +--------------------------+
168            rsp + 16 | mutex pointer            |
169                     +--------------------------+
170            rsp +  8 | condvar pointer          |
171                     +--------------------------+
172            rsp +  4 | old broadcast_seq value  |
173                     +--------------------------+
174            rsp +  0 | old cancellation mode    |
175                     +--------------------------+
176         */
178         cmpq    $-1, dep_mutex(%rdi)
180                 /* Prepare structure passed to cancellation handler.  */
181         movq    %rdi, 8(%rsp)
182         movq    %rsi, 16(%rsp)
184         je      15f
185         movq    %rsi, dep_mutex(%rdi)
187         /* Get internal lock.  */
188 15:     movl    $1, %esi
189         xorl    %eax, %eax
190         LOCK
191 #if cond_lock == 0
192         cmpxchgl %esi, (%rdi)
193 #else
194         cmpxchgl %esi, cond_lock(%rdi)
195 #endif
196         jne     1f
198         /* Unlock the mutex.  */
199 2:      movq    16(%rsp), %rdi
200         xorl    %esi, %esi
201         callq   __pthread_mutex_unlock_usercnt
203         testl   %eax, %eax
204         jne     12f
206         movq    8(%rsp), %rdi
207         incq    total_seq(%rdi)
208         incl    cond_futex(%rdi)
209         addl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
211         /* Install cancellation handler.  */
212 #ifdef PIC
213         leaq    __condvar_cleanup(%rip), %rsi
214 #else
215         leaq    __condvar_cleanup, %rsi
216 #endif
217         leaq    32(%rsp), %rdi
218         movq    %rsp, %rdx
219         callq   __pthread_cleanup_push
221         /* Get and store current wakeup_seq value.  */
222         movq    8(%rsp), %rdi
223         movq    wakeup_seq(%rdi), %r9
224         movl    broadcast_seq(%rdi), %edx
225         movq    %r9, 24(%rsp)
226         movl    %edx, 4(%rsp)
228         /* Unlock.  */
229 8:      movl    cond_futex(%rdi), %r12d
230         LOCK
231 #if cond_lock == 0
232         decl    (%rdi)
233 #else
234         decl    cond_lock(%rdi)
235 #endif
236         jne     3f
238 4:      callq   __pthread_enable_asynccancel
239         movl    %eax, (%rsp)
241         movq    8(%rsp), %rdi
242         xorq    %r10, %r10
243         movq    %r12, %rdx
244         addq    $cond_futex-cond_lock, %rdi
245         cmpq    $-1, dep_mutex-cond_futex(%rdi)
246 #ifdef __ASSUME_PRIVATE_FUTEX
247         movl    $FUTEX_WAIT, %eax
248         movl    $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
249         cmove   %eax, %esi
250 #else
251         movl    $FUTEX_WAIT, %eax
252         movl    %fs:PRIVATE_FUTEX, %esi
253         cmove   %eax, %esi
254 # if FUTEX_WAIT != 0
255         orl     $FUTEX_WAIT, %esi
256 # endif
257 #endif
258         movl    $SYS_futex, %eax
259         syscall
261         movl    (%rsp), %edi
262         callq   __pthread_disable_asynccancel
264         /* Lock.  */
265         movq    8(%rsp), %rdi
266         movl    $1, %esi
267         xorl    %eax, %eax
268         LOCK
269 #if cond_lock == 0
270         cmpxchgl %esi, (%rdi)
271 #else
272         cmpxchgl %esi, cond_lock(%rdi)
273 #endif
274         jnz     5f
276 6:      movl    broadcast_seq(%rdi), %edx
278         movq    woken_seq(%rdi), %rax
280         movq    wakeup_seq(%rdi), %r9
282         cmpl    4(%rsp), %edx
283         jne     16f
285         cmpq    24(%rsp), %r9
286         jbe     8b
288         cmpq    %rax, %r9
289         jna     8b
291         incq    woken_seq(%rdi)
293         /* Unlock */
294 16:     subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
296         /* Wake up a thread which wants to destroy the condvar object.  */
297         cmpq    $0xffffffffffffffff, total_seq(%rdi)
298         jne     17f
299         movl    cond_nwaiters(%rdi), %eax
300         andl    $~((1 << nwaiters_shift) - 1), %eax
301         jne     17f
303         addq    $cond_nwaiters, %rdi
304         cmpq    $-1, dep_mutex-cond_nwaiters(%rdi)
305         movl    $1, %edx
306 #ifdef __ASSUME_PRIVATE_FUTEX
307         movl    $FUTEX_WAKE, %eax
308         movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
309         cmove   %eax, %esi
310 #else
311         movl    $0, %eax
312         movl    %fs:PRIVATE_FUTEX, %esi
313         cmove   %eax, %esi
314         orl     $FUTEX_WAKE, %esi
315 #endif
316         movl    $SYS_futex, %eax
317         syscall
318         subq    $cond_nwaiters, %rdi
320 17:     LOCK
321 #if cond_lock == 0
322         decl    (%rdi)
323 #else
324         decl    cond_lock(%rdi)
325 #endif
326         jne     10f
328         /* Remove cancellation handler.  */
329 11:     movq    32+CLEANUP_PREV(%rsp), %rdx
330         movq    %rdx, %fs:CLEANUP
332         movq    16(%rsp), %rdi
333         callq   __pthread_mutex_cond_lock
334 14:     addq    $FRAME_SIZE, %rsp
335 .Laddq:
337         popq    %r12
338 .Lpop_r12:
340         /* We return the result of the mutex_lock operation.  */
341         retq
343         /* Initial locking failed.  */
345 .LSbl1:
346 #if cond_lock != 0
347         addq    $cond_lock, %rdi
348 #endif
349         cmpq    $-1, dep_mutex-cond_lock(%rdi)
350         movl    $LLL_PRIVATE, %eax
351         movl    $LLL_SHARED, %esi
352         cmovne  %eax, %esi
353         callq   __lll_lock_wait
354         jmp     2b
356         /* Unlock in loop requires wakeup.  */
358 #if cond_lock != 0
359         addq    $cond_lock, %rdi
360 #endif
361         cmpq    $-1, dep_mutex-cond_lock(%rdi)
362         movl    $LLL_PRIVATE, %eax
363         movl    $LLL_SHARED, %esi
364         cmovne  %eax, %esi
365         callq   __lll_unlock_wake
366         jmp     4b
368         /* Locking in loop failed.  */
370 #if cond_lock != 0
371         addq    $cond_lock, %rdi
372 #endif
373         cmpq    $-1, dep_mutex-cond_lock(%rdi)
374         movl    $LLL_PRIVATE, %eax
375         movl    $LLL_SHARED, %esi
376         cmovne  %eax, %esi
377         callq   __lll_lock_wait
378 #if cond_lock != 0
379         subq    $cond_lock, %rdi
380 #endif
381         jmp     6b
383         /* Unlock after loop requires wakeup.  */
385 #if cond_lock != 0
386         addq    $cond_lock, %rdi
387 #endif
388         cmpq    $-1, dep_mutex-cond_lock(%rdi)
389         movl    $LLL_PRIVATE, %eax
390         movl    $LLL_SHARED, %esi
391         cmovne  %eax, %esi
392         callq   __lll_unlock_wake
393         jmp     11b
395         /* The initial unlocking of the mutex failed.  */
396 12:     movq    %rax, %r10
397         movq    8(%rsp), %rdi
398         LOCK
399 #if cond_lock == 0
400         decl    (%rdi)
401 #else
402         decl    cond_lock(%rdi)
403 #endif
404         je      13f
406 #if cond_lock != 0
407         addq    $cond_lock, %rdi
408 #endif
409         cmpq    $-1, dep_mutex-cond_lock(%rdi)
410         movl    $LLL_PRIVATE, %eax
411         movl    $LLL_SHARED, %esi
412         cmovne  %eax, %esi
413         callq   __lll_unlock_wake
415 13:     movq    %r10, %rax
416         jmp     14b
417 .LENDCODE:
418         .size   __pthread_cond_wait, .-__pthread_cond_wait
419 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
420                   GLIBC_2_3_2)
423         .section .eh_frame,"a",@progbits
424 .LSTARTFRAME:
425         .long   L(ENDCIE)-L(STARTCIE)           # Length of the CIE.
426 .LSTARTCIE:
427         .long   0                               # CIE ID.
428         .byte   1                               # Version number.
429 #ifdef SHARED
430         .string "zR"                            # NUL-terminated augmentation
431                                                 # string.
432 #else
433         .ascii  "\0"                            # NUL-terminated augmentation
434                                                 # string.
435 #endif
436         .uleb128 1                              # Code alignment factor.
437         .sleb128 -8                             # Data alignment factor.
438         .byte   16                              # Return address register
439                                                 # column.
440 #ifdef SHARED
441         .uleb128 1                              # Augmentation value length.
442         .byte   0x1b                            # Encoding: DW_EH_PE_pcrel
443                                                 # + DW_EH_PE_sdata4.
444 #endif
445         .byte 0x0c                              # DW_CFA_def_cfa
446         .uleb128 7
447         .uleb128 8
448         .byte   0x90                            # DW_CFA_offset, column 0x8
449         .uleb128 1
450         .align 8
451 .LENDCIE:
453         .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
454 .LSTARTFDE:
455         .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
456 #ifdef SHARED
457         .long   .LSTARTCODE-.                   # PC-relative start address
458                                                 # of the code
459 #else
460         .long   .LSTARTCODE                     # Start address of the code.
461 #endif
462         .long   .LENDCODE-.LSTARTCODE           # Length of the code.
463 #ifdef SHARED
464         .uleb128 0                              # No augmentation data.
465 #endif
466         .byte   0x40+.Lpush_r12-.LSTARTCODE     # DW_CFA_advance_loc+N
467         .byte   14                              # DW_CFA_def_cfa_offset
468         .uleb128 16
469         .byte   0x8c                            # DW_CFA_offset %r12
470         .uleb128 2
471         .byte   0x40+.Lsubq-.Lpush_r12          # DW_CFA_advance_loc+N
472         .byte   14                              # DW_CFA_def_cfa_offset
473         .uleb128 16+FRAME_SIZE
474         .byte   3                               # DW_CFA_advance_loc2
475         .2byte  .Laddq-.Lsubq
476         .byte   14                              # DW_CFA_def_cfa_offset
477         .uleb128 16
478         .byte   0x40+.Lpop_r12-.Laddq           # DW_CFA_advance_loc+N
479         .byte   14                              # DW_CFA_def_cfa_offset
480         .uleb128 8
481         .byte   0xcc                            # DW_CFA_restore %r12
482         .byte   0x40+.LSbl1-.Lpop_r12           # DW_CFA_advance_loc+N
483         .byte   14                              # DW_CFA_def_cfa_offset
484         .uleb128 80
485         .byte   0x8c                            # DW_CFA_offset %r12
486         .uleb128 2
487         .align  8
488 .LENDFDE: