2.5-18.1
[glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / i486 / pthread_cond_timedwait.S
blobf481a8e43c55654a05904060f1d41b24aca555b2
1 /* Copyright (C) 2002, 2003, 2004, 2006 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
18    02111-1307 USA.  */
20 #include <sysdep.h>
21 #include <shlib-compat.h>
22 #include <lowlevelcond.h>
23 #include <pthread-errnos.h>
25 #ifdef UP
26 # define LOCK
27 #else
28 # define LOCK lock
29 #endif
31 #define SYS_gettimeofday        __NR_gettimeofday
32 #define SYS_futex               240
33 #define FUTEX_WAIT              0
34 #define FUTEX_WAKE              1
37         .text
39 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
40                                const struct timespec *abstime)  */
41         .globl  __pthread_cond_timedwait
42         .type   __pthread_cond_timedwait, @function
43         .align  16
44 __pthread_cond_timedwait:
45 .LSTARTCODE:
46         pushl   %ebp
47 .Lpush_ebp:
48         pushl   %edi
49 .Lpush_edi:
50         pushl   %esi
51 .Lpush_esi:
52         pushl   %ebx
53 .Lpush_ebx:
55         movl    20(%esp), %ebx
56         movl    28(%esp), %ebp
58         cmpl    $1000000000, 4(%ebp)
59         movl    $EINVAL, %eax
60         jae     18f
62         /* Get internal lock.  */
63         movl    $1, %edx
64         xorl    %eax, %eax
65         LOCK
66 #if cond_lock == 0
67         cmpxchgl %edx, (%ebx)
68 #else
69         cmpxchgl %edx, cond_lock(%ebx)
70 #endif
71         jnz     1f
73         /* Store the reference to the mutex.  If there is already a
74            different value in there this is a bad user bug.  */
75 2:      cmpl    $-1, dep_mutex(%ebx)
76         movl    24(%esp), %eax
77         je      17f
78         movl    %eax, dep_mutex(%ebx)
80         /* Unlock the mutex.  */
81 17:     xorl    %edx, %edx
82         call    __pthread_mutex_unlock_usercnt
84         testl   %eax, %eax
85         jne     16f
87         addl    $1, total_seq(%ebx)
88         adcl    $0, total_seq+4(%ebx)
89         addl    $1, cond_futex(%ebx)
90         addl    $(1 << clock_bits), cond_nwaiters(%ebx)
92 #define FRAME_SIZE 24
93         subl    $FRAME_SIZE, %esp
94 .Lsubl:
96         /* Get and store current wakeup_seq value.  */
97         movl    wakeup_seq(%ebx), %edi
98         movl    wakeup_seq+4(%ebx), %edx
99         movl    broadcast_seq(%ebx), %eax
100         movl    %edi, 12(%esp)
101         movl    %edx, 16(%esp)
102         movl    %eax, 20(%esp)
104         /* Get the current time.  */
105 8:      movl    %ebx, %edx
106 #ifdef __NR_clock_gettime
107         /* Get the clock number.  */
108         movl    cond_nwaiters(%ebx), %ebx
109         andl    $((1 << clock_bits) - 1), %ebx
110         /* Only clocks 0 and 1 are allowed so far.  Both are handled in the
111            kernel.  */
112         leal    4(%esp), %ecx
113         movl    $__NR_clock_gettime, %eax
114         ENTER_KERNEL
115 # ifndef __ASSUME_POSIX_TIMERS
116         cmpl    $-ENOSYS, %eax
117         je      19f
118 # endif
119         movl    %edx, %ebx
121         /* Compute relative timeout.  */
122         movl    (%ebp), %ecx
123         movl    4(%ebp), %edx
124         subl    4(%esp), %ecx
125         subl    8(%esp), %edx
126 #else
127         /* Get the current time.  */
128         leal    4(%esp), %ebx
129         xorl    %ecx, %ecx
130         movl    $SYS_gettimeofday, %eax
131         ENTER_KERNEL
132         movl    %edx, %ebx
134         /* Compute relative timeout.  */
135         movl    8(%esp), %eax
136         movl    $1000, %edx
137         mul     %edx            /* Milli seconds to nano seconds.  */
138         movl    (%ebp), %ecx
139         movl    4(%ebp), %edx
140         subl    4(%esp), %ecx
141         subl    %eax, %edx
142 #endif
143         jns     12f
144         addl    $1000000000, %edx
145         subl    $1, %ecx
146 12:     testl   %ecx, %ecx
147         movl    $-ETIMEDOUT, %esi
148         js      6f
150         /* Store relative timeout.  */
151 21:     movl    %ecx, 4(%esp)
152         movl    %edx, 8(%esp)
154         movl    cond_futex(%ebx), %edi
156         /* Unlock.  */
157         LOCK
158 #if cond_lock == 0
159         subl    $1, (%ebx)
160 #else
161         subl    $1, cond_lock(%ebx)
162 #endif
163         jne     3f
165 .LcleanupSTART:
166 4:      call    __pthread_enable_asynccancel
167         movl    %eax, (%esp)
169         leal    4(%esp), %esi
170         xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
171         movl    %edi, %edx
172         addl    $cond_futex, %ebx
173 .Ladd_cond_futex:
174         movl    $SYS_futex, %eax
175         ENTER_KERNEL
176         subl    $cond_futex, %ebx
177 .Lsub_cond_futex:
178         movl    %eax, %esi
180         movl    (%esp), %eax
181         call    __pthread_disable_asynccancel
182 .LcleanupEND:
184         /* Lock.  */
185         movl    $1, %edx
186         xorl    %eax, %eax
187         LOCK
188 #if cond_lock == 0
189         cmpxchgl %edx, (%ebx)
190 #else
191         cmpxchgl %edx, cond_lock(%ebx)
192 #endif
193         jnz     5f
195 6:      movl    broadcast_seq(%ebx), %eax
196         cmpl    20(%esp), %eax
197         jne     23f
199         movl    woken_seq(%ebx), %eax
200         movl    woken_seq+4(%ebx), %ecx
202         movl    wakeup_seq(%ebx), %edi
203         movl    wakeup_seq+4(%ebx), %edx
205         cmpl    16(%esp), %edx
206         jne     7f
207         cmpl    12(%esp), %edi
208         je      15f
210 7:      cmpl    %ecx, %edx
211         jne     9f
212         cmp     %eax, %edi
213         jne     9f
215 15:     cmpl    $-ETIMEDOUT, %esi
216         jne     8b
218         addl    $1, wakeup_seq(%ebx)
219         adcl    $0, wakeup_seq+4(%ebx)
220         addl    $1, cond_futex(%ebx)
221         movl    $ETIMEDOUT, %esi
222         jmp     14f
224 23:     xorl    %esi, %esi
225         jmp     24f
227 9:      xorl    %esi, %esi
228 14:     addl    $1, woken_seq(%ebx)
229         adcl    $0, woken_seq+4(%ebx)
231 24:     subl    $(1 << clock_bits), cond_nwaiters(%ebx)
233         /* Wake up a thread which wants to destroy the condvar object.  */
234         movl    total_seq(%ebx), %eax
235         andl    total_seq+4(%ebx), %eax
236         cmpl    $0xffffffff, %eax
237         jne     25f
238         movl    cond_nwaiters(%ebx), %eax
239         andl    $~((1 << clock_bits) - 1), %eax
240         jne     25f
242         addl    $cond_nwaiters, %ebx
243         movl    $SYS_futex, %eax
244         movl    $FUTEX_WAKE, %ecx
245         movl    $1, %edx
246         ENTER_KERNEL
247         subl    $cond_nwaiters, %ebx
249 25:     LOCK
250 #if cond_lock == 0
251         subl    $1, (%ebx)
252 #else
253         subl    $1, cond_lock(%ebx)
254 #endif
255         jne     10f
257         /* Remove cancellation handler.  */
258 11:     movl    24+FRAME_SIZE(%esp), %eax
259         call    __pthread_mutex_cond_lock
260         addl    $FRAME_SIZE, %esp
261 .Laddl:
263         /* We return the result of the mutex_lock operation if it failed.  */
264         testl   %eax, %eax
265 #ifdef HAVE_CMOV
266         cmovel  %esi, %eax
267 #else
268         jne     22f
269         movl    %esi, %eax
271 #endif
273 18:     popl    %ebx
274 .Lpop_ebx:
275         popl    %esi
276 .Lpop_esi:
277         popl    %edi
278 .Lpop_edi:
279         popl    %ebp
280 .Lpop_ebp:
282         ret
284         /* Initial locking failed.  */
286 .LSbl1:
287 #if cond_lock == 0
288         movl    %ebx, %ecx
289 #else
290         leal    cond_lock(%ebx), %ecx
291 #endif
292         call    __lll_mutex_lock_wait
293         jmp     2b
295         /* Unlock in loop requires wakeup.  */
297 .LSbl2:
298 #if cond_lock == 0
299         movl    %ebx, %eax
300 #else
301         leal    cond_lock(%ebx), %eax
302 #endif
303         call    __lll_mutex_unlock_wake
304         jmp     4b
306         /* Locking in loop failed.  */
308 #if cond_lock == 0
309         movl    %ebx, %ecx
310 #else
311         leal    cond_lock(%ebx), %ecx
312 #endif
313         call    __lll_mutex_lock_wait
314         jmp     6b
316         /* Unlock after loop requires wakeup.  */
318 #if cond_lock == 0
319         movl    %ebx, %eax
320 #else
321         leal    cond_lock(%ebx), %eax
322 #endif
323         call    __lll_mutex_unlock_wake
324         jmp     11b
326         /* The initial unlocking of the mutex failed.  */
328 .LSbl3:
329         LOCK
330 #if cond_lock == 0
331         subl    $1, (%ebx)
332 #else
333         subl    $1, cond_lock(%ebx)
334 #endif
335         jne     18b
337         movl    %eax, %esi
338 #if cond_lock == 0
339         movl    %ebx, %eax
340 #else
341         leal    cond_lock(%ebx), %eax
342 #endif
343         call    __lll_mutex_unlock_wake
345         movl    %esi, %eax
346         jmp     18b
348 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
349         /* clock_gettime not available.  */
350 .LSbl4:
351 19:     leal    4(%esp), %ebx
352         xorl    %ecx, %ecx
353         movl    $SYS_gettimeofday, %eax
354         ENTER_KERNEL
355         movl    %edx, %ebx
357         /* Compute relative timeout.  */
358         movl    8(%esp), %eax
359         movl    $1000, %edx
360         mul     %edx            /* Milli seconds to nano seconds.  */
361         movl    (%ebp), %ecx
362         movl    4(%ebp), %edx
363         subl    4(%esp), %ecx
364         subl    %eax, %edx
365         jns     20f
366         addl    $1000000000, %edx
367         subl    $1, %ecx
368 20:     testl   %ecx, %ecx
369         movl    $-ETIMEDOUT, %esi
370         js      6b
371         jmp     21b
372 #endif
373         .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
374 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
375                   GLIBC_2_3_2)
378         .type   __condvar_tw_cleanup2, @function
379 __condvar_tw_cleanup2:
380         subl    $cond_futex, %ebx
381 .LSbl5:
382         .size   __condvar_tw_cleanup2, .-__condvar_tw_cleanup2
383         .type   __condvar_tw_cleanup, @function
384 __condvar_tw_cleanup:
385         movl    %eax, %esi
387         /* Get internal lock.  */
388         movl    $1, %edx
389         xorl    %eax, %eax
390         LOCK
391 #if cond_lock == 0
392         cmpxchgl %edx, (%ebx)
393 #else
394         cmpxchgl %edx, cond_lock(%ebx)
395 #endif
396         jz      1f
398 #if cond_lock == 0
399         movl    %ebx, %ecx
400 #else
401         leal    cond_lock(%ebx), %ecx
402 #endif
403         call    __lll_mutex_lock_wait
405 1:      movl    broadcast_seq(%ebx), %eax
406         cmpl    20(%esp), %eax
407         jne     3f
409         /* We increment the wakeup_seq counter only if it is lower than
410            total_seq.  If this is not the case the thread was woken and
411            then canceled.  In this case we ignore the signal.  */
412         movl    total_seq(%ebx), %eax
413         movl    total_seq+4(%ebx), %edi
414         cmpl    wakeup_seq+4(%ebx), %edi
415         jb      6f
416         ja      7f
417         cmpl    wakeup_seq(%ebx), %eax
418         jbe     7f
420 6:      addl    $1, wakeup_seq(%ebx)
421         adcl    $0, wakeup_seq+4(%ebx)
422         addl    $1, cond_futex(%ebx)
424 7:      addl    $1, woken_seq(%ebx)
425         adcl    $0, woken_seq+4(%ebx)
427 3:      subl    $(1 << clock_bits), cond_nwaiters(%ebx)
429         /* Wake up a thread which wants to destroy the condvar object.  */
430         xorl    %edi, %edi
431         movl    total_seq(%ebx), %eax
432         andl    total_seq+4(%ebx), %eax
433         cmpl    $0xffffffff, %eax
434         jne     4f
435         movl    cond_nwaiters(%ebx), %eax
436         andl    $~((1 << clock_bits) - 1), %eax
437         jne     4f
439         addl    $cond_nwaiters, %ebx
440         movl    $SYS_futex, %eax
441         movl    $FUTEX_WAKE, %ecx
442         movl    $1, %edx
443         ENTER_KERNEL
444         subl    $cond_nwaiters, %ebx
445         movl    $1, %edi
447 4:      LOCK
448 #if cond_lock == 0
449         subl    $1, (%ebx)
450 #else
451         subl    $1, cond_lock(%ebx)
452 #endif
453         je      2f
455 #if cond_lock == 0
456         movl    %ebx, %eax
457 #else
458         leal    cond_lock(%ebx), %eax
459 #endif
460         call    __lll_mutex_unlock_wake
462         /* Wake up all waiters to make sure no signal gets lost.  */
463 2:      testl   %edi, %edi
464         jnz     5f
465         addl    $cond_futex, %ebx
466         movl    $FUTEX_WAKE, %ecx
467         movl    $SYS_futex, %eax
468         movl    $0x7fffffff, %edx
469         ENTER_KERNEL
471 5:      movl    24+FRAME_SIZE(%esp), %eax
472         call    __pthread_mutex_cond_lock
474         movl    %esi, (%esp)
475 .LcallUR:
476         call    _Unwind_Resume
477         hlt
478 .LENDCODE:
479         .size   __condvar_tw_cleanup, .-__condvar_tw_cleanup
482         .section .gcc_except_table,"a",@progbits
483 .LexceptSTART:
484         .byte   0xff                            # @LPStart format (omit)
485         .byte   0xff                            # @TType format (omit)
486         .byte   0x0b                            # call-site format
487                                                 # DW_EH_PE_sdata4
488         .uleb128 .Lcstend-.Lcstbegin
489 .Lcstbegin:
490         .long   .LcleanupSTART-.LSTARTCODE
491         .long   .Ladd_cond_futex-.LcleanupSTART
492         .long   __condvar_tw_cleanup-.LSTARTCODE
493         .uleb128  0
494         .long   .Ladd_cond_futex-.LSTARTCODE
495         .long   .Lsub_cond_futex-.Ladd_cond_futex
496         .long   __condvar_tw_cleanup2-.LSTARTCODE
497         .uleb128  0
498         .long   .Lsub_cond_futex-.LSTARTCODE
499         .long   .LcleanupEND-.Lsub_cond_futex
500         .long   __condvar_tw_cleanup-.LSTARTCODE
501         .uleb128  0
502         .long   .LcallUR-.LSTARTCODE
503         .long   .LENDCODE-.LcallUR
504         .long   0
505         .uleb128  0
506 .Lcstend:
509         .section .eh_frame,"a",@progbits
510 .LSTARTFRAME:
511         .long   L(ENDCIE)-L(STARTCIE)           # Length of the CIE.
512 .LSTARTCIE:
513         .long   0                               # CIE ID.
514         .byte   1                               # Version number.
515 #ifdef SHARED
516         .string "zPLR"                          # NUL-terminated augmentation
517                                                 # string.
518 #else
519         .string "zPL"                           # NUL-terminated augmentation
520                                                 # string.
521 #endif
522         .uleb128 1                              # Code alignment factor.
523         .sleb128 -4                             # Data alignment factor.
524         .byte   8                               # Return address register
525                                                 # column.
526 #ifdef SHARED
527         .uleb128 7                              # Augmentation value length.
528         .byte   0x9b                            # Personality: DW_EH_PE_pcrel
529                                                 # + DW_EH_PE_sdata4
530                                                 # + DW_EH_PE_indirect
531         .long   DW.ref.__gcc_personality_v0-.
532         .byte   0x1b                            # LSDA Encoding: DW_EH_PE_pcrel
533                                                 # + DW_EH_PE_sdata4.
534         .byte   0x1b                            # FDE Encoding: DW_EH_PE_pcrel
535                                                 # + DW_EH_PE_sdata4.
536 #else
537         .uleb128 6                              # Augmentation value length.
538         .byte   0x0                             # Personality: absolute
539         .long   __gcc_personality_v0
540         .byte   0x0                             # LSDA Encoding: absolute
541 #endif
542         .byte 0x0c                              # DW_CFA_def_cfa
543         .uleb128 4
544         .uleb128 4
545         .byte   0x88                            # DW_CFA_offset, column 0x8
546         .uleb128 1
547         .align 4
548 .LENDCIE:
550         .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
551 .LSTARTFDE:
552         .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
553 #ifdef SHARED
554         .long   .LSTARTCODE-.                   # PC-relative start address
555                                                 # of the code
556 #else
557         .long   .LSTARTCODE                     # Start address of the code.
558 #endif
559         .long   .LENDCODE-.LSTARTCODE           # Length of the code.
560         .uleb128 4                              # Augmentation size
561 #ifdef SHARED
562         .long   .LexceptSTART-.
563 #else
564         .long   .LexceptSTART
565 #endif
566         .byte   0x40+.Lpush_ebp-.LSTARTCODE     # DW_CFA_advance_loc+N
567         .byte   14                              # DW_CFA_def_cfa_offset
568         .uleb128 8
569         .byte   0x85                            # DW_CFA_offset %ebp
570         .uleb128 2
571         .byte   0x40+ .Lpush_edi-.Lpush_ebp     # DW_CFA_advance_loc+N
572         .byte   14                              # DW_CFA_def_cfa_offset
573         .uleb128 12
574         .byte   0x87                            # DW_CFA_offset %edi
575         .uleb128 3
576         .byte   0x40+.Lpush_esi-.Lpush_edi      # DW_CFA_advance_loc+N
577         .byte   14                              # DW_CFA_def_cfa_offset
578         .uleb128 16
579         .byte   0x86                            # DW_CFA_offset %esi
580         .uleb128 4
581         .byte   0x40+.Lpush_ebx-.Lpush_esi      # DW_CFA_advance_loc+N
582         .byte   14                              # DW_CFA_def_cfa_offset
583         .uleb128 20
584         .byte   0x83                            # DW_CFA_offset %ebx
585         .uleb128 5
586         .byte   2                               # DW_CFA_advance_loc1
587         .byte   .Lsubl-.Lpush_ebx
588         .byte   14                              # DW_CFA_def_cfa_offset
589         .uleb128 20+FRAME_SIZE
590         .byte   3                               # DW_CFA_advance_loc2
591         .2byte  .Laddl-.Lsubl
592         .byte   14                              # DW_CFA_def_cfa_offset
593         .uleb128 20
594         .byte   0x40+.Lpop_ebx-.Laddl           # DW_CFA_advance_loc+N
595         .byte   14                              # DW_CFA_def_cfa_offset
596         .uleb128 16
597         .byte   0xc3                            # DW_CFA_restore %ebx
598         .byte   0x40+.Lpop_esi-.Lpop_ebx        # DW_CFA_advance_loc+N
599         .byte   14                              # DW_CFA_def_cfa_offset
600         .uleb128 12
601         .byte   0xc6                            # DW_CFA_restore %esi
602         .byte   0x40+.Lpop_edi-.Lpop_esi        # DW_CFA_advance_loc+N
603         .byte   14                              # DW_CFA_def_cfa_offset
604         .uleb128 8
605         .byte   0xc7                            # DW_CFA_restore %edi
606         .byte   0x40+.Lpop_ebp-.Lpop_edi        # DW_CFA_advance_loc+N
607         .byte   14                              # DW_CFA_def_cfa_offset
608         .uleb128 4
609         .byte   0xc5                            # DW_CFA_restore %ebp
610         .byte   0x40+.LSbl1-.Lpop_edi           # DW_CFA_advance_loc+N
611         .byte   14                              # DW_CFA_def_cfa_offset
612         .uleb128 20
613         .byte   0x40+.LSbl2-.LSbl1              # DW_CFA_advance_loc+N
614         .byte   14                              # DW_CFA_def_cfa_offset
615         .uleb128 20+FRAME_SIZE
616         .byte   0x85                            # DW_CFA_offset %ebp
617         .uleb128 2
618         .byte   0x87                            # DW_CFA_offset %edi
619         .uleb128 3
620         .byte   0x86                            # DW_CFA_offset %esi
621         .uleb128 4
622         .byte   0x83                            # DW_CFA_offset %ebx
623         .uleb128 5
624         .byte   0x40+.LSbl3-.LSbl2              # DW_CFA_advance_loc+N
625         .byte   14                              # DW_CFA_def_cfa_offset
626         .uleb128 20
627 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
628         .byte   0x40+.LSbl4-.LSbl3              # DW_CFA_advance_loc+N
629 #else
630         .byte   4                               # DW_CFA_advance_loc4
631         .long   .LSbl5-.LSbl3
632 #endif
633         .byte   14                              # DW_CFA_def_cfa_offset
634         .uleb128 20+FRAME_SIZE
635         .align  4
636 .LENDFDE:
638 #ifdef SHARED
639         .hidden DW.ref.__gcc_personality_v0
640         .weak   DW.ref.__gcc_personality_v0
641         .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
642         .align 4
643         .type   DW.ref.__gcc_personality_v0, @object
644         .size   DW.ref.__gcc_personality_v0, 4
645 DW.ref.__gcc_personality_v0:
646         .long   __gcc_personality_v0
647 #endif