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 <lowlevellock.h>
21 #include <lowlevelcond.h>
22 #include <pthread-errnos.h>
23 #include <pthread-pi-defines.h>
24 #include <bits/kernel-features.h>
29 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
30 const struct timespec *abstime) */
31 .globl __pthread_cond_timedwait
32 .type __pthread_cond_timedwait, @function
33 .protected __pthread_cond_timedwait
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 weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait)
511 .type __condvar_tw_cleanup2, @function
512 __condvar_tw_cleanup2:
513 subl $cond_futex, %ebx
514 .size __condvar_tw_cleanup2, .-__condvar_tw_cleanup2
515 .type __condvar_tw_cleanup, @function
516 __condvar_tw_cleanup:
519 /* Get internal lock. */
524 cmpxchgl %edx, (%ebx)
526 cmpxchgl %edx, cond_lock(%ebx)
533 leal cond_lock(%ebx), %edx
535 #if (LLL_SHARED-LLL_PRIVATE) > 255
538 cmpl $-1, dep_mutex(%ebx)
541 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
543 addl $LLL_PRIVATE, %ecx
547 1: movl broadcast_seq(%ebx), %eax
551 /* We increment the wakeup_seq counter only if it is lower than
552 total_seq. If this is not the case the thread was woken and
553 then canceled. In this case we ignore the signal. */
554 movl total_seq(%ebx), %eax
555 movl total_seq+4(%ebx), %edi
556 cmpl wakeup_seq+4(%ebx), %edi
559 cmpl wakeup_seq(%ebx), %eax
562 6: addl $1, wakeup_seq(%ebx)
563 adcl $0, wakeup_seq+4(%ebx)
564 addl $1, cond_futex(%ebx)
566 7: addl $1, woken_seq(%ebx)
567 adcl $0, woken_seq+4(%ebx)
569 3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
571 /* Wake up a thread which wants to destroy the condvar object. */
573 movl total_seq(%ebx), %eax
574 andl total_seq+4(%ebx), %eax
575 cmpl $0xffffffff, %eax
577 movl cond_nwaiters(%ebx), %eax
578 andl $~((1 << nwaiters_shift) - 1), %eax
581 addl $cond_nwaiters, %ebx
582 movl $SYS_futex, %eax
583 #if FUTEX_PRIVATE_FLAG > 255
586 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
589 #ifdef __ASSUME_PRIVATE_FUTEX
590 andl $FUTEX_PRIVATE_FLAG, %ecx
592 andl %gs:PRIVATE_FUTEX, %ecx
594 addl $FUTEX_WAKE, %ecx
597 subl $cond_nwaiters, %ebx
604 subl $1, cond_lock(%ebx)
611 leal cond_lock(%ebx), %eax
613 #if (LLL_SHARED-LLL_PRIVATE) > 255
616 cmpl $-1, dep_mutex(%ebx)
619 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
621 addl $LLL_PRIVATE, %ecx
623 call __lll_unlock_wake
625 /* Wake up all waiters to make sure no signal gets lost. */
628 addl $cond_futex, %ebx
629 #if FUTEX_PRIVATE_FLAG > 255
632 cmpl $-1, dep_mutex-cond_futex(%ebx)
635 #ifdef __ASSUME_PRIVATE_FUTEX
636 andl $FUTEX_PRIVATE_FLAG, %ecx
638 andl %gs:PRIVATE_FUTEX, %ecx
640 addl $FUTEX_WAKE, %ecx
641 movl $SYS_futex, %eax
642 movl $0x7fffffff, %edx
645 5: movl 24+FRAME_SIZE(%esp), %eax
646 call __pthread_mutex_cond_lock
651 call __i686.get_pc_thunk.bx
652 addl $_GLOBAL_OFFSET_TABLE_, %ebx
654 call _Unwind_Resume@PLT
658 .size __condvar_tw_cleanup, .-__condvar_tw_cleanup
661 .section .gcc_except_table,"a",@progbits
663 .byte DW_EH_PE_omit # @LPStart format (omit)
664 .byte DW_EH_PE_omit # @TType format (omit)
665 .byte DW_EH_PE_sdata4 # call-site format
667 .uleb128 .Lcstend-.Lcstbegin
669 .long .LcleanupSTART-.LSTARTCODE
670 .long .Ladd_cond_futex-.LcleanupSTART
671 .long __condvar_tw_cleanup-.LSTARTCODE
673 .long .Ladd_cond_futex-.LSTARTCODE
674 .long .Lsub_cond_futex-.Ladd_cond_futex
675 .long __condvar_tw_cleanup2-.LSTARTCODE
677 .long .Lsub_cond_futex-.LSTARTCODE
678 .long .LcleanupEND-.Lsub_cond_futex
679 .long __condvar_tw_cleanup-.LSTARTCODE
681 .long .LcallUR-.LSTARTCODE
682 .long .LENDCODE-.LcallUR
689 .hidden DW.ref.__gcc_personality_v0
690 .weak DW.ref.__gcc_personality_v0
691 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
693 .type DW.ref.__gcc_personality_v0, @object
694 .size DW.ref.__gcc_personality_v0, 4
695 DW.ref.__gcc_personality_v0:
696 .long __gcc_personality_v0