OSDN Git Service

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