OSDN Git Service

Replace FSF snail mail address with URLs
[uclinux-h8/uClibc.git] / libpthread / nptl / sysdeps / unix / sysv / linux / x86_64 / pthread_cond_wait.S
1 /* Copyright (C) 2002-2007, 2009 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, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <sysdep.h>
20 #include <lowlevellock.h>
21 #include <lowlevelcond.h>
22 #include <tcb-offsets.h>
23 #include <pthread-pi-defines.h>
24
25 #include <bits/kernel-features.h>
26
27
28         .text
29
30 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */
31         .globl  __pthread_cond_wait
32         .type   __pthread_cond_wait, @function
33         .protected      __pthread_cond_wait
34         .align  16
35 __pthread_cond_wait:
36 .LSTARTCODE:
37         cfi_startproc
38
39 #define FRAME_SIZE 32
40         leaq    -FRAME_SIZE(%rsp), %rsp
41         cfi_adjust_cfa_offset(FRAME_SIZE)
42
43         /* Stack frame:
44
45            rsp + 32
46                     +--------------------------+
47            rsp + 24 | old wake_seq value       |
48                     +--------------------------+
49            rsp + 16 | mutex pointer            |
50                     +--------------------------+
51            rsp +  8 | condvar pointer          |
52                     +--------------------------+
53            rsp +  4 | old broadcast_seq value  |
54                     +--------------------------+
55            rsp +  0 | old cancellation mode    |
56                     +--------------------------+
57         */
58
59         cmpq    $-1, dep_mutex(%rdi)
60
61                 /* Prepare structure passed to cancellation handler.  */
62         movq    %rdi, 8(%rsp)
63         movq    %rsi, 16(%rsp)
64
65         je      15f
66         movq    %rsi, dep_mutex(%rdi)
67
68         /* Get internal lock.  */
69 15:     movl    $1, %esi
70         xorl    %eax, %eax
71         LOCK
72 #if cond_lock == 0
73         cmpxchgl %esi, (%rdi)
74 #else
75         cmpxchgl %esi, cond_lock(%rdi)
76 #endif
77         jne     1f
78
79         /* Unlock the mutex.  */
80 2:      movq    16(%rsp), %rdi
81         xorl    %esi, %esi
82         callq   __pthread_mutex_unlock_usercnt
83
84         testl   %eax, %eax
85         jne     12f
86
87         movq    8(%rsp), %rdi
88         incq    total_seq(%rdi)
89         incl    cond_futex(%rdi)
90         addl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
91
92         /* Get and store current wakeup_seq value.  */
93         movq    8(%rsp), %rdi
94         movq    wakeup_seq(%rdi), %r9
95         movl    broadcast_seq(%rdi), %edx
96         movq    %r9, 24(%rsp)
97         movl    %edx, 4(%rsp)
98
99         /* Unlock.  */
100 8:      movl    cond_futex(%rdi), %edx
101         LOCK
102 #if cond_lock == 0
103         decl    (%rdi)
104 #else
105         decl    cond_lock(%rdi)
106 #endif
107         jne     3f
108
109 .LcleanupSTART:
110 4:      callq   __pthread_enable_asynccancel
111         movl    %eax, (%rsp)
112
113         xorq    %r10, %r10
114         cmpq    $-1, dep_mutex(%rdi)
115         leaq    cond_futex(%rdi), %rdi
116         movl    $FUTEX_WAIT, %esi
117         je      60f
118
119         movq    dep_mutex-cond_futex(%rdi), %r8
120         /* Requeue to a non-robust PI mutex if the PI bit is set and
121         the robust bit is not set.  */
122         movl    MUTEX_KIND(%r8), %eax
123         andl    $(ROBUST_BIT|PI_BIT), %eax
124         cmpl    $PI_BIT, %eax
125         jne     61f
126
127         movl    $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
128         movl    $SYS_futex, %eax
129         syscall
130
131         movl    $1, %r8d
132 #ifdef __ASSUME_REQUEUE_PI
133         jmp     62f
134 #else
135         cmpq    $-4095, %rax
136         jnae    62f
137
138 # ifndef __ASSUME_PRIVATE_FUTEX
139         movl    $FUTEX_WAIT, %esi
140 # endif
141 #endif
142
143 61:
144 #ifdef __ASSUME_PRIVATE_FUTEX
145         movl    $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
146 #else
147         orl     %fs:PRIVATE_FUTEX, %esi
148 #endif
149 60:     xorl    %r8d, %r8d
150         movl    $SYS_futex, %eax
151         syscall
152
153 62:     movl    (%rsp), %edi
154         callq   __pthread_disable_asynccancel
155 .LcleanupEND:
156
157         /* Lock.  */
158         movq    8(%rsp), %rdi
159         movl    $1, %esi
160         xorl    %eax, %eax
161         LOCK
162 #if cond_lock == 0
163         cmpxchgl %esi, (%rdi)
164 #else
165         cmpxchgl %esi, cond_lock(%rdi)
166 #endif
167         jnz     5f
168
169 6:      movl    broadcast_seq(%rdi), %edx
170
171         movq    woken_seq(%rdi), %rax
172
173         movq    wakeup_seq(%rdi), %r9
174
175         cmpl    4(%rsp), %edx
176         jne     16f
177
178         cmpq    24(%rsp), %r9
179         jbe     8b
180
181         cmpq    %rax, %r9
182         jna     8b
183
184         incq    woken_seq(%rdi)
185
186         /* Unlock */
187 16:     subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
188
189         /* Wake up a thread which wants to destroy the condvar object.  */
190         cmpq    $0xffffffffffffffff, total_seq(%rdi)
191         jne     17f
192         movl    cond_nwaiters(%rdi), %eax
193         andl    $~((1 << nwaiters_shift) - 1), %eax
194         jne     17f
195
196         addq    $cond_nwaiters, %rdi
197         cmpq    $-1, dep_mutex-cond_nwaiters(%rdi)
198         movl    $1, %edx
199 #ifdef __ASSUME_PRIVATE_FUTEX
200         movl    $FUTEX_WAKE, %eax
201         movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
202         cmove   %eax, %esi
203 #else
204         movl    $0, %eax
205         movl    %fs:PRIVATE_FUTEX, %esi
206         cmove   %eax, %esi
207         orl     $FUTEX_WAKE, %esi
208 #endif
209         movl    $SYS_futex, %eax
210         syscall
211         subq    $cond_nwaiters, %rdi
212
213 17:     LOCK
214 #if cond_lock == 0
215         decl    (%rdi)
216 #else
217         decl    cond_lock(%rdi)
218 #endif
219         jne     10f
220
221         /* If requeue_pi is used the kernel performs the locking of the
222            mutex. */
223 11:     movq    16(%rsp), %rdi
224         testl   %r8d, %r8d
225         jnz     18f
226
227         callq   __pthread_mutex_cond_lock
228
229 14:     leaq    FRAME_SIZE(%rsp), %rsp
230         cfi_adjust_cfa_offset(-FRAME_SIZE)
231
232         /* We return the result of the mutex_lock operation.  */
233         retq
234
235         cfi_adjust_cfa_offset(FRAME_SIZE)
236
237 18:     callq   __pthread_mutex_cond_lock_adjust
238         xorl    %eax, %eax
239         jmp     14b
240
241         /* Initial locking failed.  */
242 1:
243 #if cond_lock != 0
244         addq    $cond_lock, %rdi
245 #endif
246         cmpq    $-1, dep_mutex-cond_lock(%rdi)
247         movl    $LLL_PRIVATE, %eax
248         movl    $LLL_SHARED, %esi
249         cmovne  %eax, %esi
250         callq   __lll_lock_wait
251         jmp     2b
252
253         /* Unlock in loop requires wakeup.  */
254 3:
255 #if cond_lock != 0
256         addq    $cond_lock, %rdi
257 #endif
258         cmpq    $-1, dep_mutex-cond_lock(%rdi)
259         movl    $LLL_PRIVATE, %eax
260         movl    $LLL_SHARED, %esi
261         cmovne  %eax, %esi
262         /* The call preserves %rdx.  */
263         callq   __lll_unlock_wake
264 #if cond_lock != 0
265         subq    $cond_lock, %rdi
266 #endif
267         jmp     4b
268
269         /* Locking in loop failed.  */
270 5:
271 #if cond_lock != 0
272         addq    $cond_lock, %rdi
273 #endif
274         cmpq    $-1, dep_mutex-cond_lock(%rdi)
275         movl    $LLL_PRIVATE, %eax
276         movl    $LLL_SHARED, %esi
277         cmovne  %eax, %esi
278         callq   __lll_lock_wait
279 #if cond_lock != 0
280         subq    $cond_lock, %rdi
281 #endif
282         jmp     6b
283
284         /* Unlock after loop requires wakeup.  */
285 10:
286 #if cond_lock != 0
287         addq    $cond_lock, %rdi
288 #endif
289         cmpq    $-1, dep_mutex-cond_lock(%rdi)
290         movl    $LLL_PRIVATE, %eax
291         movl    $LLL_SHARED, %esi
292         cmovne  %eax, %esi
293         callq   __lll_unlock_wake
294         jmp     11b
295
296         /* The initial unlocking of the mutex failed.  */
297 12:     movq    %rax, %r10
298         movq    8(%rsp), %rdi
299         LOCK
300 #if cond_lock == 0
301         decl    (%rdi)
302 #else
303         decl    cond_lock(%rdi)
304 #endif
305         je      13f
306
307 #if cond_lock != 0
308         addq    $cond_lock, %rdi
309 #endif
310         cmpq    $-1, dep_mutex-cond_lock(%rdi)
311         movl    $LLL_PRIVATE, %eax
312         movl    $LLL_SHARED, %esi
313         cmovne  %eax, %esi
314         callq   __lll_unlock_wake
315
316 13:     movq    %r10, %rax
317         jmp     14b
318         .size   __pthread_cond_wait, .-__pthread_cond_wait
319 weak_alias(__pthread_cond_wait, pthread_cond_wait)
320
321
322         .align  16
323         .type   __condvar_cleanup1, @function
324         .globl  __condvar_cleanup1
325         .hidden __condvar_cleanup1
326 __condvar_cleanup1:
327         /* Stack frame:
328
329            rsp + 32
330                     +--------------------------+
331            rsp + 24 | unused                   |
332                     +--------------------------+
333            rsp + 16 | mutex pointer            |
334                     +--------------------------+
335            rsp +  8 | condvar pointer          |
336                     +--------------------------+
337            rsp +  4 | old broadcast_seq value  |
338                     +--------------------------+
339            rsp +  0 | old cancellation mode    |
340                     +--------------------------+
341         */
342
343         movq    %rax, 24(%rsp)
344
345         /* Get internal lock.  */
346         movq    8(%rsp), %rdi
347         movl    $1, %esi
348         xorl    %eax, %eax
349         LOCK
350 #if cond_lock == 0
351         cmpxchgl %esi, (%rdi)
352 #else
353         cmpxchgl %esi, cond_lock(%rdi)
354 #endif
355         jz      1f
356
357 #if cond_lock != 0
358         addq    $cond_lock, %rdi
359 #endif
360         cmpq    $-1, dep_mutex-cond_lock(%rdi)
361         movl    $LLL_PRIVATE, %eax
362         movl    $LLL_SHARED, %esi
363         cmovne  %eax, %esi
364         callq   __lll_lock_wait
365 #if cond_lock != 0
366         subq    $cond_lock, %rdi
367 #endif
368
369 1:      movl    broadcast_seq(%rdi), %edx
370         cmpl    4(%rsp), %edx
371         jne     3f
372
373         /* We increment the wakeup_seq counter only if it is lower than
374            total_seq.  If this is not the case the thread was woken and
375            then canceled.  In this case we ignore the signal.  */
376         movq    total_seq(%rdi), %rax
377         cmpq    wakeup_seq(%rdi), %rax
378         jbe     6f
379         incq    wakeup_seq(%rdi)
380         incl    cond_futex(%rdi)
381 6:      incq    woken_seq(%rdi)
382
383 3:      subl    $(1 << nwaiters_shift), cond_nwaiters(%rdi)
384
385         /* Wake up a thread which wants to destroy the condvar object.  */
386         xorl    %ecx, %ecx
387         cmpq    $0xffffffffffffffff, total_seq(%rdi)
388         jne     4f
389         movl    cond_nwaiters(%rdi), %eax
390         andl    $~((1 << nwaiters_shift) - 1), %eax
391         jne     4f
392
393         cmpq    $-1, dep_mutex(%rdi)
394         leaq    cond_nwaiters(%rdi), %rdi
395         movl    $1, %edx
396 #ifdef __ASSUME_PRIVATE_FUTEX
397         movl    $FUTEX_WAKE, %eax
398         movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
399         cmove   %eax, %esi
400 #else
401         movl    $0, %eax
402         movl    %fs:PRIVATE_FUTEX, %esi
403         cmove   %eax, %esi
404         orl     $FUTEX_WAKE, %esi
405 #endif
406         movl    $SYS_futex, %eax
407         syscall
408         subq    $cond_nwaiters, %rdi
409         movl    $1, %ecx
410
411 4:      LOCK
412 #if cond_lock == 0
413         decl    (%rdi)
414 #else
415         decl    cond_lock(%rdi)
416 #endif
417         je      2f
418 #if cond_lock != 0
419         addq    $cond_lock, %rdi
420 #endif
421         cmpq    $-1, dep_mutex-cond_lock(%rdi)
422         movl    $LLL_PRIVATE, %eax
423         movl    $LLL_SHARED, %esi
424         cmovne  %eax, %esi
425         /* The call preserves %rcx.  */
426         callq   __lll_unlock_wake
427
428         /* Wake up all waiters to make sure no signal gets lost.  */
429 2:      testl   %ecx, %ecx
430         jnz     5f
431         addq    $cond_futex, %rdi
432         cmpq    $-1, dep_mutex-cond_futex(%rdi)
433         movl    $0x7fffffff, %edx
434 #ifdef __ASSUME_PRIVATE_FUTEX
435         movl    $FUTEX_WAKE, %eax
436         movl    $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
437         cmove   %eax, %esi
438 #else
439         movl    $0, %eax
440         movl    %fs:PRIVATE_FUTEX, %esi
441         cmove   %eax, %esi
442         orl     $FUTEX_WAKE, %esi
443 #endif
444         movl    $SYS_futex, %eax
445         syscall
446
447 5:      movq    16(%rsp), %rdi
448         callq   __pthread_mutex_cond_lock
449
450         movq    24(%rsp), %rdi
451 .LcallUR:
452         call    _Unwind_Resume@PLT
453         hlt
454 .LENDCODE:
455         cfi_endproc
456         .size   __condvar_cleanup1, .-__condvar_cleanup1
457
458
459         .section .gcc_except_table,"a",@progbits
460 .LexceptSTART:
461         .byte   DW_EH_PE_omit                   # @LPStart format
462         .byte   DW_EH_PE_omit                   # @TType format
463         .byte   DW_EH_PE_uleb128                # call-site format
464         .uleb128 .Lcstend-.Lcstbegin
465 .Lcstbegin:
466         .uleb128 .LcleanupSTART-.LSTARTCODE
467         .uleb128 .LcleanupEND-.LcleanupSTART
468         .uleb128 __condvar_cleanup1-.LSTARTCODE
469         .uleb128  0
470         .uleb128 .LcallUR-.LSTARTCODE
471         .uleb128 .LENDCODE-.LcallUR
472         .uleb128 0
473         .uleb128  0
474 .Lcstend:
475
476
477 #ifdef SHARED
478         .hidden DW.ref.__gcc_personality_v0
479         .weak   DW.ref.__gcc_personality_v0
480         .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
481         .align  8
482         .type   DW.ref.__gcc_personality_v0, @object
483         .size   DW.ref.__gcc_personality_v0, 8
484 DW.ref.__gcc_personality_v0:
485         .quad   __gcc_personality_v0
486 #endif