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 <lowlevellock.h>
22 #include <lowlevelcond.h>
23 #include <pthread-errnos.h>
24 #include <pthread-pi-defines.h>
25 #include <bits/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
34 .protected __pthread_cond_timedwait
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 weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait)
512 .type __condvar_tw_cleanup2, @function
513 __condvar_tw_cleanup2:
514 subl $cond_futex, %ebx
515 .size __condvar_tw_cleanup2, .-__condvar_tw_cleanup2
516 .type __condvar_tw_cleanup, @function
517 __condvar_tw_cleanup:
520 /* Get internal lock. */
525 cmpxchgl %edx, (%ebx)
527 cmpxchgl %edx, cond_lock(%ebx)
534 leal cond_lock(%ebx), %edx
536 #if (LLL_SHARED-LLL_PRIVATE) > 255
539 cmpl $-1, dep_mutex(%ebx)
542 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
544 addl $LLL_PRIVATE, %ecx
548 1: movl broadcast_seq(%ebx), %eax
552 /* We increment the wakeup_seq counter only if it is lower than
553 total_seq. If this is not the case the thread was woken and
554 then canceled. In this case we ignore the signal. */
555 movl total_seq(%ebx), %eax
556 movl total_seq+4(%ebx), %edi
557 cmpl wakeup_seq+4(%ebx), %edi
560 cmpl wakeup_seq(%ebx), %eax
563 6: addl $1, wakeup_seq(%ebx)
564 adcl $0, wakeup_seq+4(%ebx)
565 addl $1, cond_futex(%ebx)
567 7: addl $1, woken_seq(%ebx)
568 adcl $0, woken_seq+4(%ebx)
570 3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
572 /* Wake up a thread which wants to destroy the condvar object. */
574 movl total_seq(%ebx), %eax
575 andl total_seq+4(%ebx), %eax
576 cmpl $0xffffffff, %eax
578 movl cond_nwaiters(%ebx), %eax
579 andl $~((1 << nwaiters_shift) - 1), %eax
582 addl $cond_nwaiters, %ebx
583 movl $SYS_futex, %eax
584 #if FUTEX_PRIVATE_FLAG > 255
587 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
590 #ifdef __ASSUME_PRIVATE_FUTEX
591 andl $FUTEX_PRIVATE_FLAG, %ecx
593 andl %gs:PRIVATE_FUTEX, %ecx
595 addl $FUTEX_WAKE, %ecx
598 subl $cond_nwaiters, %ebx
605 subl $1, cond_lock(%ebx)
612 leal cond_lock(%ebx), %eax
614 #if (LLL_SHARED-LLL_PRIVATE) > 255
617 cmpl $-1, dep_mutex(%ebx)
620 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
622 addl $LLL_PRIVATE, %ecx
624 call __lll_unlock_wake
626 /* Wake up all waiters to make sure no signal gets lost. */
629 addl $cond_futex, %ebx
630 #if FUTEX_PRIVATE_FLAG > 255
633 cmpl $-1, dep_mutex-cond_futex(%ebx)
636 #ifdef __ASSUME_PRIVATE_FUTEX
637 andl $FUTEX_PRIVATE_FLAG, %ecx
639 andl %gs:PRIVATE_FUTEX, %ecx
641 addl $FUTEX_WAKE, %ecx
642 movl $SYS_futex, %eax
643 movl $0x7fffffff, %edx
646 5: movl 24+FRAME_SIZE(%esp), %eax
647 call __pthread_mutex_cond_lock
652 call __i686.get_pc_thunk.bx
653 addl $_GLOBAL_OFFSET_TABLE_, %ebx
655 call _Unwind_Resume@PLT
659 .size __condvar_tw_cleanup, .-__condvar_tw_cleanup
662 .section .gcc_except_table,"a",@progbits
664 .byte DW_EH_PE_omit # @LPStart format (omit)
665 .byte DW_EH_PE_omit # @TType format (omit)
666 .byte DW_EH_PE_sdata4 # call-site format
668 .uleb128 .Lcstend-.Lcstbegin
670 .long .LcleanupSTART-.LSTARTCODE
671 .long .Ladd_cond_futex-.LcleanupSTART
672 .long __condvar_tw_cleanup-.LSTARTCODE
674 .long .Ladd_cond_futex-.LSTARTCODE
675 .long .Lsub_cond_futex-.Ladd_cond_futex
676 .long __condvar_tw_cleanup2-.LSTARTCODE
678 .long .Lsub_cond_futex-.LSTARTCODE
679 .long .LcleanupEND-.Lsub_cond_futex
680 .long __condvar_tw_cleanup-.LSTARTCODE
682 .long .LcallUR-.LSTARTCODE
683 .long .LENDCODE-.LcallUR
690 .hidden DW.ref.__gcc_personality_v0
691 .weak DW.ref.__gcc_personality_v0
692 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
694 .type DW.ref.__gcc_personality_v0, @object
695 .size DW.ref.__gcc_personality_v0, 4
696 DW.ref.__gcc_personality_v0:
697 .long __gcc_personality_v0