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