1 /* Copyright (C) 2002-2004,2006-2007,2009,2010 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 <pthread-pi-defines.h>
26 #include <kernel-features.h>
31 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
32 const struct timespec *abstime) */
33 .globl __pthread_cond_timedwait
34 .type __pthread_cond_timedwait, @function
36 __pthread_cond_timedwait:
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)
44 cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
45 cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
49 cfi_adjust_cfa_offset(4)
50 cfi_rel_offset(%ebp, 0)
52 cfi_adjust_cfa_offset(4)
53 cfi_rel_offset(%edi, 0)
55 cfi_adjust_cfa_offset(4)
56 cfi_rel_offset(%esi, 0)
58 cfi_adjust_cfa_offset(4)
59 cfi_rel_offset(%ebx, 0)
64 cmpl $1000000000, 4(%ebp)
68 /* Get internal lock. */
75 cmpxchgl %edx, cond_lock(%ebx)
79 /* Store the reference to the mutex. If there is already a
80 different value in there this is a bad user bug. */
81 2: cmpl $-1, dep_mutex(%ebx)
84 movl %eax, dep_mutex(%ebx)
86 /* Unlock the mutex. */
88 call __pthread_mutex_unlock_usercnt
93 addl $1, total_seq(%ebx)
94 adcl $0, total_seq+4(%ebx)
95 addl $1, cond_futex(%ebx)
96 addl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
99 subl $FRAME_SIZE, %esp
100 cfi_adjust_cfa_offset(FRAME_SIZE)
103 /* Get and store current wakeup_seq value. */
104 movl wakeup_seq(%ebx), %edi
105 movl wakeup_seq+4(%ebx), %edx
106 movl broadcast_seq(%ebx), %eax
111 /* Reset the pi-requeued flag. */
113 /* Get the current time. */
115 #ifdef __NR_clock_gettime
116 /* Get the clock number. */
117 movl cond_nwaiters(%ebx), %ebx
118 andl $((1 << nwaiters_shift) - 1), %ebx
119 /* Only clocks 0 and 1 are allowed so far. Both are handled in the
122 movl $__NR_clock_gettime, %eax
124 # ifndef __ASSUME_POSIX_TIMERS
130 /* Compute relative timeout. */
136 /* Get the current time. */
139 movl $__NR_gettimeofday, %eax
143 /* Compute relative timeout. */
146 mul %edx /* Milli seconds to nano seconds. */
153 addl $1000000000, %edx
156 movl $-ETIMEDOUT, %esi
159 /* Store relative timeout. */
160 21: movl %ecx, 4(%esp)
163 movl cond_futex(%ebx), %edi
171 subl $1, cond_lock(%ebx)
176 4: call __pthread_enable_asynccancel
179 #if FUTEX_PRIVATE_FLAG > 255
182 cmpl $-1, dep_mutex(%ebx)
186 movl dep_mutex(%ebx), %edi
187 /* Requeue to a non-robust PI mutex if the PI bit is set and
188 the robust bit is not set. */
189 movl MUTEX_KIND(%edi), %eax
190 andl $(ROBUST_BIT|PI_BIT), %eax
194 movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
195 /* The following only works like this because we only support
196 two clocks, represented using a single bit. */
197 testl $1, cond_nwaiters(%ebx)
198 /* XXX Need to implement using sete instead of a jump. */
200 orl $FUTEX_CLOCK_REALTIME, %ecx
202 /* Requeue-PI uses absolute timeout */
203 42: leal (%ebp), %esi
205 addl $cond_futex, %ebx
206 movl $SYS_futex, %eax
208 subl $cond_futex, %ebx
210 /* Set the pi-requeued flag only if the kernel has returned 0. The
211 kernel does not hold the mutex on ETIMEDOUT or any other error. */
216 /* Normal and PI futexes dont mix. Use normal futex functions only
217 if the kernel does not support the PI futex functions. */
223 #ifdef __ASSUME_PRIVATE_FUTEX
224 andl $FUTEX_PRIVATE_FLAG, %ecx
226 andl %gs:PRIVATE_FUTEX, %ecx
229 addl $FUTEX_WAIT, %ecx
233 addl $cond_futex, %ebx
235 movl $SYS_futex, %eax
237 subl $cond_futex, %ebx
241 41: movl (%esp), %eax
242 call __pthread_disable_asynccancel
250 cmpxchgl %edx, (%ebx)
252 cmpxchgl %edx, cond_lock(%ebx)
256 6: movl broadcast_seq(%ebx), %eax
260 movl woken_seq(%ebx), %eax
261 movl woken_seq+4(%ebx), %ecx
263 movl wakeup_seq(%ebx), %edi
264 movl wakeup_seq+4(%ebx), %edx
276 15: cmpl $-ETIMEDOUT, %esi
279 addl $1, wakeup_seq(%ebx)
280 adcl $0, wakeup_seq+4(%ebx)
281 addl $1, cond_futex(%ebx)
282 movl $ETIMEDOUT, %esi
289 14: addl $1, woken_seq(%ebx)
290 adcl $0, woken_seq+4(%ebx)
292 24: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
294 /* Wake up a thread which wants to destroy the condvar object. */
295 movl total_seq(%ebx), %eax
296 andl total_seq+4(%ebx), %eax
297 cmpl $0xffffffff, %eax
299 movl cond_nwaiters(%ebx), %eax
300 andl $~((1 << nwaiters_shift) - 1), %eax
303 addl $cond_nwaiters, %ebx
304 movl $SYS_futex, %eax
305 #if FUTEX_PRIVATE_FLAG > 255
308 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
311 #ifdef __ASSUME_PRIVATE_FUTEX
312 andl $FUTEX_PRIVATE_FLAG, %ecx
314 andl %gs:PRIVATE_FUTEX, %ecx
316 addl $FUTEX_WAKE, %ecx
319 subl $cond_nwaiters, %ebx
325 subl $1, cond_lock(%ebx)
329 11: movl 24+FRAME_SIZE(%esp), %eax
330 /* With requeue_pi, the mutex lock is held in the kernel. */
335 call __pthread_mutex_cond_lock
336 26: addl $FRAME_SIZE, %esp
337 cfi_adjust_cfa_offset(-FRAME_SIZE);
339 /* We return the result of the mutex_lock operation if it failed. */
350 cfi_adjust_cfa_offset(-4)
353 cfi_adjust_cfa_offset(-4)
356 cfi_adjust_cfa_offset(-4)
359 cfi_adjust_cfa_offset(-4)
366 27: call __pthread_mutex_cond_lock_adjust
370 cfi_adjust_cfa_offset(-FRAME_SIZE);
371 /* Initial locking failed. */
376 leal cond_lock(%ebx), %edx
378 #if (LLL_SHARED-LLL_PRIVATE) > 255
381 cmpl $-1, dep_mutex(%ebx)
384 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
386 addl $LLL_PRIVATE, %ecx
391 /* The initial unlocking of the mutex failed. */
397 subl $1, cond_lock(%ebx)
405 leal cond_lock(%ebx), %eax
407 #if (LLL_SHARED-LLL_PRIVATE) > 255
410 cmpl $-1, dep_mutex(%ebx)
413 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
415 addl $LLL_PRIVATE, %ecx
417 call __lll_unlock_wake
422 cfi_adjust_cfa_offset(FRAME_SIZE)
424 /* Unlock in loop requires wakeup. */
429 leal cond_lock(%ebx), %eax
431 #if (LLL_SHARED-LLL_PRIVATE) > 255
434 cmpl $-1, dep_mutex(%ebx)
437 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
439 addl $LLL_PRIVATE, %ecx
441 call __lll_unlock_wake
444 /* Locking in loop failed. */
449 leal cond_lock(%ebx), %edx
451 #if (LLL_SHARED-LLL_PRIVATE) > 255
454 cmpl $-1, dep_mutex(%ebx)
457 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
459 addl $LLL_PRIVATE, %ecx
464 /* Unlock after loop requires wakeup. */
469 leal cond_lock(%ebx), %eax
471 #if (LLL_SHARED-LLL_PRIVATE) > 255
474 cmpl $-1, dep_mutex(%ebx)
477 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
479 addl $LLL_PRIVATE, %ecx
481 call __lll_unlock_wake
484 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
485 /* clock_gettime not available. */
486 19: leal 4(%esp), %ebx
488 movl $__NR_gettimeofday, %eax
492 /* Compute relative timeout. */
495 mul %edx /* Milli seconds to nano seconds. */
501 addl $1000000000, %edx
504 movl $-ETIMEDOUT, %esi
508 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
509 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
513 .type __condvar_tw_cleanup2, @function
514 __condvar_tw_cleanup2:
515 subl $cond_futex, %ebx
516 .size __condvar_tw_cleanup2, .-__condvar_tw_cleanup2
517 .type __condvar_tw_cleanup, @function
518 __condvar_tw_cleanup:
521 /* Get internal lock. */
526 cmpxchgl %edx, (%ebx)
528 cmpxchgl %edx, cond_lock(%ebx)
535 leal cond_lock(%ebx), %edx
537 #if (LLL_SHARED-LLL_PRIVATE) > 255
540 cmpl $-1, dep_mutex(%ebx)
543 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
545 addl $LLL_PRIVATE, %ecx
549 1: movl broadcast_seq(%ebx), %eax
553 /* We increment the wakeup_seq counter only if it is lower than
554 total_seq. If this is not the case the thread was woken and
555 then canceled. In this case we ignore the signal. */
556 movl total_seq(%ebx), %eax
557 movl total_seq+4(%ebx), %edi
558 cmpl wakeup_seq+4(%ebx), %edi
561 cmpl wakeup_seq(%ebx), %eax
564 6: addl $1, wakeup_seq(%ebx)
565 adcl $0, wakeup_seq+4(%ebx)
566 addl $1, cond_futex(%ebx)
568 7: addl $1, woken_seq(%ebx)
569 adcl $0, woken_seq+4(%ebx)
571 3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
573 /* Wake up a thread which wants to destroy the condvar object. */
575 movl total_seq(%ebx), %eax
576 andl total_seq+4(%ebx), %eax
577 cmpl $0xffffffff, %eax
579 movl cond_nwaiters(%ebx), %eax
580 andl $~((1 << nwaiters_shift) - 1), %eax
583 addl $cond_nwaiters, %ebx
584 movl $SYS_futex, %eax
585 #if FUTEX_PRIVATE_FLAG > 255
588 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
591 #ifdef __ASSUME_PRIVATE_FUTEX
592 andl $FUTEX_PRIVATE_FLAG, %ecx
594 andl %gs:PRIVATE_FUTEX, %ecx
596 addl $FUTEX_WAKE, %ecx
599 subl $cond_nwaiters, %ebx
606 subl $1, cond_lock(%ebx)
613 leal cond_lock(%ebx), %eax
615 #if (LLL_SHARED-LLL_PRIVATE) > 255
618 cmpl $-1, dep_mutex(%ebx)
621 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
623 addl $LLL_PRIVATE, %ecx
625 call __lll_unlock_wake
627 /* Wake up all waiters to make sure no signal gets lost. */
630 addl $cond_futex, %ebx
631 #if FUTEX_PRIVATE_FLAG > 255
634 cmpl $-1, dep_mutex-cond_futex(%ebx)
637 #ifdef __ASSUME_PRIVATE_FUTEX
638 andl $FUTEX_PRIVATE_FLAG, %ecx
640 andl %gs:PRIVATE_FUTEX, %ecx
642 addl $FUTEX_WAKE, %ecx
643 movl $SYS_futex, %eax
644 movl $0x7fffffff, %edx
647 5: movl 24+FRAME_SIZE(%esp), %eax
648 call __pthread_mutex_cond_lock
656 .size __condvar_tw_cleanup, .-__condvar_tw_cleanup
659 .section .gcc_except_table,"a",@progbits
661 .byte DW_EH_PE_omit # @LPStart format (omit)
662 .byte DW_EH_PE_omit # @TType format (omit)
663 .byte DW_EH_PE_sdata4 # call-site format
665 .uleb128 .Lcstend-.Lcstbegin
667 .long .LcleanupSTART-.LSTARTCODE
668 .long .Ladd_cond_futex-.LcleanupSTART
669 .long __condvar_tw_cleanup-.LSTARTCODE
671 .long .Ladd_cond_futex-.LSTARTCODE
672 .long .Lsub_cond_futex-.Ladd_cond_futex
673 .long __condvar_tw_cleanup2-.LSTARTCODE
675 .long .Lsub_cond_futex-.LSTARTCODE
676 .long .LcleanupEND-.Lsub_cond_futex
677 .long __condvar_tw_cleanup-.LSTARTCODE
679 .long .LcallUR-.LSTARTCODE
680 .long .LENDCODE-.LcallUR
687 .hidden DW.ref.__gcc_personality_v0
688 .weak DW.ref.__gcc_personality_v0
689 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
691 .type DW.ref.__gcc_personality_v0, @object
692 .size DW.ref.__gcc_personality_v0, 4
693 DW.ref.__gcc_personality_v0:
694 .long __gcc_personality_v0