Revert {send,sendm,recv,recvm}msg conformance changes
[glibc.git] / sysdeps / unix / sysv / linux / i386 / pthread_cond_wait.S
blob50167188018882ea7f648e34bf05f60af13b4881
1 /* Copyright (C) 2002-2016 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, see
17    <http://www.gnu.org/licenses/>.  */
19 #include <sysdep.h>
20 #include <shlib-compat.h>
21 #include <lowlevellock.h>
22 #include <lowlevelcond.h>
23 #include <tcb-offsets.h>
24 #include <pthread-errnos.h>
25 #include <pthread-pi-defines.h>
26 #include <kernel-features.h>
27 #include <stap-probe.h>
30         .text
32 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */
33         .globl  __pthread_cond_wait
34         .type   __pthread_cond_wait, @function
35         .align  16
36 __pthread_cond_wait:
37 .LSTARTCODE:
38         cfi_startproc
39 #ifdef SHARED
40         cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
41                         DW.ref.__gcc_personality_v0)
42         cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
43 #else
44         cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
45         cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
46 #endif
48         pushl   %ebp
49         cfi_adjust_cfa_offset(4)
50         cfi_rel_offset(%ebp, 0)
51         pushl   %edi
52         cfi_adjust_cfa_offset(4)
53         cfi_rel_offset(%edi, 0)
54         pushl   %esi
55         cfi_adjust_cfa_offset(4)
56         cfi_rel_offset(%esi, 0)
57         pushl   %ebx
58         cfi_adjust_cfa_offset(4)
59         cfi_rel_offset(%ebx, 0)
61         xorl    %esi, %esi
62         movl    20(%esp), %ebx
64         LIBC_PROBE (cond_wait, 2, 24(%esp), %ebx)
66         /* Get internal lock.  */
67         movl    $1, %edx
68         xorl    %eax, %eax
69         LOCK
70 #if cond_lock == 0
71         cmpxchgl %edx, (%ebx)
72 #else
73         cmpxchgl %edx, cond_lock(%ebx)
74 #endif
75         jnz     1f
77         /* Store the reference to the mutex.  If there is already a
78            different value in there this is a bad user bug.  */
79 2:      cmpl    $-1, dep_mutex(%ebx)
80         movl    24(%esp), %eax
81         je      15f
82         movl    %eax, dep_mutex(%ebx)
84         /* Unlock the mutex.  */
85 15:     xorl    %edx, %edx
86         call    __pthread_mutex_unlock_usercnt
88         testl   %eax, %eax
89         jne     12f
91         addl    $1, total_seq(%ebx)
92         adcl    $0, total_seq+4(%ebx)
93         addl    $1, cond_futex(%ebx)
94         addl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
96 #define FRAME_SIZE 20
97         subl    $FRAME_SIZE, %esp
98         cfi_adjust_cfa_offset(FRAME_SIZE)
99         cfi_remember_state
101         /* Get and store current wakeup_seq value.  */
102         movl    wakeup_seq(%ebx), %edi
103         movl    wakeup_seq+4(%ebx), %edx
104         movl    broadcast_seq(%ebx), %eax
105         movl    %edi, 4(%esp)
106         movl    %edx, 8(%esp)
107         movl    %eax, 12(%esp)
109         /* Reset the pi-requeued flag.  */
110 8:      movl    $0, 16(%esp)
111         movl    cond_futex(%ebx), %ebp
113         /* Unlock.  */
114         LOCK
115 #if cond_lock == 0
116         subl    $1, (%ebx)
117 #else
118         subl    $1, cond_lock(%ebx)
119 #endif
120         jne     3f
122 .LcleanupSTART:
123 4:      call    __pthread_enable_asynccancel
124         movl    %eax, (%esp)
126         xorl    %ecx, %ecx
127         cmpl    $-1, dep_mutex(%ebx)
128         sete    %cl
129         je      18f
131         movl    dep_mutex(%ebx), %edi
132         /* Requeue to a non-robust PI mutex if the PI bit is set and
133            the robust bit is not set.  */
134         movl    MUTEX_KIND(%edi), %eax
135         andl    $(ROBUST_BIT|PI_BIT), %eax
136         cmpl    $PI_BIT, %eax
137         jne     18f
139         movl    $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
140         movl    %ebp, %edx
141         xorl    %esi, %esi
142         addl    $cond_futex, %ebx
143 .Ladd_cond_futex_pi:
144         movl    $SYS_futex, %eax
145         ENTER_KERNEL
146         subl    $cond_futex, %ebx
147 .Lsub_cond_futex_pi:
148         /* Set the pi-requeued flag only if the kernel has returned 0. The
149            kernel does not hold the mutex on error.  */
150         cmpl    $0, %eax
151         sete    16(%esp)
152         je      19f
154         /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
155            successfully, it has already locked the mutex for us and the
156            pi_flag (16(%esp)) is set to denote that fact.  However, if another
157            thread changed the futex value before we entered the wait, the
158            syscall may return an EAGAIN and the mutex is not locked.  We go
159            ahead with a success anyway since later we look at the pi_flag to
160            decide if we got the mutex or not.  The sequence numbers then make
161            sure that only one of the threads actually wake up.  We retry using
162            normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
163            and PI futexes don't mix.
165            Note that we don't check for EAGAIN specifically; we assume that the
166            only other error the futex function could return is EAGAIN since
167            anything else would mean an error in our function.  It is too
168            expensive to do that check for every call (which is  quite common in
169            case of a large number of threads), so it has been skipped.  */
170         cmpl    $-ENOSYS, %eax
171         jne     19f
172         xorl    %ecx, %ecx
174 18:     subl    $1, %ecx
175 #ifdef __ASSUME_PRIVATE_FUTEX
176         andl    $FUTEX_PRIVATE_FLAG, %ecx
177 #else
178         andl    %gs:PRIVATE_FUTEX, %ecx
179 #endif
180 #if FUTEX_WAIT != 0
181         addl    $FUTEX_WAIT, %ecx
182 #endif
183         movl    %ebp, %edx
184         addl    $cond_futex, %ebx
185 .Ladd_cond_futex:
186         movl    $SYS_futex, %eax
187         ENTER_KERNEL
188         subl    $cond_futex, %ebx
189 .Lsub_cond_futex:
191 19:     movl    (%esp), %eax
192         call    __pthread_disable_asynccancel
193 .LcleanupEND:
195         /* Lock.  */
196         movl    $1, %edx
197         xorl    %eax, %eax
198         LOCK
199 #if cond_lock == 0
200         cmpxchgl %edx, (%ebx)
201 #else
202         cmpxchgl %edx, cond_lock(%ebx)
203 #endif
204         jnz     5f
206 6:      movl    broadcast_seq(%ebx), %eax
207         cmpl    12(%esp), %eax
208         jne     16f
210         movl    woken_seq(%ebx), %eax
211         movl    woken_seq+4(%ebx), %ecx
213         movl    wakeup_seq(%ebx), %edi
214         movl    wakeup_seq+4(%ebx), %edx
216         cmpl    8(%esp), %edx
217         jne     7f
218         cmpl    4(%esp), %edi
219         je      22f
221 7:      cmpl    %ecx, %edx
222         jne     9f
223         cmp     %eax, %edi
224         je      22f
226 9:      addl    $1, woken_seq(%ebx)
227         adcl    $0, woken_seq+4(%ebx)
229         /* Unlock */
230 16:     subl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
232         /* Wake up a thread which wants to destroy the condvar object.  */
233         movl    total_seq(%ebx), %eax
234         andl    total_seq+4(%ebx), %eax
235         cmpl    $0xffffffff, %eax
236         jne     17f
237         movl    cond_nwaiters(%ebx), %eax
238         andl    $~((1 << nwaiters_shift) - 1), %eax
239         jne     17f
241         addl    $cond_nwaiters, %ebx
242         movl    $SYS_futex, %eax
243 #if FUTEX_PRIVATE_FLAG > 255
244         xorl    %ecx, %ecx
245 #endif
246         cmpl    $-1, dep_mutex-cond_nwaiters(%ebx)
247         sete    %cl
248         subl    $1, %ecx
249 #ifdef __ASSUME_PRIVATE_FUTEX
250         andl    $FUTEX_PRIVATE_FLAG, %ecx
251 #else
252         andl    %gs:PRIVATE_FUTEX, %ecx
253 #endif
254         addl    $FUTEX_WAKE, %ecx
255         movl    $1, %edx
256         ENTER_KERNEL
257         subl    $cond_nwaiters, %ebx
259 17:     LOCK
260 #if cond_lock == 0
261         subl    $1, (%ebx)
262 #else
263         subl    $1, cond_lock(%ebx)
264 #endif
265         jne     10f
267         /* With requeue_pi, the mutex lock is held in the kernel.  */
268 11:     movl    24+FRAME_SIZE(%esp), %eax
269         movl    16(%esp), %ecx
270         testl   %ecx, %ecx
271         jnz     21f
273         call    __pthread_mutex_cond_lock
274 20:     addl    $FRAME_SIZE, %esp
275         cfi_adjust_cfa_offset(-FRAME_SIZE);
277 14:     popl    %ebx
278         cfi_adjust_cfa_offset(-4)
279         cfi_restore(%ebx)
280         popl    %esi
281         cfi_adjust_cfa_offset(-4)
282         cfi_restore(%esi)
283         popl    %edi
284         cfi_adjust_cfa_offset(-4)
285         cfi_restore(%edi)
286         popl    %ebp
287         cfi_adjust_cfa_offset(-4)
288         cfi_restore(%ebp)
290         /* We return the result of the mutex_lock operation.  */
291         ret
293         cfi_restore_state
295 21:     call    __pthread_mutex_cond_lock_adjust
296         xorl    %eax, %eax
297         jmp     20b
299         cfi_adjust_cfa_offset(-FRAME_SIZE);
301         /* We need to go back to futex_wait.  If we're using requeue_pi, then
302            release the mutex we had acquired and go back.  */
303 22:     movl    16(%esp), %edx
304         test    %edx, %edx
305         jz      8b
307         /* Adjust the mutex values first and then unlock it.  The unlock
308            should always succeed or else the kernel did not lock the mutex
309            correctly.  */
310         movl    dep_mutex(%ebx), %eax
311         call    __pthread_mutex_cond_lock_adjust
312         movl    dep_mutex(%ebx), %eax
313         xorl    %edx, %edx
314         call    __pthread_mutex_unlock_usercnt
315         jmp     8b
317         /* Initial locking failed.  */
319 #if cond_lock == 0
320         movl    %ebx, %edx
321 #else
322         leal    cond_lock(%ebx), %edx
323 #endif
324 #if (LLL_SHARED-LLL_PRIVATE) > 255
325         xorl    %ecx, %ecx
326 #endif
327         cmpl    $-1, dep_mutex(%ebx)
328         setne   %cl
329         subl    $1, %ecx
330         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
331 #if LLL_PRIVATE != 0
332         addl    $LLL_PRIVATE, %ecx
333 #endif
334         call    __lll_lock_wait
335         jmp     2b
337         /* The initial unlocking of the mutex failed.  */
339         LOCK
340 #if cond_lock == 0
341         subl    $1, (%ebx)
342 #else
343         subl    $1, cond_lock(%ebx)
344 #endif
345         jne     14b
347         movl    %eax, %esi
348 #if cond_lock == 0
349         movl    %ebx, %eax
350 #else
351         leal    cond_lock(%ebx), %eax
352 #endif
353 #if (LLL_SHARED-LLL_PRIVATE) > 255
354         xorl    %ecx, %ecx
355 #endif
356         cmpl    $-1, dep_mutex(%ebx)
357         setne   %cl
358         subl    $1, %ecx
359         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
360 #if LLL_PRIVATE != 0
361         addl    $LLL_PRIVATE, %ecx
362 #endif
363         call    __lll_unlock_wake
365         movl    %esi, %eax
366         jmp     14b
368         cfi_adjust_cfa_offset(FRAME_SIZE)
370         /* Unlock in loop requires wakeup.  */
372 #if cond_lock == 0
373         movl    %ebx, %eax
374 #else
375         leal    cond_lock(%ebx), %eax
376 #endif
377 #if (LLL_SHARED-LLL_PRIVATE) > 255
378         xorl    %ecx, %ecx
379 #endif
380         cmpl    $-1, dep_mutex(%ebx)
381         setne   %cl
382         subl    $1, %ecx
383         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
384 #if LLL_PRIVATE != 0
385         addl    $LLL_PRIVATE, %ecx
386 #endif
387         call    __lll_unlock_wake
388         jmp     4b
390         /* Locking in loop failed.  */
392 #if cond_lock == 0
393         movl    %ebx, %edx
394 #else
395         leal    cond_lock(%ebx), %edx
396 #endif
397 #if (LLL_SHARED-LLL_PRIVATE) > 255
398         xorl    %ecx, %ecx
399 #endif
400         cmpl    $-1, dep_mutex(%ebx)
401         setne   %cl
402         subl    $1, %ecx
403         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
404 #if LLL_PRIVATE != 0
405         addl    $LLL_PRIVATE, %ecx
406 #endif
407         call    __lll_lock_wait
408         jmp     6b
410         /* Unlock after loop requires wakeup.  */
412 #if cond_lock == 0
413         movl    %ebx, %eax
414 #else
415         leal    cond_lock(%ebx), %eax
416 #endif
417 #if (LLL_SHARED-LLL_PRIVATE) > 255
418         xorl    %ecx, %ecx
419 #endif
420         cmpl    $-1, dep_mutex(%ebx)
421         setne   %cl
422         subl    $1, %ecx
423         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
424 #if LLL_PRIVATE != 0
425         addl    $LLL_PRIVATE, %ecx
426 #endif
427         call    __lll_unlock_wake
428         jmp     11b
430         .size   __pthread_cond_wait, .-__pthread_cond_wait
431 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
432                   GLIBC_2_3_2)
435         .type   __condvar_w_cleanup2, @function
436 __condvar_w_cleanup2:
437         subl    $cond_futex, %ebx
438         .size   __condvar_w_cleanup2, .-__condvar_w_cleanup2
439 .LSbl4:
440         .type   __condvar_w_cleanup, @function
441 __condvar_w_cleanup:
442         movl    %eax, %esi
444         /* Get internal lock.  */
445         movl    $1, %edx
446         xorl    %eax, %eax
447         LOCK
448 #if cond_lock == 0
449         cmpxchgl %edx, (%ebx)
450 #else
451         cmpxchgl %edx, cond_lock(%ebx)
452 #endif
453         jz      1f
455 #if cond_lock == 0
456         movl    %ebx, %edx
457 #else
458         leal    cond_lock(%ebx), %edx
459 #endif
460 #if (LLL_SHARED-LLL_PRIVATE) > 255
461         xorl    %ecx, %ecx
462 #endif
463         cmpl    $-1, dep_mutex(%ebx)
464         setne   %cl
465         subl    $1, %ecx
466         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
467 #if LLL_PRIVATE != 0
468         addl    $LLL_PRIVATE, %ecx
469 #endif
470         call    __lll_lock_wait
472 1:      movl    broadcast_seq(%ebx), %eax
473         cmpl    12(%esp), %eax
474         jne     3f
476         /* We increment the wakeup_seq counter only if it is lower than
477            total_seq.  If this is not the case the thread was woken and
478            then canceled.  In this case we ignore the signal.  */
479         movl    total_seq(%ebx), %eax
480         movl    total_seq+4(%ebx), %edi
481         cmpl    wakeup_seq+4(%ebx), %edi
482         jb      6f
483         ja      7f
484         cmpl    wakeup_seq(%ebx), %eax
485         jbe     7f
487 6:      addl    $1, wakeup_seq(%ebx)
488         adcl    $0, wakeup_seq+4(%ebx)
489         addl    $1, cond_futex(%ebx)
491 7:      addl    $1, woken_seq(%ebx)
492         adcl    $0, woken_seq+4(%ebx)
494 3:      subl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
496         /* Wake up a thread which wants to destroy the condvar object.  */
497         xorl    %edi, %edi
498         movl    total_seq(%ebx), %eax
499         andl    total_seq+4(%ebx), %eax
500         cmpl    $0xffffffff, %eax
501         jne     4f
502         movl    cond_nwaiters(%ebx), %eax
503         andl    $~((1 << nwaiters_shift) - 1), %eax
504         jne     4f
506         addl    $cond_nwaiters, %ebx
507         movl    $SYS_futex, %eax
508 #if FUTEX_PRIVATE_FLAG > 255
509         xorl    %ecx, %ecx
510 #endif
511         cmpl    $-1, dep_mutex-cond_nwaiters(%ebx)
512         sete    %cl
513         subl    $1, %ecx
514 #ifdef __ASSUME_PRIVATE_FUTEX
515         andl    $FUTEX_PRIVATE_FLAG, %ecx
516 #else
517         andl    %gs:PRIVATE_FUTEX, %ecx
518 #endif
519         addl    $FUTEX_WAKE, %ecx
520         movl    $1, %edx
521         ENTER_KERNEL
522         subl    $cond_nwaiters, %ebx
523         movl    $1, %edi
525 4:      LOCK
526 #if cond_lock == 0
527         subl    $1, (%ebx)
528 #else
529         subl    $1, cond_lock(%ebx)
530 #endif
531         je      2f
533 #if cond_lock == 0
534         movl    %ebx, %eax
535 #else
536         leal    cond_lock(%ebx), %eax
537 #endif
538 #if (LLL_SHARED-LLL_PRIVATE) > 255
539         xorl    %ecx, %ecx
540 #endif
541         cmpl    $-1, dep_mutex(%ebx)
542         setne   %cl
543         subl    $1, %ecx
544         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
545 #if LLL_PRIVATE != 0
546         addl    $LLL_PRIVATE, %ecx
547 #endif
548         call    __lll_unlock_wake
550         /* Wake up all waiters to make sure no signal gets lost.  */
551 2:      testl   %edi, %edi
552         jnz     5f
553         addl    $cond_futex, %ebx
554 #if FUTEX_PRIVATE_FLAG > 255
555         xorl    %ecx, %ecx
556 #endif
557         cmpl    $-1, dep_mutex-cond_futex(%ebx)
558         sete    %cl
559         subl    $1, %ecx
560 #ifdef __ASSUME_PRIVATE_FUTEX
561         andl    $FUTEX_PRIVATE_FLAG, %ecx
562 #else
563         andl    %gs:PRIVATE_FUTEX, %ecx
564 #endif
565         addl    $FUTEX_WAKE, %ecx
566         movl    $SYS_futex, %eax
567         movl    $0x7fffffff, %edx
568         ENTER_KERNEL
570         /* Lock the mutex only if we don't own it already.  This only happens
571            in case of PI mutexes, if we got cancelled after a successful
572            return of the futex syscall and before disabling async
573            cancellation.  */
574 5:      movl    24+FRAME_SIZE(%esp), %eax
575         movl    MUTEX_KIND(%eax), %ebx
576         andl    $(ROBUST_BIT|PI_BIT), %ebx
577         cmpl    $PI_BIT, %ebx
578         jne     8f
580         movl    (%eax), %ebx
581         andl    $TID_MASK, %ebx
582         cmpl    %ebx, %gs:TID
583         jne     8f
584         /* We managed to get the lock.  Fix it up before returning.  */
585         call    __pthread_mutex_cond_lock_adjust
586         jmp     9f
588 8:      call    __pthread_mutex_cond_lock
590 9:      movl    %esi, (%esp)
591 .LcallUR:
592         call    _Unwind_Resume
593         hlt
594 .LENDCODE:
595         cfi_endproc
596         .size   __condvar_w_cleanup, .-__condvar_w_cleanup
599         .section .gcc_except_table,"a",@progbits
600 .LexceptSTART:
601         .byte   DW_EH_PE_omit                   # @LPStart format (omit)
602         .byte   DW_EH_PE_omit                   # @TType format (omit)
603         .byte   DW_EH_PE_sdata4                 # call-site format
604                                                 # DW_EH_PE_sdata4
605         .uleb128 .Lcstend-.Lcstbegin
606 .Lcstbegin:
607         .long   .LcleanupSTART-.LSTARTCODE
608         .long   .Ladd_cond_futex_pi-.LcleanupSTART
609         .long   __condvar_w_cleanup-.LSTARTCODE
610         .uleb128  0
611         .long   .Ladd_cond_futex_pi-.LSTARTCODE
612         .long   .Lsub_cond_futex_pi-.Ladd_cond_futex_pi
613         .long   __condvar_w_cleanup2-.LSTARTCODE
614         .uleb128  0
615         .long   .Lsub_cond_futex_pi-.LSTARTCODE
616         .long   .Ladd_cond_futex-.Lsub_cond_futex_pi
617         .long   __condvar_w_cleanup-.LSTARTCODE
618         .uleb128  0
619         .long   .Ladd_cond_futex-.LSTARTCODE
620         .long   .Lsub_cond_futex-.Ladd_cond_futex
621         .long   __condvar_w_cleanup2-.LSTARTCODE
622         .uleb128  0
623         .long   .Lsub_cond_futex-.LSTARTCODE
624         .long   .LcleanupEND-.Lsub_cond_futex
625         .long   __condvar_w_cleanup-.LSTARTCODE
626         .uleb128  0
627         .long   .LcallUR-.LSTARTCODE
628         .long   .LENDCODE-.LcallUR
629         .long   0
630         .uleb128  0
631 .Lcstend:
633 #ifdef SHARED
634         .hidden DW.ref.__gcc_personality_v0
635         .weak   DW.ref.__gcc_personality_v0
636         .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
637         .align 4
638         .type   DW.ref.__gcc_personality_v0, @object
639         .size   DW.ref.__gcc_personality_v0, 4
640 DW.ref.__gcc_personality_v0:
641         .long   __gcc_personality_v0
642 #endif