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