Updated to fedora-glibc-20070731T1624
[glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_cond_wait.S
blobaaad22e020ace6d58dafb02a270b949aba2e7b09
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 <lowlevelcond.h>
23 #include <tcb-offsets.h>
25 #ifdef UP
26 # define LOCK
27 #else
28 # define LOCK lock
29 #endif
31 #define SYS_futex               202
32 #define FUTEX_WAIT              0
33 #define FUTEX_WAKE              1
36         .text
38         .align  16
39         .type   __condvar_cleanup, @function
40         .globl  __condvar_cleanup
41         .hidden __condvar_cleanup
42 __condvar_cleanup:
43         pushq   %r12
45         /* Get internal lock.  */
46         movq    %rdi, %r8
47         movq    8(%rdi), %rdi
48         movl    $1, %esi
49         xorl    %eax, %eax
50         LOCK
51 #if cond_lock == 0
52         cmpxchgl %esi, (%rdi)
53 #else
54         cmpxchgl %esi, cond_lock(%rdi)
55 #endif
56         jz      1f
58 #if cond_lock != 0
59         addq    $cond_lock, %rdi
60 #endif
61         callq   __lll_mutex_lock_wait
62 #if cond_lock != 0
63         subq    $cond_lock, %rdi
64 #endif
66 1:      movl    broadcast_seq(%rdi), %edx
67         cmpl    4(%r8), %edx
68         jne     3f
70         /* We increment the wakeup_seq counter only if it is lower than
71            total_seq.  If this is not the case the thread was woken and
72            then canceled.  In this case we ignore the signal.  */
73         movq    total_seq(%rdi), %rax
74         cmpq    wakeup_seq(%rdi), %rax
75         jbe     6f
76         incq    wakeup_seq(%rdi)
77         incl    cond_futex(%rdi)
78 6:      incq    woken_seq(%rdi)
80 3:      subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
82         /* Wake up a thread which wants to destroy the condvar object.  */
83         xorq    %r12, %r12
84         cmpq    $0xffffffffffffffff, total_seq(%rdi)
85         jne     4f
86         movl    cond_nwaiters(%rdi), %eax
87         andl    $~((1 << nwaiters_shift) - 1), %eax
88         jne     4f
90         addq    $cond_nwaiters, %rdi
91         movl    $SYS_futex, %eax
92         movl    $FUTEX_WAKE, %esi
93         movl    $1, %edx
94         syscall
95         subq    $cond_nwaiters, %rdi
96         movl    $1, %r12d
98 4:      LOCK
99 #if cond_lock == 0
100         decl    (%rdi)
101 #else
102         decl    cond_lock(%rdi)
103 #endif
104         je      2f
105 #if cond_lock != 0
106         addq    $cond_lock, %rdi
107 #endif
108         callq   __lll_mutex_unlock_wake
110         /* Wake up all waiters to make sure no signal gets lost.  */
111 2:      testq   %r12, %r12
112         jnz     5f
113         addq    $cond_futex, %rdi
114         movl    $FUTEX_WAKE, %esi
115         movl    $0x7fffffff, %edx
116         movl    $SYS_futex, %eax
117         syscall
119 5:      movq    16(%r8), %rdi
120         callq   __pthread_mutex_cond_lock
122         popq    %r12
124         retq
125         .size   __condvar_cleanup, .-__condvar_cleanup
128 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */
129         .globl  __pthread_cond_wait
130         .type   __pthread_cond_wait, @function
131         .align  16
132 __pthread_cond_wait:
133 .LSTARTCODE:
134         pushq   %r12
135 .Lpush_r12:
136 #define FRAME_SIZE 64
137         subq    $FRAME_SIZE, %rsp
138 .Lsubq:
139         /* Stack frame:
141            rsp + 64
142                     +--------------------------+
143            rsp + 32 | cleanup buffer           |
144                     +--------------------------+
145            rsp + 24 | old wake_seq value       |
146                     +--------------------------+
147            rsp + 16 | mutex pointer            |
148                     +--------------------------+
149            rsp +  8 | condvar pointer          |
150                     +--------------------------+
151            rsp +  4 | old broadcast_seq value  |
152                     +--------------------------+
153            rsp +  0 | old cancellation mode    |
154                     +--------------------------+
155         */
157         cmpq    $-1, dep_mutex(%rdi)
159                 /* Prepare structure passed to cancellation handler.  */
160         movq    %rdi, 8(%rsp)
161         movq    %rsi, 16(%rsp)
163         je      15f
164         movq    %rsi, dep_mutex(%rdi)
166         /* Get internal lock.  */
167 15:     movl    $1, %esi
168         xorl    %eax, %eax
169         LOCK
170 #if cond_lock == 0
171         cmpxchgl %esi, (%rdi)
172 #else
173         cmpxchgl %esi, cond_lock(%rdi)
174 #endif
175         jne     1f
177         /* Unlock the mutex.  */
178 2:      movq    16(%rsp), %rdi
179         xorl    %esi, %esi
180         callq   __pthread_mutex_unlock_usercnt
182         testl   %eax, %eax
183         jne     12f
185         movq    8(%rsp), %rdi
186         incq    total_seq(%rdi)
187         incl    cond_futex(%rdi)
188         addl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
190         /* Install cancellation handler.  */
191 #ifdef PIC
192         leaq    __condvar_cleanup(%rip), %rsi
193 #else
194         leaq    __condvar_cleanup, %rsi
195 #endif
196         leaq    32(%rsp), %rdi
197         movq    %rsp, %rdx
198         callq   __pthread_cleanup_push
200         /* Get and store current wakeup_seq value.  */
201         movq    8(%rsp), %rdi
202         movq    wakeup_seq(%rdi), %r9
203         movl    broadcast_seq(%rdi), %edx
204         movq    %r9, 24(%rsp)
205         movl    %edx, 4(%rsp)
207         /* Unlock.  */
208 8:      movl    cond_futex(%rdi), %r12d
209         LOCK
210 #if cond_lock == 0
211         decl    (%rdi)
212 #else
213         decl    cond_lock(%rdi)
214 #endif
215         jne     3f
217 4:      callq   __pthread_enable_asynccancel
218         movl    %eax, (%rsp)
220         movq    8(%rsp), %rdi
221         xorq    %r10, %r10
222         movq    %r12, %rdx
223         addq    $cond_futex-cond_lock, %rdi
224         movl    $SYS_futex, %eax
225 #if FUTEX_WAIT == 0
226         xorl    %esi, %esi
227 #else
228         movl    $FUTEX_WAIT, %esi
229 #endif
230         syscall
232         movl    (%rsp), %edi
233         callq   __pthread_disable_asynccancel
235         /* Lock.  */
236         movq    8(%rsp), %rdi
237         movl    $1, %esi
238         xorl    %eax, %eax
239         LOCK
240 #if cond_lock == 0
241         cmpxchgl %esi, (%rdi)
242 #else
243         cmpxchgl %esi, cond_lock(%rdi)
244 #endif
245         jnz     5f
247 6:      movl    broadcast_seq(%rdi), %edx
249         movq    woken_seq(%rdi), %rax
251         movq    wakeup_seq(%rdi), %r9
253         cmpl    4(%rsp), %edx
254         jne     16f
256         cmpq    24(%rsp), %r9
257         jbe     8b
259         cmpq    %rax, %r9
260         jna     8b
262         incq    woken_seq(%rdi)
264         /* Unlock */
265 16:     subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
267         /* Wake up a thread which wants to destroy the condvar object.  */
268         cmpq    $0xffffffffffffffff, total_seq(%rdi)
269         jne     17f
270         movl    cond_nwaiters(%rdi), %eax
271         andl    $~((1 << nwaiters_shift) - 1), %eax
272         jne     17f
274         addq    $cond_nwaiters, %rdi
275         movl    $SYS_futex, %eax
276         movl    $FUTEX_WAKE, %esi
277         movl    $1, %edx
278         syscall
279         subq    $cond_nwaiters, %rdi
281 17:     LOCK
282 #if cond_lock == 0
283         decl    (%rdi)
284 #else
285         decl    cond_lock(%rdi)
286 #endif
287         jne     10f
289         /* Remove cancellation handler.  */
290 11:     movq    32+CLEANUP_PREV(%rsp), %rdx
291         movq    %rdx, %fs:CLEANUP
293         movq    16(%rsp), %rdi
294         callq   __pthread_mutex_cond_lock
295 14:     addq    $FRAME_SIZE, %rsp
296 .Laddq:
298         popq    %r12
299 .Lpop_r12:
301         /* We return the result of the mutex_lock operation.  */
302         retq
304         /* Initial locking failed.  */
306 .LSbl1:
307 #if cond_lock != 0
308         addq    $cond_lock, %rdi
309 #endif
310         callq   __lll_mutex_lock_wait
311         jmp     2b
313         /* Unlock in loop requires wakeup.  */
315 #if cond_lock != 0
316         addq    $cond_lock, %rdi
317 #endif
318         callq   __lll_mutex_unlock_wake
319         jmp     4b
321         /* Locking in loop failed.  */
323 #if cond_lock != 0
324         addq    $cond_lock, %rdi
325 #endif
326         callq   __lll_mutex_lock_wait
327 #if cond_lock != 0
328         subq    $cond_lock, %rdi
329 #endif
330         jmp     6b
332         /* Unlock after loop requires wakeup.  */
334 #if cond_lock != 0
335         addq    $cond_lock, %rdi
336 #endif
337         callq   __lll_mutex_unlock_wake
338         jmp     11b
340         /* The initial unlocking of the mutex failed.  */
341 12:     movq    %rax, %r10
342         movq    8(%rsp), %rdi
343         LOCK
344 #if cond_lock == 0
345         decl    (%rdi)
346 #else
347         decl    cond_lock(%rdi)
348 #endif
349         jne     13f
351 #if cond_lock != 0
352         addq    $cond_lock, %rdi
353 #endif
354         callq   __lll_mutex_unlock_wake
356 13:     movq    %r10, %rax
357         jmp     14b
358 .LENDCODE:
359         .size   __pthread_cond_wait, .-__pthread_cond_wait
360 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
361                   GLIBC_2_3_2)
364         .section .eh_frame,"a",@progbits
365 .LSTARTFRAME:
366         .long   L(ENDCIE)-L(STARTCIE)           # Length of the CIE.
367 .LSTARTCIE:
368         .long   0                               # CIE ID.
369         .byte   1                               # Version number.
370 #ifdef SHARED
371         .string "zR"                            # NUL-terminated augmentation
372                                                 # string.
373 #else
374         .ascii  "\0"                            # NUL-terminated augmentation
375                                                 # string.
376 #endif
377         .uleb128 1                              # Code alignment factor.
378         .sleb128 -8                             # Data alignment factor.
379         .byte   16                              # Return address register
380                                                 # column.
381 #ifdef SHARED
382         .uleb128 1                              # Augmentation value length.
383         .byte   0x1b                            # Encoding: DW_EH_PE_pcrel
384                                                 # + DW_EH_PE_sdata4.
385 #endif
386         .byte 0x0c                              # DW_CFA_def_cfa
387         .uleb128 7
388         .uleb128 8
389         .byte   0x90                            # DW_CFA_offset, column 0x8
390         .uleb128 1
391         .align 8
392 .LENDCIE:
394         .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
395 .LSTARTFDE:
396         .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
397 #ifdef SHARED
398         .long   .LSTARTCODE-.                   # PC-relative start address
399                                                 # of the code
400 #else
401         .long   .LSTARTCODE                     # Start address of the code.
402 #endif
403         .long   .LENDCODE-.LSTARTCODE           # Length of the code.
404 #ifdef SHARED
405         .uleb128 0                              # No augmentation data.
406 #endif
407         .byte   0x40+.Lpush_r12-.LSTARTCODE     # DW_CFA_advance_loc+N
408         .byte   14                              # DW_CFA_def_cfa_offset
409         .uleb128 16
410         .byte   0x8c                            # DW_CFA_offset %r12
411         .uleb128 2
412         .byte   0x40+.Lsubq-.Lpush_r12          # DW_CFA_advance_loc+N
413         .byte   14                              # DW_CFA_def_cfa_offset
414         .uleb128 16+FRAME_SIZE
415         .byte   3                               # DW_CFA_advance_loc2
416         .2byte  .Laddq-.Lsubq
417         .byte   14                              # DW_CFA_def_cfa_offset
418         .uleb128 16
419         .byte   0x40+.Lpop_r12-.Laddq           # DW_CFA_advance_loc+N
420         .byte   14                              # DW_CFA_def_cfa_offset
421         .uleb128 8
422         .byte   0xcc                            # DW_CFA_restore %r12
423         .byte   0x40+.LSbl1-.Lpop_r12           # DW_CFA_advance_loc+N
424         .byte   14                              # DW_CFA_def_cfa_offset
425         .uleb128 80
426         .byte   0x8c                            # DW_CFA_offset %r12
427         .uleb128 2
428         .align  8
429 .LENDFDE: