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 <tcb-offsets.h>
24 #include <pthread-errnos.h>
25 #include <pthread-pi-defines.h>
26 #include <bits/kernel-features.h>
31 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
32 .globl __pthread_cond_wait
33 .type __pthread_cond_wait, @function
34 .protected __pthread_cond_wait
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 /* Get internal lock. */
71 cmpxchgl %edx, cond_lock(%ebx)
75 /* Store the reference to the mutex. If there is already a
76 different value in there this is a bad user bug. */
77 2: cmpl $-1, dep_mutex(%ebx)
80 movl %eax, dep_mutex(%ebx)
82 /* Unlock the mutex. */
84 call __pthread_mutex_unlock_usercnt
89 addl $1, total_seq(%ebx)
90 adcl $0, total_seq+4(%ebx)
91 addl $1, cond_futex(%ebx)
92 addl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
95 subl $FRAME_SIZE, %esp
96 cfi_adjust_cfa_offset(FRAME_SIZE)
99 /* Get and store current wakeup_seq value. */
100 movl wakeup_seq(%ebx), %edi
101 movl wakeup_seq+4(%ebx), %edx
102 movl broadcast_seq(%ebx), %eax
107 /* Reset the pi-requeued flag. */
109 movl cond_futex(%ebx), %ebp
116 subl $1, cond_lock(%ebx)
121 4: call __pthread_enable_asynccancel
125 cmpl $-1, dep_mutex(%ebx)
129 movl dep_mutex(%ebx), %edi
130 /* Requeue to a non-robust PI mutex if the PI bit is set and
131 the robust bit is not set. */
132 movl MUTEX_KIND(%edi), %eax
133 andl $(ROBUST_BIT|PI_BIT), %eax
137 movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
140 addl $cond_futex, %ebx
141 movl $SYS_futex, %eax
143 subl $cond_futex, %ebx
144 /* Set the pi-requeued flag only if the kernel has returned 0. The
145 kernel does not hold the mutex on error. */
150 /* Normal and PI futexes dont mix. Use normal futex functions only
151 if the kernel does not support the PI futex functions. */
157 #ifdef __ASSUME_PRIVATE_FUTEX
158 andl $FUTEX_PRIVATE_FLAG, %ecx
160 andl %gs:PRIVATE_FUTEX, %ecx
163 addl $FUTEX_WAIT, %ecx
166 addl $cond_futex, %ebx
168 movl $SYS_futex, %eax
170 subl $cond_futex, %ebx
173 19: movl (%esp), %eax
174 call __pthread_disable_asynccancel
182 cmpxchgl %edx, (%ebx)
184 cmpxchgl %edx, cond_lock(%ebx)
188 6: movl broadcast_seq(%ebx), %eax
192 movl woken_seq(%ebx), %eax
193 movl woken_seq+4(%ebx), %ecx
195 movl wakeup_seq(%ebx), %edi
196 movl wakeup_seq+4(%ebx), %edx
208 9: addl $1, woken_seq(%ebx)
209 adcl $0, woken_seq+4(%ebx)
212 16: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
214 /* Wake up a thread which wants to destroy the condvar object. */
215 movl total_seq(%ebx), %eax
216 andl total_seq+4(%ebx), %eax
217 cmpl $0xffffffff, %eax
219 movl cond_nwaiters(%ebx), %eax
220 andl $~((1 << nwaiters_shift) - 1), %eax
223 addl $cond_nwaiters, %ebx
224 movl $SYS_futex, %eax
225 #if FUTEX_PRIVATE_FLAG > 255
228 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
231 #ifdef __ASSUME_PRIVATE_FUTEX
232 andl $FUTEX_PRIVATE_FLAG, %ecx
234 andl %gs:PRIVATE_FUTEX, %ecx
236 addl $FUTEX_WAKE, %ecx
239 subl $cond_nwaiters, %ebx
245 subl $1, cond_lock(%ebx)
249 /* With requeue_pi, the mutex lock is held in the kernel. */
250 11: movl 24+FRAME_SIZE(%esp), %eax
255 call __pthread_mutex_cond_lock
256 20: addl $FRAME_SIZE, %esp
257 cfi_adjust_cfa_offset(-FRAME_SIZE);
260 cfi_adjust_cfa_offset(-4)
263 cfi_adjust_cfa_offset(-4)
266 cfi_adjust_cfa_offset(-4)
269 cfi_adjust_cfa_offset(-4)
272 /* We return the result of the mutex_lock operation. */
277 21: call __pthread_mutex_cond_lock_adjust
281 cfi_adjust_cfa_offset(-FRAME_SIZE);
282 /* Initial locking failed. */
287 leal cond_lock(%ebx), %edx
289 #if (LLL_SHARED-LLL_PRIVATE) > 255
292 cmpl $-1, dep_mutex(%ebx)
295 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
297 addl $LLL_PRIVATE, %ecx
302 /* The initial unlocking of the mutex failed. */
308 subl $1, cond_lock(%ebx)
316 leal cond_lock(%ebx), %eax
318 #if (LLL_SHARED-LLL_PRIVATE) > 255
321 cmpl $-1, dep_mutex(%ebx)
324 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
326 addl $LLL_PRIVATE, %ecx
328 call __lll_unlock_wake
333 cfi_adjust_cfa_offset(FRAME_SIZE)
335 /* Unlock in loop requires wakeup. */
340 leal cond_lock(%ebx), %eax
342 #if (LLL_SHARED-LLL_PRIVATE) > 255
345 cmpl $-1, dep_mutex(%ebx)
348 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
350 addl $LLL_PRIVATE, %ecx
352 call __lll_unlock_wake
355 /* Locking in loop failed. */
360 leal cond_lock(%ebx), %edx
362 #if (LLL_SHARED-LLL_PRIVATE) > 255
365 cmpl $-1, dep_mutex(%ebx)
368 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
370 addl $LLL_PRIVATE, %ecx
375 /* Unlock after loop requires wakeup. */
380 leal cond_lock(%ebx), %eax
382 #if (LLL_SHARED-LLL_PRIVATE) > 255
385 cmpl $-1, dep_mutex(%ebx)
388 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
390 addl $LLL_PRIVATE, %ecx
392 call __lll_unlock_wake
394 .size __pthread_cond_wait, .-__pthread_cond_wait
395 weak_alias(__pthread_cond_wait, pthread_cond_wait)
398 .type __condvar_w_cleanup2, @function
399 __condvar_w_cleanup2:
400 subl $cond_futex, %ebx
401 .size __condvar_w_cleanup2, .-__condvar_w_cleanup2
403 .type __condvar_w_cleanup, @function
407 /* Get internal lock. */
412 cmpxchgl %edx, (%ebx)
414 cmpxchgl %edx, cond_lock(%ebx)
421 leal cond_lock(%ebx), %edx
423 #if (LLL_SHARED-LLL_PRIVATE) > 255
426 cmpl $-1, dep_mutex(%ebx)
429 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
431 addl $LLL_PRIVATE, %ecx
435 1: movl broadcast_seq(%ebx), %eax
439 /* We increment the wakeup_seq counter only if it is lower than
440 total_seq. If this is not the case the thread was woken and
441 then canceled. In this case we ignore the signal. */
442 movl total_seq(%ebx), %eax
443 movl total_seq+4(%ebx), %edi
444 cmpl wakeup_seq+4(%ebx), %edi
447 cmpl wakeup_seq(%ebx), %eax
450 6: addl $1, wakeup_seq(%ebx)
451 adcl $0, wakeup_seq+4(%ebx)
452 addl $1, cond_futex(%ebx)
454 7: addl $1, woken_seq(%ebx)
455 adcl $0, woken_seq+4(%ebx)
457 3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
459 /* Wake up a thread which wants to destroy the condvar object. */
461 movl total_seq(%ebx), %eax
462 andl total_seq+4(%ebx), %eax
463 cmpl $0xffffffff, %eax
465 movl cond_nwaiters(%ebx), %eax
466 andl $~((1 << nwaiters_shift) - 1), %eax
469 addl $cond_nwaiters, %ebx
470 movl $SYS_futex, %eax
471 #if FUTEX_PRIVATE_FLAG > 255
474 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
477 #ifdef __ASSUME_PRIVATE_FUTEX
478 andl $FUTEX_PRIVATE_FLAG, %ecx
480 andl %gs:PRIVATE_FUTEX, %ecx
482 addl $FUTEX_WAKE, %ecx
485 subl $cond_nwaiters, %ebx
492 subl $1, cond_lock(%ebx)
499 leal cond_lock(%ebx), %eax
501 #if (LLL_SHARED-LLL_PRIVATE) > 255
504 cmpl $-1, dep_mutex(%ebx)
507 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
509 addl $LLL_PRIVATE, %ecx
511 call __lll_unlock_wake
513 /* Wake up all waiters to make sure no signal gets lost. */
516 addl $cond_futex, %ebx
517 #if FUTEX_PRIVATE_FLAG > 255
520 cmpl $-1, dep_mutex-cond_futex(%ebx)
523 #ifdef __ASSUME_PRIVATE_FUTEX
524 andl $FUTEX_PRIVATE_FLAG, %ecx
526 andl %gs:PRIVATE_FUTEX, %ecx
528 addl $FUTEX_WAKE, %ecx
529 movl $SYS_futex, %eax
530 movl $0x7fffffff, %edx
533 5: movl 24+FRAME_SIZE(%esp), %eax
534 call __pthread_mutex_cond_lock
539 call __i686.get_pc_thunk.bx
540 addl $_GLOBAL_OFFSET_TABLE_, %ebx
542 call _Unwind_Resume@PLT
546 .size __condvar_w_cleanup, .-__condvar_w_cleanup
549 .section .gcc_except_table,"a",@progbits
551 .byte DW_EH_PE_omit # @LPStart format (omit)
552 .byte DW_EH_PE_omit # @TType format (omit)
553 .byte DW_EH_PE_sdata4 # call-site format
555 .uleb128 .Lcstend-.Lcstbegin
557 .long .LcleanupSTART-.LSTARTCODE
558 .long .Ladd_cond_futex-.LcleanupSTART
559 .long __condvar_w_cleanup-.LSTARTCODE
561 .long .Ladd_cond_futex-.LSTARTCODE
562 .long .Lsub_cond_futex-.Ladd_cond_futex
563 .long __condvar_w_cleanup2-.LSTARTCODE
565 .long .Lsub_cond_futex-.LSTARTCODE
566 .long .LcleanupEND-.Lsub_cond_futex
567 .long __condvar_w_cleanup-.LSTARTCODE
569 .long .LcallUR-.LSTARTCODE
570 .long .LENDCODE-.LcallUR
576 .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
577 .globl __i686.get_pc_thunk.bx
578 .hidden __i686.get_pc_thunk.bx
579 .type __i686.get_pc_thunk.bx,@function
580 __i686.get_pc_thunk.bx:
583 .size __i686.get_pc_thunk.bx,.-__i686.get_pc_thunk.bx
587 .hidden DW.ref.__gcc_personality_v0
588 .weak DW.ref.__gcc_personality_v0
589 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
591 .type DW.ref.__gcc_personality_v0, @object
592 .size DW.ref.__gcc_personality_v0, 4
593 DW.ref.__gcc_personality_v0:
594 .long __gcc_personality_v0