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, see
17 <http://www.gnu.org/licenses/>. */
20 #include <shlib-compat.h>
21 #include <lowlevellock.h>
22 #include <lowlevelcond.h>
23 #include <pthread-errnos.h>
24 #include <pthread-pi-defines.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:
39 cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
40 DW.ref.__gcc_personality_v0)
41 cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
43 cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
44 cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
48 cfi_adjust_cfa_offset(4)
49 cfi_rel_offset(%ebp, 0)
51 cfi_adjust_cfa_offset(4)
52 cfi_rel_offset(%edi, 0)
54 cfi_adjust_cfa_offset(4)
55 cfi_rel_offset(%esi, 0)
57 cfi_adjust_cfa_offset(4)
58 cfi_rel_offset(%ebx, 0)
63 cmpl $1000000000, 4(%ebp)
67 /* Get internal lock. */
74 cmpxchgl %edx, cond_lock(%ebx)
78 /* Store the reference to the mutex. If there is already a
79 different value in there this is a bad user bug. */
80 2: cmpl $-1, dep_mutex(%ebx)
83 movl %eax, dep_mutex(%ebx)
85 /* Unlock the mutex. */
87 call __pthread_mutex_unlock_usercnt
92 addl $1, total_seq(%ebx)
93 adcl $0, total_seq+4(%ebx)
94 addl $1, cond_futex(%ebx)
95 addl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
98 subl $FRAME_SIZE, %esp
99 cfi_adjust_cfa_offset(FRAME_SIZE)
102 /* Get and store current wakeup_seq value. */
103 movl wakeup_seq(%ebx), %edi
104 movl wakeup_seq+4(%ebx), %edx
105 movl broadcast_seq(%ebx), %eax
110 /* Reset the pi-requeued flag. */
112 /* Get the current time. */
114 #ifdef __NR_clock_gettime
115 /* Get the clock number. */
116 movl cond_nwaiters(%ebx), %ebx
117 andl $((1 << nwaiters_shift) - 1), %ebx
118 /* Only clocks 0 and 1 are allowed so far. Both are handled in the
121 movl $__NR_clock_gettime, %eax
123 # ifndef __ASSUME_POSIX_TIMERS
129 /* Compute relative timeout. */
135 /* Get the current time. */
138 movl $__NR_gettimeofday, %eax
142 /* Compute relative timeout. */
145 mul %edx /* Milli seconds to nano seconds. */
152 addl $1000000000, %edx
155 movl $-ETIMEDOUT, %esi
158 /* Store relative timeout. */
159 21: movl %ecx, 4(%esp)
162 movl cond_futex(%ebx), %edi
170 subl $1, cond_lock(%ebx)
175 4: call __pthread_enable_asynccancel
178 #if FUTEX_PRIVATE_FLAG > 255
181 cmpl $-1, dep_mutex(%ebx)
185 movl dep_mutex(%ebx), %edi
186 /* Requeue to a non-robust PI mutex if the PI bit is set and
187 the robust bit is not set. */
188 movl MUTEX_KIND(%edi), %eax
189 andl $(ROBUST_BIT|PI_BIT), %eax
193 movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
194 /* The following only works like this because we only support
195 two clocks, represented using a single bit. */
196 testl $1, cond_nwaiters(%ebx)
197 /* XXX Need to implement using sete instead of a jump. */
199 orl $FUTEX_CLOCK_REALTIME, %ecx
201 /* Requeue-PI uses absolute timeout */
202 42: leal (%ebp), %esi
204 addl $cond_futex, %ebx
205 movl $SYS_futex, %eax
207 subl $cond_futex, %ebx
209 /* Set the pi-requeued flag only if the kernel has returned 0. The
210 kernel does not hold the mutex on ETIMEDOUT or any other error. */
215 /* Normal and PI futexes dont mix. Use normal futex functions only
216 if the kernel does not support the PI futex functions. */
222 #ifdef __ASSUME_PRIVATE_FUTEX
223 andl $FUTEX_PRIVATE_FLAG, %ecx
225 andl %gs:PRIVATE_FUTEX, %ecx
228 addl $FUTEX_WAIT, %ecx
232 addl $cond_futex, %ebx
234 movl $SYS_futex, %eax
236 subl $cond_futex, %ebx
240 41: movl (%esp), %eax
241 call __pthread_disable_asynccancel
249 cmpxchgl %edx, (%ebx)
251 cmpxchgl %edx, cond_lock(%ebx)
255 6: movl broadcast_seq(%ebx), %eax
259 movl woken_seq(%ebx), %eax
260 movl woken_seq+4(%ebx), %ecx
262 movl wakeup_seq(%ebx), %edi
263 movl wakeup_seq+4(%ebx), %edx
275 15: cmpl $-ETIMEDOUT, %esi
278 addl $1, wakeup_seq(%ebx)
279 adcl $0, wakeup_seq+4(%ebx)
280 addl $1, cond_futex(%ebx)
281 movl $ETIMEDOUT, %esi
288 14: addl $1, woken_seq(%ebx)
289 adcl $0, woken_seq+4(%ebx)
291 24: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
293 /* Wake up a thread which wants to destroy the condvar object. */
294 movl total_seq(%ebx), %eax
295 andl total_seq+4(%ebx), %eax
296 cmpl $0xffffffff, %eax
298 movl cond_nwaiters(%ebx), %eax
299 andl $~((1 << nwaiters_shift) - 1), %eax
302 addl $cond_nwaiters, %ebx
303 movl $SYS_futex, %eax
304 #if FUTEX_PRIVATE_FLAG > 255
307 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
310 #ifdef __ASSUME_PRIVATE_FUTEX
311 andl $FUTEX_PRIVATE_FLAG, %ecx
313 andl %gs:PRIVATE_FUTEX, %ecx
315 addl $FUTEX_WAKE, %ecx
318 subl $cond_nwaiters, %ebx
324 subl $1, cond_lock(%ebx)
328 11: movl 24+FRAME_SIZE(%esp), %eax
329 /* With requeue_pi, the mutex lock is held in the kernel. */
334 call __pthread_mutex_cond_lock
335 26: addl $FRAME_SIZE, %esp
336 cfi_adjust_cfa_offset(-FRAME_SIZE);
338 /* We return the result of the mutex_lock operation if it failed. */
349 cfi_adjust_cfa_offset(-4)
352 cfi_adjust_cfa_offset(-4)
355 cfi_adjust_cfa_offset(-4)
358 cfi_adjust_cfa_offset(-4)
365 27: call __pthread_mutex_cond_lock_adjust
369 cfi_adjust_cfa_offset(-FRAME_SIZE);
370 /* Initial locking failed. */
375 leal cond_lock(%ebx), %edx
377 #if (LLL_SHARED-LLL_PRIVATE) > 255
380 cmpl $-1, dep_mutex(%ebx)
383 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
385 addl $LLL_PRIVATE, %ecx
390 /* The initial unlocking of the mutex failed. */
396 subl $1, cond_lock(%ebx)
404 leal cond_lock(%ebx), %eax
406 #if (LLL_SHARED-LLL_PRIVATE) > 255
409 cmpl $-1, dep_mutex(%ebx)
412 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
414 addl $LLL_PRIVATE, %ecx
416 call __lll_unlock_wake
421 cfi_adjust_cfa_offset(FRAME_SIZE)
423 /* Unlock in loop requires wakeup. */
428 leal cond_lock(%ebx), %eax
430 #if (LLL_SHARED-LLL_PRIVATE) > 255
433 cmpl $-1, dep_mutex(%ebx)
436 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
438 addl $LLL_PRIVATE, %ecx
440 call __lll_unlock_wake
443 /* Locking in loop failed. */
448 leal cond_lock(%ebx), %edx
450 #if (LLL_SHARED-LLL_PRIVATE) > 255
453 cmpl $-1, dep_mutex(%ebx)
456 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
458 addl $LLL_PRIVATE, %ecx
463 /* Unlock after loop requires wakeup. */
468 leal cond_lock(%ebx), %eax
470 #if (LLL_SHARED-LLL_PRIVATE) > 255
473 cmpl $-1, dep_mutex(%ebx)
476 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
478 addl $LLL_PRIVATE, %ecx
480 call __lll_unlock_wake
483 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
484 /* clock_gettime not available. */
485 19: leal 4(%esp), %ebx
487 movl $__NR_gettimeofday, %eax
491 /* Compute relative timeout. */
494 mul %edx /* Milli seconds to nano seconds. */
500 addl $1000000000, %edx
503 movl $-ETIMEDOUT, %esi
507 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
508 versioned_symbol (libpthread, __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
655 .size __condvar_tw_cleanup, .-__condvar_tw_cleanup
658 .section .gcc_except_table,"a",@progbits
660 .byte DW_EH_PE_omit # @LPStart format (omit)
661 .byte DW_EH_PE_omit # @TType format (omit)
662 .byte DW_EH_PE_sdata4 # call-site format
664 .uleb128 .Lcstend-.Lcstbegin
666 .long .LcleanupSTART-.LSTARTCODE
667 .long .Ladd_cond_futex-.LcleanupSTART
668 .long __condvar_tw_cleanup-.LSTARTCODE
670 .long .Ladd_cond_futex-.LSTARTCODE
671 .long .Lsub_cond_futex-.Ladd_cond_futex
672 .long __condvar_tw_cleanup2-.LSTARTCODE
674 .long .Lsub_cond_futex-.LSTARTCODE
675 .long .LcleanupEND-.Lsub_cond_futex
676 .long __condvar_tw_cleanup-.LSTARTCODE
678 .long .LcallUR-.LSTARTCODE
679 .long .LENDCODE-.LcallUR
686 .hidden DW.ref.__gcc_personality_v0
687 .weak DW.ref.__gcc_personality_v0
688 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
690 .type DW.ref.__gcc_personality_v0, @object
691 .size DW.ref.__gcc_personality_v0, 4
692 DW.ref.__gcc_personality_v0:
693 .long __gcc_personality_v0