OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / uClibc / libpthread / nptl / sysdeps / unix / sysv / linux / i386 / i486 / pthread_cond_wait.S
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.
4
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.
9
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.
14
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
18    02111-1307 USA.  */
19
20 #include <sysdep.h>
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>
27
28
29         .text
30
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
35         .align  16
36 __pthread_cond_wait:
37 .LSTARTCODE:
38         cfi_startproc
39 #ifdef SHARED
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)
43 #else
44         cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
45         cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
46 #endif
47
48         pushl   %ebp
49         cfi_adjust_cfa_offset(4)
50         cfi_rel_offset(%ebp, 0)
51         pushl   %edi
52         cfi_adjust_cfa_offset(4)
53         cfi_rel_offset(%edi, 0)
54         pushl   %esi
55         cfi_adjust_cfa_offset(4)
56         cfi_rel_offset(%esi, 0)
57         pushl   %ebx
58         cfi_adjust_cfa_offset(4)
59         cfi_rel_offset(%ebx, 0)
60
61         xorl    %esi, %esi
62         movl    20(%esp), %ebx
63
64         /* Get internal lock.  */
65         movl    $1, %edx
66         xorl    %eax, %eax
67         LOCK
68 #if cond_lock == 0
69         cmpxchgl %edx, (%ebx)
70 #else
71         cmpxchgl %edx, cond_lock(%ebx)
72 #endif
73         jnz     1f
74
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)
78         movl    24(%esp), %eax
79         je      15f
80         movl    %eax, dep_mutex(%ebx)
81
82         /* Unlock the mutex.  */
83 15:     xorl    %edx, %edx
84         call    __pthread_mutex_unlock_usercnt
85
86         testl   %eax, %eax
87         jne     12f
88
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)
93
94 #define FRAME_SIZE 20
95         subl    $FRAME_SIZE, %esp
96         cfi_adjust_cfa_offset(FRAME_SIZE)
97         cfi_remember_state
98
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
103         movl    %edi, 4(%esp)
104         movl    %edx, 8(%esp)
105         movl    %eax, 12(%esp)
106
107         /* Reset the pi-requeued flag.  */
108 8:      movl    $0, 16(%esp)
109         movl    cond_futex(%ebx), %ebp
110
111         /* Unlock.  */
112         LOCK
113 #if cond_lock == 0
114         subl    $1, (%ebx)
115 #else
116         subl    $1, cond_lock(%ebx)
117 #endif
118         jne     3f
119
120 .LcleanupSTART:
121 4:      call    __pthread_enable_asynccancel
122         movl    %eax, (%esp)
123
124         xorl    %ecx, %ecx
125         cmpl    $-1, dep_mutex(%ebx)
126         sete    %cl
127         je      18f
128
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
134         cmpl    $PI_BIT, %eax
135         jne     18f
136
137         movl    $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
138         movl    %ebp, %edx
139         xorl    %esi, %esi
140         addl    $cond_futex, %ebx
141         movl    $SYS_futex, %eax
142         ENTER_KERNEL
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.  */
146         cmpl    $0, %eax
147         sete    16(%esp)
148         je      19f
149
150         /* Normal and PI futexes dont mix. Use normal futex functions only
151            if the kernel does not support the PI futex functions.  */
152         cmpl    $-ENOSYS, %eax
153         jne     19f
154         xorl    %ecx, %ecx
155
156 18:     subl    $1, %ecx
157 #ifdef __ASSUME_PRIVATE_FUTEX
158         andl    $FUTEX_PRIVATE_FLAG, %ecx
159 #else
160         andl    %gs:PRIVATE_FUTEX, %ecx
161 #endif
162 #if FUTEX_WAIT != 0
163         addl    $FUTEX_WAIT, %ecx
164 #endif
165         movl    %ebp, %edx
166         addl    $cond_futex, %ebx
167 .Ladd_cond_futex:
168         movl    $SYS_futex, %eax
169         ENTER_KERNEL
170         subl    $cond_futex, %ebx
171 .Lsub_cond_futex:
172
173 19:     movl    (%esp), %eax
174         call    __pthread_disable_asynccancel
175 .LcleanupEND:
176
177         /* Lock.  */
178         movl    $1, %edx
179         xorl    %eax, %eax
180         LOCK
181 #if cond_lock == 0
182         cmpxchgl %edx, (%ebx)
183 #else
184         cmpxchgl %edx, cond_lock(%ebx)
185 #endif
186         jnz     5f
187
188 6:      movl    broadcast_seq(%ebx), %eax
189         cmpl    12(%esp), %eax
190         jne     16f
191
192         movl    woken_seq(%ebx), %eax
193         movl    woken_seq+4(%ebx), %ecx
194
195         movl    wakeup_seq(%ebx), %edi
196         movl    wakeup_seq+4(%ebx), %edx
197
198         cmpl    8(%esp), %edx
199         jne     7f
200         cmpl    4(%esp), %edi
201         je      8b
202
203 7:      cmpl    %ecx, %edx
204         jne     9f
205         cmp     %eax, %edi
206         je      8b
207
208 9:      addl    $1, woken_seq(%ebx)
209         adcl    $0, woken_seq+4(%ebx)
210
211         /* Unlock */
212 16:     subl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
213
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
218         jne     17f
219         movl    cond_nwaiters(%ebx), %eax
220         andl    $~((1 << nwaiters_shift) - 1), %eax
221         jne     17f
222
223         addl    $cond_nwaiters, %ebx
224         movl    $SYS_futex, %eax
225 #if FUTEX_PRIVATE_FLAG > 255
226         xorl    %ecx, %ecx
227 #endif
228         cmpl    $-1, dep_mutex-cond_nwaiters(%ebx)
229         sete    %cl
230         subl    $1, %ecx
231 #ifdef __ASSUME_PRIVATE_FUTEX
232         andl    $FUTEX_PRIVATE_FLAG, %ecx
233 #else
234         andl    %gs:PRIVATE_FUTEX, %ecx
235 #endif
236         addl    $FUTEX_WAKE, %ecx
237         movl    $1, %edx
238         ENTER_KERNEL
239         subl    $cond_nwaiters, %ebx
240
241 17:     LOCK
242 #if cond_lock == 0
243         subl    $1, (%ebx)
244 #else
245         subl    $1, cond_lock(%ebx)
246 #endif
247         jne     10f
248
249         /* With requeue_pi, the mutex lock is held in the kernel.  */
250 11:     movl    24+FRAME_SIZE(%esp), %eax
251         movl    16(%esp), %ecx
252         testl   %ecx, %ecx
253         jnz     21f
254
255         call    __pthread_mutex_cond_lock
256 20:     addl    $FRAME_SIZE, %esp
257         cfi_adjust_cfa_offset(-FRAME_SIZE);
258
259 14:     popl    %ebx
260         cfi_adjust_cfa_offset(-4)
261         cfi_restore(%ebx)
262         popl    %esi
263         cfi_adjust_cfa_offset(-4)
264         cfi_restore(%esi)
265         popl    %edi
266         cfi_adjust_cfa_offset(-4)
267         cfi_restore(%edi)
268         popl    %ebp
269         cfi_adjust_cfa_offset(-4)
270         cfi_restore(%ebp)
271
272         /* We return the result of the mutex_lock operation.  */
273         ret
274
275         cfi_restore_state
276
277 21:     call    __pthread_mutex_cond_lock_adjust
278         xorl    %eax, %eax
279         jmp     20b
280
281         cfi_adjust_cfa_offset(-FRAME_SIZE);
282         /* Initial locking failed.  */
283 1:
284 #if cond_lock == 0
285         movl    %ebx, %edx
286 #else
287         leal    cond_lock(%ebx), %edx
288 #endif
289 #if (LLL_SHARED-LLL_PRIVATE) > 255
290         xorl    %ecx, %ecx
291 #endif
292         cmpl    $-1, dep_mutex(%ebx)
293         setne   %cl
294         subl    $1, %ecx
295         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
296 #if LLL_PRIVATE != 0
297         addl    $LLL_PRIVATE, %ecx
298 #endif
299         call    __lll_lock_wait
300         jmp     2b
301
302         /* The initial unlocking of the mutex failed.  */
303 12:
304         LOCK
305 #if cond_lock == 0
306         subl    $1, (%ebx)
307 #else
308         subl    $1, cond_lock(%ebx)
309 #endif
310         jne     14b
311
312         movl    %eax, %esi
313 #if cond_lock == 0
314         movl    %ebx, %eax
315 #else
316         leal    cond_lock(%ebx), %eax
317 #endif
318 #if (LLL_SHARED-LLL_PRIVATE) > 255
319         xorl    %ecx, %ecx
320 #endif
321         cmpl    $-1, dep_mutex(%ebx)
322         setne   %cl
323         subl    $1, %ecx
324         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
325 #if LLL_PRIVATE != 0
326         addl    $LLL_PRIVATE, %ecx
327 #endif
328         call    __lll_unlock_wake
329
330         movl    %esi, %eax
331         jmp     14b
332
333         cfi_adjust_cfa_offset(FRAME_SIZE)
334
335         /* Unlock in loop requires wakeup.  */
336 3:
337 #if cond_lock == 0
338         movl    %ebx, %eax
339 #else
340         leal    cond_lock(%ebx), %eax
341 #endif
342 #if (LLL_SHARED-LLL_PRIVATE) > 255
343         xorl    %ecx, %ecx
344 #endif
345         cmpl    $-1, dep_mutex(%ebx)
346         setne   %cl
347         subl    $1, %ecx
348         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
349 #if LLL_PRIVATE != 0
350         addl    $LLL_PRIVATE, %ecx
351 #endif
352         call    __lll_unlock_wake
353         jmp     4b
354
355         /* Locking in loop failed.  */
356 5:
357 #if cond_lock == 0
358         movl    %ebx, %edx
359 #else
360         leal    cond_lock(%ebx), %edx
361 #endif
362 #if (LLL_SHARED-LLL_PRIVATE) > 255
363         xorl    %ecx, %ecx
364 #endif
365         cmpl    $-1, dep_mutex(%ebx)
366         setne   %cl
367         subl    $1, %ecx
368         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
369 #if LLL_PRIVATE != 0
370         addl    $LLL_PRIVATE, %ecx
371 #endif
372         call    __lll_lock_wait
373         jmp     6b
374
375         /* Unlock after loop requires wakeup.  */
376 10:
377 #if cond_lock == 0
378         movl    %ebx, %eax
379 #else
380         leal    cond_lock(%ebx), %eax
381 #endif
382 #if (LLL_SHARED-LLL_PRIVATE) > 255
383         xorl    %ecx, %ecx
384 #endif
385         cmpl    $-1, dep_mutex(%ebx)
386         setne   %cl
387         subl    $1, %ecx
388         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
389 #if LLL_PRIVATE != 0
390         addl    $LLL_PRIVATE, %ecx
391 #endif
392         call    __lll_unlock_wake
393         jmp     11b
394         .size   __pthread_cond_wait, .-__pthread_cond_wait
395 weak_alias(__pthread_cond_wait, pthread_cond_wait)
396
397
398         .type   __condvar_w_cleanup2, @function
399 __condvar_w_cleanup2:
400         subl    $cond_futex, %ebx
401         .size   __condvar_w_cleanup2, .-__condvar_w_cleanup2
402 .LSbl4:
403         .type   __condvar_w_cleanup, @function
404 __condvar_w_cleanup:
405         movl    %eax, %esi
406
407         /* Get internal lock.  */
408         movl    $1, %edx
409         xorl    %eax, %eax
410         LOCK
411 #if cond_lock == 0
412         cmpxchgl %edx, (%ebx)
413 #else
414         cmpxchgl %edx, cond_lock(%ebx)
415 #endif
416         jz      1f
417
418 #if cond_lock == 0
419         movl    %ebx, %edx
420 #else
421         leal    cond_lock(%ebx), %edx
422 #endif
423 #if (LLL_SHARED-LLL_PRIVATE) > 255
424         xorl    %ecx, %ecx
425 #endif
426         cmpl    $-1, dep_mutex(%ebx)
427         setne   %cl
428         subl    $1, %ecx
429         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
430 #if LLL_PRIVATE != 0
431         addl    $LLL_PRIVATE, %ecx
432 #endif
433         call    __lll_lock_wait
434
435 1:      movl    broadcast_seq(%ebx), %eax
436         cmpl    12(%esp), %eax
437         jne     3f
438
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
445         jb      6f
446         ja      7f
447         cmpl    wakeup_seq(%ebx), %eax
448         jbe     7f
449
450 6:      addl    $1, wakeup_seq(%ebx)
451         adcl    $0, wakeup_seq+4(%ebx)
452         addl    $1, cond_futex(%ebx)
453
454 7:      addl    $1, woken_seq(%ebx)
455         adcl    $0, woken_seq+4(%ebx)
456
457 3:      subl    $(1 << nwaiters_shift), cond_nwaiters(%ebx)
458
459         /* Wake up a thread which wants to destroy the condvar object.  */
460         xorl    %edi, %edi
461         movl    total_seq(%ebx), %eax
462         andl    total_seq+4(%ebx), %eax
463         cmpl    $0xffffffff, %eax
464         jne     4f
465         movl    cond_nwaiters(%ebx), %eax
466         andl    $~((1 << nwaiters_shift) - 1), %eax
467         jne     4f
468
469         addl    $cond_nwaiters, %ebx
470         movl    $SYS_futex, %eax
471 #if FUTEX_PRIVATE_FLAG > 255
472         xorl    %ecx, %ecx
473 #endif
474         cmpl    $-1, dep_mutex-cond_nwaiters(%ebx)
475         sete    %cl
476         subl    $1, %ecx
477 #ifdef __ASSUME_PRIVATE_FUTEX
478         andl    $FUTEX_PRIVATE_FLAG, %ecx
479 #else
480         andl    %gs:PRIVATE_FUTEX, %ecx
481 #endif
482         addl    $FUTEX_WAKE, %ecx
483         movl    $1, %edx
484         ENTER_KERNEL
485         subl    $cond_nwaiters, %ebx
486         movl    $1, %edi
487
488 4:      LOCK
489 #if cond_lock == 0
490         subl    $1, (%ebx)
491 #else
492         subl    $1, cond_lock(%ebx)
493 #endif
494         je      2f
495
496 #if cond_lock == 0
497         movl    %ebx, %eax
498 #else
499         leal    cond_lock(%ebx), %eax
500 #endif
501 #if (LLL_SHARED-LLL_PRIVATE) > 255
502         xorl    %ecx, %ecx
503 #endif
504         cmpl    $-1, dep_mutex(%ebx)
505         setne   %cl
506         subl    $1, %ecx
507         andl    $(LLL_SHARED-LLL_PRIVATE), %ecx
508 #if LLL_PRIVATE != 0
509         addl    $LLL_PRIVATE, %ecx
510 #endif
511         call    __lll_unlock_wake
512
513         /* Wake up all waiters to make sure no signal gets lost.  */
514 2:      testl   %edi, %edi
515         jnz     5f
516         addl    $cond_futex, %ebx
517 #if FUTEX_PRIVATE_FLAG > 255
518         xorl    %ecx, %ecx
519 #endif
520         cmpl    $-1, dep_mutex-cond_futex(%ebx)
521         sete    %cl
522         subl    $1, %ecx
523 #ifdef __ASSUME_PRIVATE_FUTEX
524         andl    $FUTEX_PRIVATE_FLAG, %ecx
525 #else
526         andl    %gs:PRIVATE_FUTEX, %ecx
527 #endif
528         addl    $FUTEX_WAKE, %ecx
529         movl    $SYS_futex, %eax
530         movl    $0x7fffffff, %edx
531         ENTER_KERNEL
532
533 5:      movl    24+FRAME_SIZE(%esp), %eax
534         call    __pthread_mutex_cond_lock
535
536         movl    %esi, (%esp)
537 .LcallUR:
538 #ifdef __PIC__
539         call    __i686.get_pc_thunk.bx
540         addl    $_GLOBAL_OFFSET_TABLE_, %ebx
541 #endif
542         call    _Unwind_Resume@PLT
543         hlt
544 .LENDCODE:
545         cfi_endproc
546         .size   __condvar_w_cleanup, .-__condvar_w_cleanup
547
548
549         .section .gcc_except_table,"a",@progbits
550 .LexceptSTART:
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
554                                                 # DW_EH_PE_sdata4
555         .uleb128 .Lcstend-.Lcstbegin
556 .Lcstbegin:
557         .long   .LcleanupSTART-.LSTARTCODE
558         .long   .Ladd_cond_futex-.LcleanupSTART
559         .long   __condvar_w_cleanup-.LSTARTCODE
560         .uleb128  0
561         .long   .Ladd_cond_futex-.LSTARTCODE
562         .long   .Lsub_cond_futex-.Ladd_cond_futex
563         .long   __condvar_w_cleanup2-.LSTARTCODE
564         .uleb128  0
565         .long   .Lsub_cond_futex-.LSTARTCODE
566         .long   .LcleanupEND-.Lsub_cond_futex
567         .long   __condvar_w_cleanup-.LSTARTCODE
568         .uleb128  0
569         .long   .LcallUR-.LSTARTCODE
570         .long   .LENDCODE-.LcallUR
571         .long   0
572         .uleb128  0
573 .Lcstend:
574
575 #ifdef __PIC__
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:
581         movl (%esp), %ebx;
582         ret
583         .size   __i686.get_pc_thunk.bx,.-__i686.get_pc_thunk.bx
584 #endif
585
586 #ifdef SHARED
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
590         .align 4
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
595 #endif