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 <shlib-compat.h>
22 #include <lowlevellock.h>
23 #include <lowlevelcond.h>
24 #include <tcb-offsets.h>
25 #include <pthread-errnos.h>
26 #include <pthread-pi-defines.h>
27 #include <kernel-features.h>
32 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
33 .globl __pthread_cond_wait
34 .type __pthread_cond_wait, @function
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 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
399 .type __condvar_w_cleanup2, @function
400 __condvar_w_cleanup2:
401 subl $cond_futex, %ebx
402 .size __condvar_w_cleanup2, .-__condvar_w_cleanup2
404 .type __condvar_w_cleanup, @function
408 /* Get internal lock. */
413 cmpxchgl %edx, (%ebx)
415 cmpxchgl %edx, cond_lock(%ebx)
422 leal cond_lock(%ebx), %edx
424 #if (LLL_SHARED-LLL_PRIVATE) > 255
427 cmpl $-1, dep_mutex(%ebx)
430 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
432 addl $LLL_PRIVATE, %ecx
436 1: movl broadcast_seq(%ebx), %eax
440 /* We increment the wakeup_seq counter only if it is lower than
441 total_seq. If this is not the case the thread was woken and
442 then canceled. In this case we ignore the signal. */
443 movl total_seq(%ebx), %eax
444 movl total_seq+4(%ebx), %edi
445 cmpl wakeup_seq+4(%ebx), %edi
448 cmpl wakeup_seq(%ebx), %eax
451 6: addl $1, wakeup_seq(%ebx)
452 adcl $0, wakeup_seq+4(%ebx)
453 addl $1, cond_futex(%ebx)
455 7: addl $1, woken_seq(%ebx)
456 adcl $0, woken_seq+4(%ebx)
458 3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
460 /* Wake up a thread which wants to destroy the condvar object. */
462 movl total_seq(%ebx), %eax
463 andl total_seq+4(%ebx), %eax
464 cmpl $0xffffffff, %eax
466 movl cond_nwaiters(%ebx), %eax
467 andl $~((1 << nwaiters_shift) - 1), %eax
470 addl $cond_nwaiters, %ebx
471 movl $SYS_futex, %eax
472 #if FUTEX_PRIVATE_FLAG > 255
475 cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
478 #ifdef __ASSUME_PRIVATE_FUTEX
479 andl $FUTEX_PRIVATE_FLAG, %ecx
481 andl %gs:PRIVATE_FUTEX, %ecx
483 addl $FUTEX_WAKE, %ecx
486 subl $cond_nwaiters, %ebx
493 subl $1, cond_lock(%ebx)
500 leal cond_lock(%ebx), %eax
502 #if (LLL_SHARED-LLL_PRIVATE) > 255
505 cmpl $-1, dep_mutex(%ebx)
508 andl $(LLL_SHARED-LLL_PRIVATE), %ecx
510 addl $LLL_PRIVATE, %ecx
512 call __lll_unlock_wake
514 /* Wake up all waiters to make sure no signal gets lost. */
517 addl $cond_futex, %ebx
518 #if FUTEX_PRIVATE_FLAG > 255
521 cmpl $-1, dep_mutex-cond_futex(%ebx)
524 #ifdef __ASSUME_PRIVATE_FUTEX
525 andl $FUTEX_PRIVATE_FLAG, %ecx
527 andl %gs:PRIVATE_FUTEX, %ecx
529 addl $FUTEX_WAKE, %ecx
530 movl $SYS_futex, %eax
531 movl $0x7fffffff, %edx
534 5: movl 24+FRAME_SIZE(%esp), %eax
535 call __pthread_mutex_cond_lock
543 .size __condvar_w_cleanup, .-__condvar_w_cleanup
546 .section .gcc_except_table,"a",@progbits
548 .byte DW_EH_PE_omit # @LPStart format (omit)
549 .byte DW_EH_PE_omit # @TType format (omit)
550 .byte DW_EH_PE_sdata4 # call-site format
552 .uleb128 .Lcstend-.Lcstbegin
554 .long .LcleanupSTART-.LSTARTCODE
555 .long .Ladd_cond_futex-.LcleanupSTART
556 .long __condvar_w_cleanup-.LSTARTCODE
558 .long .Ladd_cond_futex-.LSTARTCODE
559 .long .Lsub_cond_futex-.Ladd_cond_futex
560 .long __condvar_w_cleanup2-.LSTARTCODE
562 .long .Lsub_cond_futex-.LSTARTCODE
563 .long .LcleanupEND-.Lsub_cond_futex
564 .long __condvar_w_cleanup-.LSTARTCODE
566 .long .LcallUR-.LSTARTCODE
567 .long .LENDCODE-.LcallUR
573 .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
574 .globl __i686.get_pc_thunk.cx
575 .hidden __i686.get_pc_thunk.cx
576 .type __i686.get_pc_thunk.cx,@function
577 __i686.get_pc_thunk.cx:
580 .size __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
584 .hidden DW.ref.__gcc_personality_v0
585 .weak DW.ref.__gcc_personality_v0
586 .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
588 .type DW.ref.__gcc_personality_v0, @object
589 .size DW.ref.__gcc_personality_v0, 4
590 DW.ref.__gcc_personality_v0:
591 .long __gcc_personality_v0