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 <tcb-offsets.h>
23 #include <pthread-errnos.h>
24 #include <pthread-pi-defines.h>
25 #include <bits/kernel-features.h>
30 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
31 .globl __pthread_cond_wait
32 .type __pthread_cond_wait, @function
33 .protected __pthread_cond_wait
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 /* Get internal lock. */
70 cmpxchgl %edx, cond_lock(%ebx)
74 /* Store the reference to the mutex. If there is already a
75 different value in there this is a bad user bug. */
76 2: cmpl $-1, dep_mutex(%ebx)
79 movl %eax, dep_mutex(%ebx)
81 /* Unlock the mutex. */
83 call __pthread_mutex_unlock_usercnt
88 addl $1, total_seq(%ebx)
89 adcl $0, total_seq+4(%ebx)
90 addl $1, cond_futex(%ebx)
91 addl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
94 subl $FRAME_SIZE, %esp
95 cfi_adjust_cfa_offset(FRAME_SIZE)
98 /* Get and store current wakeup_seq value. */
99 movl wakeup_seq(%ebx), %edi
100 movl wakeup_seq+4(%ebx), %edx
101 movl broadcast_seq(%ebx), %eax
106 /* Reset the pi-requeued flag. */
108 movl cond_futex(%ebx), %ebp
115 subl $1, cond_lock(%ebx)
120 4: call __pthread_enable_asynccancel
124 cmpl $-1, dep_mutex(%ebx)
128 movl dep_mutex(%ebx), %edi
129 /* Requeue to a non-robust PI mutex if the PI bit is set and
130 the robust bit is not set. */
131 movl MUTEX_KIND(%edi), %eax
132 andl $(ROBUST_BIT|PI_BIT), %eax
136 movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
139 addl $cond_futex, %ebx
140 movl $SYS_futex, %eax
142 subl $cond_futex, %ebx
143 /* Set the pi-requeued flag only if the kernel has returned 0. The
144 kernel does not hold the mutex on error. */
149 /* Normal and PI futexes dont mix. Use normal futex functions only
150 if the kernel does not support the PI futex functions. */
156 #ifdef __ASSUME_PRIVATE_FUTEX
157 andl $FUTEX_PRIVATE_FLAG, %ecx
159 andl %gs:PRIVATE_FUTEX, %ecx
162 addl $FUTEX_WAIT, %ecx
165 addl $cond_futex, %ebx
167 movl $SYS_futex, %eax
169 subl $cond_futex, %ebx
172 19: movl (%esp), %eax
173 call __pthread_disable_asynccancel
181 cmpxchgl %edx, (%ebx)
183 cmpxchgl %edx, cond_lock(%ebx)
187 6: movl broadcast_seq(%ebx), %eax
191 movl woken_seq(%ebx), %eax
192 movl woken_seq+4(%ebx), %ecx
194 movl wakeup_seq(%ebx), %edi
195 movl wakeup_seq+4(%ebx), %edx
207 9: addl $1, woken_seq(%ebx)
208 adcl $0, woken_seq+4(%ebx)
211 16: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
213 /* Wake up a thread which wants to destroy the condvar object. */
214 movl total_seq(%ebx), %eax
215 andl total_seq+4(%ebx), %eax
216 cmpl $0xffffffff, %eax
218 movl cond_nwaiters(%ebx), %eax
219 andl $~((1 << nwaiters_shift) - 1), %eax
222 addl $cond_nwaiters, %ebx
223 movl $SYS_futex, %eax
224 #if FUTEX_PRIVATE_FLAG > 255
227 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
230 #ifdef __ASSUME_PRIVATE_FUTEX
231 andl $FUTEX_PRIVATE_FLAG, %ecx
233 andl %gs:PRIVATE_FUTEX, %ecx
235 addl $FUTEX_WAKE, %ecx
238 subl $cond_nwaiters, %ebx
244 subl $1, cond_lock(%ebx)
248 /* With requeue_pi, the mutex lock is held in the kernel. */
249 11: movl 24+FRAME_SIZE(%esp), %eax
254 call __pthread_mutex_cond_lock
255 20: addl $FRAME_SIZE, %esp
256 cfi_adjust_cfa_offset(-FRAME_SIZE);
259 cfi_adjust_cfa_offset(-4)
262 cfi_adjust_cfa_offset(-4)
265 cfi_adjust_cfa_offset(-4)
268 cfi_adjust_cfa_offset(-4)
271 /* We return the result of the mutex_lock operation. */
276 21: call __pthread_mutex_cond_lock_adjust
280 cfi_adjust_cfa_offset(-FRAME_SIZE);
281 /* Initial locking failed. */
286 leal cond_lock(%ebx), %edx
288 #if (LLL_SHARED-LLL_PRIVATE) > 255
291 cmpl $-1, dep_mutex(%ebx)
294 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
296 addl $LLL_PRIVATE, %ecx
301 /* The initial unlocking of the mutex failed. */
307 subl $1, cond_lock(%ebx)
315 leal cond_lock(%ebx), %eax
317 #if (LLL_SHARED-LLL_PRIVATE) > 255
320 cmpl $-1, dep_mutex(%ebx)
323 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
325 addl $LLL_PRIVATE, %ecx
327 call __lll_unlock_wake
332 cfi_adjust_cfa_offset(FRAME_SIZE)
334 /* Unlock in loop requires wakeup. */
339 leal cond_lock(%ebx), %eax
341 #if (LLL_SHARED-LLL_PRIVATE) > 255
344 cmpl $-1, dep_mutex(%ebx)
347 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
349 addl $LLL_PRIVATE, %ecx
351 call __lll_unlock_wake
354 /* Locking in loop failed. */
359 leal cond_lock(%ebx), %edx
361 #if (LLL_SHARED-LLL_PRIVATE) > 255
364 cmpl $-1, dep_mutex(%ebx)
367 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
369 addl $LLL_PRIVATE, %ecx
374 /* Unlock after loop requires wakeup. */
379 leal cond_lock(%ebx), %eax
381 #if (LLL_SHARED-LLL_PRIVATE) > 255
384 cmpl $-1, dep_mutex(%ebx)
387 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
389 addl $LLL_PRIVATE, %ecx
391 call __lll_unlock_wake
393 .size __pthread_cond_wait, .-__pthread_cond_wait
394 weak_alias(__pthread_cond_wait, pthread_cond_wait)
397 .type __condvar_w_cleanup2, @function
398 __condvar_w_cleanup2:
399 subl $cond_futex, %ebx
400 .size __condvar_w_cleanup2, .-__condvar_w_cleanup2
402 .type __condvar_w_cleanup, @function
406 /* Get internal lock. */
411 cmpxchgl %edx, (%ebx)
413 cmpxchgl %edx, cond_lock(%ebx)
420 leal cond_lock(%ebx), %edx
422 #if (LLL_SHARED-LLL_PRIVATE) > 255
425 cmpl $-1, dep_mutex(%ebx)
428 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
430 addl $LLL_PRIVATE, %ecx
434 1: movl broadcast_seq(%ebx), %eax
438 /* We increment the wakeup_seq counter only if it is lower than
439 total_seq. If this is not the case the thread was woken and
440 then canceled. In this case we ignore the signal. */
441 movl total_seq(%ebx), %eax
442 movl total_seq+4(%ebx), %edi
443 cmpl wakeup_seq+4(%ebx), %edi
446 cmpl wakeup_seq(%ebx), %eax
449 6: addl $1, wakeup_seq(%ebx)
450 adcl $0, wakeup_seq+4(%ebx)
451 addl $1, cond_futex(%ebx)
453 7: addl $1, woken_seq(%ebx)
454 adcl $0, woken_seq+4(%ebx)
456 3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
458 /* Wake up a thread which wants to destroy the condvar object. */
460 movl total_seq(%ebx), %eax
461 andl total_seq+4(%ebx), %eax
462 cmpl $0xffffffff, %eax
464 movl cond_nwaiters(%ebx), %eax
465 andl $~((1 << nwaiters_shift) - 1), %eax
468 addl $cond_nwaiters, %ebx
469 movl $SYS_futex, %eax
470 #if FUTEX_PRIVATE_FLAG > 255
473 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
476 #ifdef __ASSUME_PRIVATE_FUTEX
477 andl $FUTEX_PRIVATE_FLAG, %ecx
479 andl %gs:PRIVATE_FUTEX, %ecx
481 addl $FUTEX_WAKE, %ecx
484 subl $cond_nwaiters, %ebx
491 subl $1, cond_lock(%ebx)
498 leal cond_lock(%ebx), %eax
500 #if (LLL_SHARED-LLL_PRIVATE) > 255
503 cmpl $-1, dep_mutex(%ebx)
506 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
508 addl $LLL_PRIVATE, %ecx
510 call __lll_unlock_wake
512 /* Wake up all waiters to make sure no signal gets lost. */
515 addl $cond_futex, %ebx
516 #if FUTEX_PRIVATE_FLAG > 255
519 cmpl $-1, dep_mutex-cond_futex(%ebx)
522 #ifdef __ASSUME_PRIVATE_FUTEX
523 andl $FUTEX_PRIVATE_FLAG, %ecx
525 andl %gs:PRIVATE_FUTEX, %ecx
527 addl $FUTEX_WAKE, %ecx
528 movl $SYS_futex, %eax
529 movl $0x7fffffff, %edx
532 5: movl 24+FRAME_SIZE(%esp), %eax
533 call __pthread_mutex_cond_lock
538 call __i686.get_pc_thunk.bx
539 addl $_GLOBAL_OFFSET_TABLE_, %ebx
541 call _Unwind_Resume@PLT
545 .size __condvar_w_cleanup, .-__condvar_w_cleanup
548 .section .gcc_except_table,"a",@progbits
550 .byte DW_EH_PE_omit # @LPStart format (omit)
551 .byte DW_EH_PE_omit # @TType format (omit)
552 .byte DW_EH_PE_sdata4 # call-site format
554 .uleb128 .Lcstend-.Lcstbegin
556 .long .LcleanupSTART-.LSTARTCODE
557 .long .Ladd_cond_futex-.LcleanupSTART
558 .long __condvar_w_cleanup-.LSTARTCODE
560 .long .Ladd_cond_futex-.LSTARTCODE
561 .long .Lsub_cond_futex-.Ladd_cond_futex
562 .long __condvar_w_cleanup2-.LSTARTCODE
564 .long .Lsub_cond_futex-.LSTARTCODE
565 .long .LcleanupEND-.Lsub_cond_futex
566 .long __condvar_w_cleanup-.LSTARTCODE
568 .long .LcallUR-.LSTARTCODE
569 .long .LENDCODE-.LcallUR
575 .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
576 .globl __i686.get_pc_thunk.bx
577 .hidden __i686.get_pc_thunk.bx
578 .type __i686.get_pc_thunk.bx,@function
579 __i686.get_pc_thunk.bx:
582 .size __i686.get_pc_thunk.bx,.-__i686.get_pc_thunk.bx
586 .hidden DW.ref.__gcc_personality_v0
587 .weak DW.ref.__gcc_personality_v0
588 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
590 .type DW.ref.__gcc_personality_v0, @object
591 .size DW.ref.__gcc_personality_v0, 4
592 DW.ref.__gcc_personality_v0:
593 .long __gcc_personality_v0