1 /* Copyright (C) 2002, 2003, 2004, 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
21 #include <shlib-compat.h>
22 #include <lowlevellock.h>
23 #include <lowlevelcond.h>
24 #include <pthread-errnos.h>
25 #include <kernel-features.h>
30 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
31 const struct timespec *abstime) */
32 .globl __pthread_cond_timedwait
33 .type __pthread_cond_timedwait, @function
35 __pthread_cond_timedwait:
49 cmpl $1000000000, 4(%ebp)
53 /* Get internal lock. */
60 cmpxchgl %edx, cond_lock(%ebx)
64 /* Store the reference to the mutex. If there is already a
65 different value in there this is a bad user bug. */
66 2: cmpl $-1, dep_mutex(%ebx)
69 movl %eax, dep_mutex(%ebx)
71 /* Unlock the mutex. */
73 call __pthread_mutex_unlock_usercnt
78 addl $1, total_seq(%ebx)
79 adcl $0, total_seq+4(%ebx)
80 addl $1, cond_futex(%ebx)
81 addl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
84 subl $FRAME_SIZE, %esp
87 /* Get and store current wakeup_seq value. */
88 movl wakeup_seq(%ebx), %edi
89 movl wakeup_seq+4(%ebx), %edx
90 movl broadcast_seq(%ebx), %eax
95 /* Get the current time. */
97 #ifdef __NR_clock_gettime
98 /* Get the clock number. */
99 movl cond_nwaiters(%ebx), %ebx
100 andl $((1 << nwaiters_shift) - 1), %ebx
101 /* Only clocks 0 and 1 are allowed so far. Both are handled in the
104 movl $__NR_clock_gettime, %eax
106 # ifndef __ASSUME_POSIX_TIMERS
112 /* Compute relative timeout. */
118 /* Get the current time. */
121 movl $__NR_gettimeofday, %eax
125 /* Compute relative timeout. */
128 mul %edx /* Milli seconds to nano seconds. */
135 addl $1000000000, %edx
138 movl $-ETIMEDOUT, %esi
141 /* Store relative timeout. */
142 21: movl %ecx, 4(%esp)
145 movl cond_futex(%ebx), %edi
152 subl $1, cond_lock(%ebx)
157 4: call __pthread_enable_asynccancel
161 #if FUTEX_PRIVATE_FLAG > 255
164 cmpl $-1, dep_mutex(%ebx)
167 #ifdef __ASSUME_PRIVATE_FUTEX
168 andl $FUTEX_PRIVATE_FLAG, %ecx
170 andl %gs:PRIVATE_FUTEX, %ecx
173 addl $FUTEX_WAIT, %ecx
176 addl $cond_futex, %ebx
178 movl $SYS_futex, %eax
180 subl $cond_futex, %ebx
185 call __pthread_disable_asynccancel
193 cmpxchgl %edx, (%ebx)
195 cmpxchgl %edx, cond_lock(%ebx)
199 6: movl broadcast_seq(%ebx), %eax
203 movl woken_seq(%ebx), %eax
204 movl woken_seq+4(%ebx), %ecx
206 movl wakeup_seq(%ebx), %edi
207 movl wakeup_seq+4(%ebx), %edx
219 15: cmpl $-ETIMEDOUT, %esi
222 addl $1, wakeup_seq(%ebx)
223 adcl $0, wakeup_seq+4(%ebx)
224 addl $1, cond_futex(%ebx)
225 movl $ETIMEDOUT, %esi
232 14: addl $1, woken_seq(%ebx)
233 adcl $0, woken_seq+4(%ebx)
235 24: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
237 /* Wake up a thread which wants to destroy the condvar object. */
238 movl total_seq(%ebx), %eax
239 andl total_seq+4(%ebx), %eax
240 cmpl $0xffffffff, %eax
242 movl cond_nwaiters(%ebx), %eax
243 andl $~((1 << nwaiters_shift) - 1), %eax
246 addl $cond_nwaiters, %ebx
247 movl $SYS_futex, %eax
248 #if FUTEX_PRIVATE_FLAG > 255
251 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
254 #ifdef __ASSUME_PRIVATE_FUTEX
255 andl $FUTEX_PRIVATE_FLAG, %ecx
257 andl %gs:PRIVATE_FUTEX, %ecx
259 addl $FUTEX_WAKE, %ecx
262 subl $cond_nwaiters, %ebx
268 subl $1, cond_lock(%ebx)
272 /* Remove cancellation handler. */
273 11: movl 24+FRAME_SIZE(%esp), %eax
274 call __pthread_mutex_cond_lock
275 addl $FRAME_SIZE, %esp
278 /* We return the result of the mutex_lock operation if it failed. */
297 popl %ecx; nacljmp %ecx
299 /* Initial locking failed. */
305 leal cond_lock(%ebx), %edx
307 #if (LLL_SHARED-LLL_PRIVATE) > 255
310 cmpl $-1, dep_mutex(%ebx)
313 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
315 addl $LLL_PRIVATE, %ecx
320 /* Unlock in loop requires wakeup. */
326 leal cond_lock(%ebx), %eax
328 #if (LLL_SHARED-LLL_PRIVATE) > 255
331 cmpl $-1, dep_mutex(%ebx)
334 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
336 addl $LLL_PRIVATE, %ecx
338 call __lll_unlock_wake
341 /* Locking in loop failed. */
346 leal cond_lock(%ebx), %edx
348 #if (LLL_SHARED-LLL_PRIVATE) > 255
351 cmpl $-1, dep_mutex(%ebx)
354 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
356 addl $LLL_PRIVATE, %ecx
361 /* Unlock after loop requires wakeup. */
366 leal cond_lock(%ebx), %eax
368 #if (LLL_SHARED-LLL_PRIVATE) > 255
371 cmpl $-1, dep_mutex(%ebx)
374 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
376 addl $LLL_PRIVATE, %ecx
378 call __lll_unlock_wake
381 /* The initial unlocking of the mutex failed. */
388 subl $1, cond_lock(%ebx)
396 leal cond_lock(%ebx), %eax
398 #if (LLL_SHARED-LLL_PRIVATE) > 255
401 cmpl $-1, dep_mutex(%ebx)
404 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
406 addl $LLL_PRIVATE, %ecx
408 call __lll_unlock_wake
413 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
414 /* clock_gettime not available. */
416 19: leal 4(%esp), %ebx
418 movl $__NR_gettimeofday, %eax
422 /* Compute relative timeout. */
425 mul %edx /* Milli seconds to nano seconds. */
431 addl $1000000000, %edx
434 movl $-ETIMEDOUT, %esi
438 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
439 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
443 .type __condvar_tw_cleanup2, @function
444 __condvar_tw_cleanup2:
445 subl $cond_futex, %ebx
447 .size __condvar_tw_cleanup2, .-__condvar_tw_cleanup2
448 .type __condvar_tw_cleanup, @function
449 __condvar_tw_cleanup:
452 /* Get internal lock. */
457 cmpxchgl %edx, (%ebx)
459 cmpxchgl %edx, cond_lock(%ebx)
466 leal cond_lock(%ebx), %edx
468 #if (LLL_SHARED-LLL_PRIVATE) > 255
471 cmpl $-1, dep_mutex(%ebx)
474 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
476 addl $LLL_PRIVATE, %ecx
480 1: movl broadcast_seq(%ebx), %eax
484 /* We increment the wakeup_seq counter only if it is lower than
485 total_seq. If this is not the case the thread was woken and
486 then canceled. In this case we ignore the signal. */
487 movl total_seq(%ebx), %eax
488 movl total_seq+4(%ebx), %edi
489 cmpl wakeup_seq+4(%ebx), %edi
492 cmpl wakeup_seq(%ebx), %eax
495 6: addl $1, wakeup_seq(%ebx)
496 adcl $0, wakeup_seq+4(%ebx)
497 addl $1, cond_futex(%ebx)
499 7: addl $1, woken_seq(%ebx)
500 adcl $0, woken_seq+4(%ebx)
502 3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
504 /* Wake up a thread which wants to destroy the condvar object. */
506 movl total_seq(%ebx), %eax
507 andl total_seq+4(%ebx), %eax
508 cmpl $0xffffffff, %eax
510 movl cond_nwaiters(%ebx), %eax
511 andl $~((1 << nwaiters_shift) - 1), %eax
514 addl $cond_nwaiters, %ebx
515 movl $SYS_futex, %eax
516 #if FUTEX_PRIVATE_FLAG > 255
519 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
522 #ifdef __ASSUME_PRIVATE_FUTEX
523 andl $FUTEX_PRIVATE_FLAG, %ecx
525 andl %gs:PRIVATE_FUTEX, %ecx
527 addl $FUTEX_WAKE, %ecx
530 subl $cond_nwaiters, %ebx
537 subl $1, cond_lock(%ebx)
544 leal cond_lock(%ebx), %eax
546 #if (LLL_SHARED-LLL_PRIVATE) > 255
549 cmpl $-1, dep_mutex(%ebx)
552 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
554 addl $LLL_PRIVATE, %ecx
556 call __lll_unlock_wake
558 /* Wake up all waiters to make sure no signal gets lost. */
561 addl $cond_futex, %ebx
562 #if FUTEX_PRIVATE_FLAG > 255
565 cmpl $-1, dep_mutex-cond_futex(%ebx)
568 #ifdef __ASSUME_PRIVATE_FUTEX
569 andl $FUTEX_PRIVATE_FLAG, %ecx
571 andl %gs:PRIVATE_FUTEX, %ecx
573 addl $FUTEX_WAKE, %ecx
574 movl $SYS_futex, %eax
575 movl $0x7fffffff, %edx
578 5: movl 24+FRAME_SIZE(%esp), %eax
579 call __pthread_mutex_cond_lock
586 .size __condvar_tw_cleanup, .-__condvar_tw_cleanup
589 .section .gcc_except_table,"a",@progbits
591 .byte 0xff # @LPStart format (omit)
592 .byte 0xff # @TType format (omit)
593 .byte 0x0b # call-site format
595 .uleb128 .Lcstend-.Lcstbegin
597 .long .LcleanupSTART-.LSTARTCODE
598 .long .Ladd_cond_futex-.LcleanupSTART
599 .long __condvar_tw_cleanup-.LSTARTCODE
601 .long .Ladd_cond_futex-.LSTARTCODE
602 .long .Lsub_cond_futex-.Ladd_cond_futex
603 .long __condvar_tw_cleanup2-.LSTARTCODE
605 .long .Lsub_cond_futex-.LSTARTCODE
606 .long .LcleanupEND-.Lsub_cond_futex
607 .long __condvar_tw_cleanup-.LSTARTCODE
609 .long .LcallUR-.LSTARTCODE
610 .long .LENDCODE-.LcallUR
616 .section .eh_frame,"a",@progbits
618 .long L(ENDCIE)-L(STARTCIE) # Length of the CIE.
621 .byte 1 # Version number.
623 .string "zPLR" # NUL-terminated augmentation
626 .string "zPL" # NUL-terminated augmentation
629 .uleb128 1 # Code alignment factor.
630 .sleb128 -4 # Data alignment factor.
631 .byte 8 # Return address register
634 .uleb128 7 # Augmentation value length.
635 .byte 0x9b # Personality: DW_EH_PE_pcrel
637 # + DW_EH_PE_indirect
638 .long DW.ref.__gcc_personality_v0-.
639 .byte 0x1b # LSDA Encoding: DW_EH_PE_pcrel
641 .byte 0x1b # FDE Encoding: DW_EH_PE_pcrel
644 .uleb128 6 # Augmentation value length.
645 .byte 0x0 # Personality: absolute
646 .long __gcc_personality_v0
647 .byte 0x0 # LSDA Encoding: absolute
649 .byte 0x0c # DW_CFA_def_cfa
652 .byte 0x88 # DW_CFA_offset, column 0x8
657 .long .LENDFDE-.LSTARTFDE # Length of the FDE.
659 .long .LSTARTFDE-.LSTARTFRAME # CIE pointer.
661 .long .LSTARTCODE-. # PC-relative start address
664 .long .LSTARTCODE # Start address of the code.
666 .long .LENDCODE-.LSTARTCODE # Length of the code.
667 .uleb128 4 # Augmentation size
669 .long .LexceptSTART-.
673 .byte 0x40+.Lpush_ebp-.LSTARTCODE # DW_CFA_advance_loc+N
674 .byte 14 # DW_CFA_def_cfa_offset
676 .byte 0x85 # DW_CFA_offset %ebp
678 .byte 0x40+ .Lpush_edi-.Lpush_ebp # DW_CFA_advance_loc+N
679 .byte 14 # DW_CFA_def_cfa_offset
681 .byte 0x87 # DW_CFA_offset %edi
683 .byte 0x40+.Lpush_esi-.Lpush_edi # DW_CFA_advance_loc+N
684 .byte 14 # DW_CFA_def_cfa_offset
686 .byte 0x86 # DW_CFA_offset %esi
688 .byte 0x40+.Lpush_ebx-.Lpush_esi # DW_CFA_advance_loc+N
689 .byte 14 # DW_CFA_def_cfa_offset
691 .byte 0x83 # DW_CFA_offset %ebx
693 .byte 4 # DW_CFA_advance_loc4
694 .4byte .Lsubl-.Lpush_ebx
695 .byte 14 # DW_CFA_def_cfa_offset
696 .uleb128 20+FRAME_SIZE
697 .byte 4 # DW_CFA_advance_loc4
699 .byte 14 # DW_CFA_def_cfa_offset
701 .byte 0x40+.Lpop_ebx-.Laddl # DW_CFA_advance_loc+N
702 .byte 14 # DW_CFA_def_cfa_offset
704 .byte 0xc3 # DW_CFA_restore %ebx
705 .byte 0x40+.Lpop_esi-.Lpop_ebx # DW_CFA_advance_loc+N
706 .byte 14 # DW_CFA_def_cfa_offset
708 .byte 0xc6 # DW_CFA_restore %esi
709 .byte 0x40+.Lpop_edi-.Lpop_esi # DW_CFA_advance_loc+N
710 .byte 14 # DW_CFA_def_cfa_offset
712 .byte 0xc7 # DW_CFA_restore %edi
713 .byte 0x40+.Lpop_ebp-.Lpop_edi # DW_CFA_advance_loc+N
714 .byte 14 # DW_CFA_def_cfa_offset
716 .byte 0xc5 # DW_CFA_restore %ebp
717 .byte 0x40+.LSbl1-.Lpop_edi # DW_CFA_advance_loc+N
718 .byte 14 # DW_CFA_def_cfa_offset
720 .byte 4 # DW_CFA_advance_loc4
722 .byte 14 # DW_CFA_def_cfa_offset
723 .uleb128 20+FRAME_SIZE
724 .byte 0x85 # DW_CFA_offset %ebp
726 .byte 0x87 # DW_CFA_offset %edi
728 .byte 0x86 # DW_CFA_offset %esi
730 .byte 0x83 # DW_CFA_offset %ebx
732 .byte 4 # DW_CFA_advance_loc4
734 .byte 14 # DW_CFA_def_cfa_offset
736 .byte 4 # DW_CFA_advance_loc4
737 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
742 .byte 14 # DW_CFA_def_cfa_offset
743 .uleb128 20+FRAME_SIZE
748 .hidden DW.ref.__gcc_personality_v0
749 .weak DW.ref.__gcc_personality_v0
750 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
752 .type DW.ref.__gcc_personality_v0, @object
753 .size DW.ref.__gcc_personality_v0, 4
754 DW.ref.__gcc_personality_v0:
755 .long __gcc_personality_v0