Update.
[platform/upstream/glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / i486 / pthread_cond_timedwait.S
1 /* Copyright (C) 2002, 2003 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 <shlib-compat.h>
22 #include <lowlevelcond.h>
23 #include <pthread-errnos.h>
24
25 #ifdef UP
26 # define LOCK
27 #else
28 # define LOCK lock
29 #endif
30
31 #define SYS_gettimeofday        __NR_gettimeofday
32 #define SYS_futex               240
33 #define FUTEX_WAIT              0
34 #define FUTEX_WAKE              1
35
36
37         .text
38
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:
54
55         movl    20(%esp), %ebx
56         movl    28(%esp), %ebp
57
58         /* Get internal lock.  */
59         movl    $1, %eax
60         LOCK
61 #if cond_lock == 0
62         xaddl   %eax, (%ebx)
63 #else
64         xaddl   %eax, cond_lock(%ebx)
65 #endif
66         testl   %eax, %eax
67         jne     1f
68
69         /* Store the reference to the mutex.  If there is already a
70            different value in there this is a bad user bug.  */
71 2:      movl    24(%esp), %eax
72         movl    %eax, dep_mutex(%ebx)
73
74         /* Unlock the mutex.  */
75         xorl    %edx, %edx
76         call    __pthread_mutex_unlock_usercnt
77
78         testl   %eax, %eax
79         jne     16f
80
81         addl    $1, total_seq(%ebx)
82         adcl    $0, total_seq+4(%ebx)
83
84         subl    $20, %esp
85 .Lsubl:
86
87         /* Get and store current wakeup_seq value.  */
88         movl    wakeup_seq(%ebx), %edi
89         movl    wakeup_seq+4(%ebx), %edx
90         movl    %edi, 12(%esp)
91         movl    %edx, 16(%esp)
92
93         /* Unlock.  */
94 8:      LOCK
95 #if cond_lock == 0
96         subl    $1, (%ebx)
97 #else
98         subl    $1, cond_lock(%ebx)
99 #endif
100         jne     3f
101
102 .LcleanupSTART:
103 4:      call    __pthread_enable_asynccancel
104         movl    %eax, (%esp)
105
106         /* Get the current time.  */
107         movl    %ebx, %edx
108 .LebxmovedUR:
109 #ifdef __NR_clock_gettime
110         /* Get the clock number.  Note that the field in the condvar
111            structure stores the number minus 1.  */
112         movl    cond_clock(%ebx), %ebx
113         /* Only clocks 0 and 1 are allowed.  Both are handled in the
114            kernel.  */
115         leal    4(%esp), %ecx
116         movl    $__NR_clock_gettime, %eax
117         ENTER_KERNEL
118 # ifndef __ASSUME_POSIX_TIMERS
119         cmpl    $-ENOSYS, %eax
120         je      19f
121 # endif
122         movl    %edx, %ebx
123 .LebxbackUR:
124
125         /* Compute relative timeout.  */
126         movl    (%ebp), %ecx
127         movl    4(%ebp), %edx
128         subl    4(%esp), %ecx
129         subl    8(%esp), %edx
130 #else
131         /* Get the current time.  */
132         leal    4(%esp), %ebx
133         xorl    %ecx, %ecx
134         movl    $SYS_gettimeofday, %eax
135         ENTER_KERNEL
136         movl    %edx, %ebx
137 .LebxbackUR:
138
139         /* Compute relative timeout.  */
140         movl    8(%esp), %eax
141         movl    $1000, %edx
142         mul     %edx            /* Milli seconds to nano seconds.  */
143         movl    (%ebp), %ecx
144         movl    4(%ebp), %edx
145         subl    4(%esp), %ecx
146         subl    %eax, %edx
147 #endif
148         jns     12f
149         addl    $1000000000, %edx
150         subl    $1, %ecx
151 12:     testl   %ecx, %ecx
152         js      13f
153
154         /* Store relative timeout.  */
155 21:     movl    %ecx, 4(%esp)
156         movl    %edx, 8(%esp)
157         leal    4(%esp), %esi
158         xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
159         movl    %edi, %edx
160         addl    $wakeup_seq, %ebx
161 .Ladd_wakeup:
162         movl    $SYS_futex, %eax
163         ENTER_KERNEL
164         subl    $wakeup_seq, %ebx
165 .Lsub_wakeup:
166         movl    %eax, %esi
167
168         movl    (%esp), %eax
169         call    __pthread_disable_asynccancel
170 .LcleanupEND:
171
172         /* Lock.  */
173         movl    $1, %eax
174         LOCK
175 #if cond_lock == 0
176         xaddl   %eax, (%ebx)
177 #else
178         xaddl   %eax, cond_lock(%ebx)
179 #endif
180         testl   %eax, %eax
181         jne     5f
182
183 6:      movl    woken_seq(%ebx), %eax
184         movl    woken_seq+4(%ebx), %ecx
185
186         movl    wakeup_seq(%ebx), %edi
187         movl    wakeup_seq+4(%ebx), %edx
188
189         cmpl    16(%esp), %edx
190         ja      7f
191         jb      15f
192         cmpl    12(%esp), %edi
193         jbe     15f
194
195 7:      cmpl    %ecx, %edx
196         ja      9f
197         jb      15f
198         cmp     %eax, %edi
199         ja      9f
200
201 15:     cmpl    $-ETIMEDOUT, %esi
202         jne     8b
203
204 13:     addl    $1, wakeup_seq(%ebx)
205         adcl    $0, wakeup_seq+4(%ebx)
206         movl    $ETIMEDOUT, %esi
207         jmp     14f
208
209 9:      xorl    %esi, %esi
210 14:     addl    $1, woken_seq(%ebx)
211         adcl    $0, woken_seq+4(%ebx)
212
213         LOCK
214 #if cond_lock == 0
215         subl    $1, (%ebx)
216 #else
217         subl    $1, cond_lock(%ebx)
218 #endif
219         jne     10f
220
221         /* Remove cancellation handler.  */
222 11:     movl    44(%esp), %eax
223         call    __pthread_mutex_cond_lock
224         addl    $20, %esp
225 .Laddl:
226
227         /* We return the result of the mutex_lock operation if it failed.  */
228         testl   %eax, %eax
229         cmovel  %esi, %eax
230
231 18:     popl    %ebx
232 .Lpop_ebx:
233         popl    %esi
234 .Lpop_esi:
235         popl    %edi
236 .Lpop_edi:
237         popl    %ebp
238 .Lpop_ebp:
239
240         ret
241
242         /* Initial locking failed.  */
243 1:
244 .LSbl1:
245 #if cond_lock == 0
246         movl    %ebx, %ecx
247 #else
248         leal    cond_lock(%ebx), %ecx
249 #endif
250         call    __lll_mutex_lock_wait
251         jmp     2b
252
253         /* Unlock in loop requires waekup.  */
254 3:
255 .LSbl2:
256 #if cond_lock == 0
257         movl    %ebx, %eax
258 #else
259         leal    cond_lock(%ebx), %eax
260 #endif
261         call    __lll_mutex_unlock_wake
262         jmp     4b
263
264         /* Locking in loop failed.  */
265 5:
266 #if cond_lock == 0
267         movl    %ebx, %ecx
268 #else
269         leal    cond_lock(%ebx), %ecx
270 #endif
271         call    __lll_mutex_lock_wait
272         jmp     6b
273
274         /* Unlock after loop requires waekup.  */
275 10:
276 #if cond_lock == 0
277         movl    %ebx, %eax
278 #else
279         leal    cond_lock(%ebx), %eax
280 #endif
281         call    __lll_mutex_unlock_wake
282         jmp     11b
283
284         /* The initial unlocking of the mutex failed.  */
285 16:
286 .LSbl3:
287         LOCK
288 #if cond_lock == 0
289         subl    $1, (%ebx)
290 #else
291         subl    $1, cond_lock(%ebx)
292 #endif
293         jne     18b
294
295         movl    %eax, %esi
296 #if cond_lock == 0
297         movl    %ebx, %eax
298 #else
299         leal    cond_lock(%ebx), %eax
300 #endif
301         call    __lll_mutex_unlock_wake
302
303         movl    %esi, %eax
304         jmp     18b
305
306 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
307         /* clock_gettime not available.  */
308 .LSbl4:
309 19:     leal    4(%esp), %ebx
310         xorl    %ecx, %ecx
311         movl    $SYS_gettimeofday, %eax
312         ENTER_KERNEL
313         movl    %edx, %ebx
314
315         /* Compute relative timeout.  */
316         movl    8(%esp), %eax
317         movl    $1000, %edx
318         mul     %edx            /* Milli seconds to nano seconds.  */
319         movl    (%ebp), %ecx
320         movl    4(%ebp), %edx
321         subl    4(%esp), %ecx
322         subl    %eax, %edx
323         jns     20f
324         addl    $1000000000, %edx
325         subl    $1, %ecx
326 20:     testl   %ecx, %ecx
327         js      13b
328         jmp     21b
329 #endif
330         .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
331 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
332                   GLIBC_2_3_2)
333
334
335         .type   __condvar_tw_cleanup3, @function
336 __condvar_tw_cleanup3:
337         movl    40(%esp), %ebx
338 .LSbl5:
339         jmp     __condvar_tw_cleanup
340         .size   __condvar_tw_cleanup3, .-__condvar_tw_cleanup3
341         .type   __condvar_tw_cleanup2, @function
342 __condvar_tw_cleanup2:
343         subl    $wakeup_seq, %ebx
344         .size   __condvar_tw_cleanup2, .-__condvar_tw_cleanup2
345         .type   __condvar_tw_cleanup, @function
346 __condvar_tw_cleanup:
347         movl    %eax, %esi
348
349         /* Get internal lock.  */
350         movl    $1, %eax
351         LOCK
352 #if cond_lock == 0
353         xaddl   %eax, (%ebx)
354 #else
355         xaddl   %eax, cond_lock(%ebx)
356 #endif
357         testl   %eax, %eax
358         je      1f
359
360 #if cond_lock == 0
361         movl    %ebx, %ecx
362 #else
363         leal    cond_lock(%ebx), %ecx
364 #endif
365         call    __lll_mutex_lock_wait
366
367 1:      addl    $1, wakeup_seq(%ebx)
368         adcl    $0, wakeup_seq+4(%ebx)
369
370         addl    $1, woken_seq(%ebx)
371         adcl    $0, woken_seq+4(%ebx)
372
373         LOCK
374         subl    $1, cond_lock(%ebx)
375         je      2f
376
377 #if cond_lock == 0
378         movl    %ebx, %eax
379 #else
380         leal    cond_lock(%ebx), %eax
381 #endif
382         call    __lll_mutex_unlock_wake
383
384         /* Wake up all waiters to make sure no signal gets lost.  */
385 2:      addl    $wakeup_seq, %ebx
386         movl    $FUTEX_WAKE, %ecx
387         movl    $SYS_futex, %eax
388         movl    $0x7fffffff, %edx
389         ENTER_KERNEL
390
391         movl    44(%esp), %eax
392         call    __pthread_mutex_cond_lock
393
394         movl    %esi, (%esp)
395 .LcallUR:
396         call    _Unwind_Resume
397         hlt
398 .LENDCODE:
399         .size   __condvar_tw_cleanup, .-__condvar_tw_cleanup
400
401
402         .section .gcc_except_table,"a",@progbits
403 .LexceptSTART:
404         .byte   0xff                            # @LPStart format (omit)
405         .byte   0xff                            # @TType format (omit)
406         .byte   0x0b                            # call-site format
407                                                 # DW_EH_PE_sdata4
408         .uleb128 .Lcstend-.Lcstbegin
409 .Lcstbegin:
410         .long   .LcleanupSTART-.LSTARTCODE
411         .long   .Ladd_wakeup-.LcleanupSTART
412         .long   __condvar_tw_cleanup-.LSTARTCODE
413         .uleb128  0
414         .long   .LebxmovedUR-.LSTARTCODE
415         .long   .LebxbackUR-.LebxmovedUR
416         .long   __condvar_tw_cleanup3-.LSTARTCODE
417         .uleb128  0
418         .long   .LebxmovedUR-.LSTARTCODE
419         .long   .Ladd_wakeup-.LebxmovedUR
420         .long   __condvar_tw_cleanup-.LSTARTCODE
421         .uleb128  0
422         .long   .Ladd_wakeup-.LSTARTCODE
423         .long   .Lsub_wakeup-.Ladd_wakeup
424         .long   __condvar_tw_cleanup2-.LSTARTCODE
425         .uleb128  0
426         .long   .Lsub_wakeup-.LSTARTCODE
427         .long   .LcleanupEND-.Lsub_wakeup
428         .long   __condvar_tw_cleanup-.LSTARTCODE
429         .uleb128  0
430         .long   .LcallUR-.LSTARTCODE
431         .long   .LENDCODE-.LcallUR
432         .long   0
433         .uleb128  0
434 .Lcstend:
435
436
437         .section .eh_frame,"a",@progbits
438 .LSTARTFRAME:
439         .long   L(ENDCIE)-L(STARTCIE)           # Length of the CIE.
440 .LSTARTCIE:
441         .long   0                               # CIE ID.
442         .byte   1                               # Version number.
443 #ifdef SHARED
444         .string "zPLR"                          # NUL-terminated augmentation
445                                                 # string.
446 #else
447         .string "zPL"                           # NUL-terminated augmentation
448                                                 # string.
449 #endif
450         .uleb128 1                              # Code alignment factor.
451         .sleb128 -4                             # Data alignment factor.
452         .byte   8                               # Return address register
453                                                 # column.
454 #ifdef SHARED
455         .uleb128 7                              # Augmentation value length.
456         .byte   0x9b                            # Personality: DW_EH_PE_pcrel
457                                                 # + DW_EH_PE_sdata4
458                                                 # + DW_EH_PE_indirect
459         .long   DW.ref.__gcc_personality_v0-.
460         .byte   0x1b                            # LSDA Encoding: DW_EH_PE_pcrel
461                                                 # + DW_EH_PE_sdata4.
462         .byte   0x1b                            # FDE Encoding: DW_EH_PE_pcrel
463                                                 # + DW_EH_PE_sdata4.
464 #else
465         .uleb128 6                              # Augmentation value length.
466         .byte   0x0                             # Personality: absolute
467         .long   __gcc_personality_v0
468         .byte   0x0                             # LSDA Encoding: absolute
469 #endif
470         .byte 0x0c                              # DW_CFA_def_cfa
471         .uleb128 4
472         .uleb128 4
473         .byte   0x88                            # DW_CFA_offset, column 0x8
474         .uleb128 1
475         .align 4
476 .LENDCIE:
477
478         .long   .LENDFDE-.LSTARTFDE             # Length of the FDE.
479 .LSTARTFDE:
480         .long   .LSTARTFDE-.LSTARTFRAME         # CIE pointer.
481 #ifdef SHARED
482         .long   .LSTARTCODE-.                   # PC-relative start address
483                                                 # of the code
484 #else
485         .long   .LSTARTCODE                     # Start address of the code.
486 #endif
487         .long   .LENDCODE-.LSTARTCODE           # Length of the code.
488         .uleb128 4                              # Augmentation size
489 #ifdef SHARED
490         .long   .LexceptSTART-.
491 #else
492         .long   .LexceptSTART
493 #endif
494         .byte   0x40+.Lpush_ebp-.LSTARTCODE     # DW_CFA_advance_loc+N
495         .byte   14                              # DW_CFA_def_cfa_offset
496         .uleb128 8
497         .byte   0x85                            # DW_CFA_offset %ebp
498         .uleb128 2
499         .byte   0x40+ .Lpush_edi-.Lpush_ebp     # DW_CFA_advance_loc+N
500         .byte   14                              # DW_CFA_def_cfa_offset
501         .uleb128 12
502         .byte   0x87                            # DW_CFA_offset %edi
503         .uleb128 3
504         .byte   0x40+.Lpush_esi-.Lpush_edi      # DW_CFA_advance_loc+N
505         .byte   14                              # DW_CFA_def_cfa_offset
506         .uleb128 16
507         .byte   0x86                            # DW_CFA_offset %esi
508         .uleb128 4
509         .byte   0x40+.Lpush_ebx-.Lpush_esi      # DW_CFA_advance_loc+N
510         .byte   14                              # DW_CFA_def_cfa_offset
511         .uleb128 20
512         .byte   0x83                            # DW_CFA_offset %ebx
513         .uleb128 5
514         .byte   2                               # DW_CFA_advance_loc1
515         .byte   .Lsubl-.Lpush_ebx
516         .byte   14                              # DW_CFA_def_cfa_offset
517         .uleb128 40
518         .byte   3                               # DW_CFA_advance_loc2
519         .2byte  .Laddl-.Lsubl
520         .byte   14                              # DW_CFA_def_cfa_offset
521         .uleb128 20
522         .byte   0x40+.Lpop_ebx-.Laddl           # DW_CFA_advance_loc+N
523         .byte   14                              # DW_CFA_def_cfa_offset
524         .uleb128 16
525         .byte   0xc3                            # DW_CFA_restore %ebx
526         .byte   0x40+.Lpop_esi-.Lpop_ebx        # DW_CFA_advance_loc+N
527         .byte   14                              # DW_CFA_def_cfa_offset
528         .uleb128 12
529         .byte   0xc6                            # DW_CFA_restore %esi
530         .byte   0x40+.Lpop_edi-.Lpop_esi        # DW_CFA_advance_loc+N
531         .byte   14                              # DW_CFA_def_cfa_offset
532         .uleb128 8
533         .byte   0xc7                            # DW_CFA_restore %edi
534         .byte   0x40+.Lpop_ebp-.Lpop_edi        # DW_CFA_advance_loc+N
535         .byte   14                              # DW_CFA_def_cfa_offset
536         .uleb128 4
537         .byte   0xc5                            # DW_CFA_restore %ebp
538         .byte   0x40+.LSbl1-.Lpop_edi           # DW_CFA_advance_loc+N
539         .byte   14                              # DW_CFA_def_cfa_offset
540         .uleb128 20
541         .byte   0x40+.LSbl2-.LSbl1              # DW_CFA_advance_loc+N
542         .byte   14                              # DW_CFA_def_cfa_offset
543         .uleb128 64
544         .byte   0x85                            # DW_CFA_offset %ebp
545         .uleb128 2
546         .byte   0x87                            # DW_CFA_offset %edi
547         .uleb128 3
548         .byte   0x86                            # DW_CFA_offset %esi
549         .uleb128 4
550         .byte   0x83                            # DW_CFA_offset %ebx
551         .uleb128 5
552         .byte   0x40+.LSbl3-.LSbl2              # DW_CFA_advance_loc+N
553         .byte   14                              # DW_CFA_def_cfa_offset
554         .uleb128 24
555 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
556         .byte   0x40+.LSbl4-.LSbl3              # DW_CFA_advance_loc+N
557         .byte   14                              # DW_CFA_def_cfa_offset
558         .uleb128 64
559         .byte   4                               # DW_CFA_advance_loc4
560         .long   .LSbl5-.LSbl4
561 #else
562         .byte   4                               # DW_CFA_advance_loc4
563         .long   .LSbl5-.LSbl3
564 #endif
565         .byte   14                              # DW_CFA_def_cfa_offset
566         .uleb128 40
567         .align  4
568 .LENDFDE:
569
570 #ifdef SHARED
571         .hidden DW.ref.__gcc_personality_v0
572         .weak   DW.ref.__gcc_personality_v0
573         .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
574         .align 4
575         .type   DW.ref.__gcc_personality_v0, @object
576         .size   DW.ref.__gcc_personality_v0, 4
577 DW.ref.__gcc_personality_v0:
578         .long   __gcc_personality_v0
579 #endif