pthread_cond_timedwait implementation for Linux/i486.
[kopensolaris-gnu/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
24 #ifdef UP
25 # define LOCK
26 #else
27 # define LOCK lock
28 #endif
29
30 #define SYS_gettimeofday        __NR_gettimeofday
31 #define SYS_futex               240
32 #define FUTEX_WAIT              0
33 #define FUTEX_WAKE              1
34
35 #define ETIMEDOUT               110
36
37
38         .text
39
40 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
41                                const struct timespec *abstime)  */
42         .globl  __pthread_cond_timedwait
43         .type   __pthread_cond_timedwait, @function
44         .align  16
45 __pthread_cond_timedwait:
46
47         pushl   %ebp
48         pushl   %edi
49         pushl   %esi
50         pushl   %ebx
51
52         movl    20(%esp), %ebx
53         movl    28(%esp), %ebp
54 #if cond_lock != 0
55         addl    $cond_lock, %ebx
56 #endif
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         /* Unlock the mutex.  */
70 2:      pushl   24(%esp)
71         call    __pthread_mutex_unlock_internal
72
73         addl    $1, total_seq(%ebx)
74         adcl    $0, total_seq+4(%ebx)
75
76         /* Install cancellation handler.  */
77 #ifdef PIC
78         call    __i686.get_pc_thunk.cx
79         addl    $_GLOBAL_OFFSET_TABLE_, %ecx
80         leal    __condvar_cleanup@GOTOFF(%ecx), %eax
81 #else
82         leal    __condvar_cleanup, %eax
83 #endif
84         subl    $32, %esp
85         leal    16(%esp), %edx
86         movl    %ebx, 8(%esp)
87         movl    %eax, 4(%esp)
88         movl    %edx, (%esp)
89         call    __pthread_cleanup_push
90
91         /* Get and store current wakeup_seq value.  */
92         movl    wakeup_seq(%ebx), %edi
93         movl    wakeup_seq+4(%ebx), %edx
94         movl    %edi, 12(%esp)
95         movl    %edx, 16(%esp)
96
97         /* Unlock.  */
98 8:      LOCK
99 #if cond_lock == 0
100         decl    (%ebx)
101 #else
102         decl    cond_lock(%ebx)
103 #endif
104         jne     3f
105
106 4:      call    __pthread_enable_asynccancel
107         movl    %eax, (%esp)
108
109         /* Get the current time.  */
110         movl    %ebx, %edx
111         leal    4(%esp), %ebx
112         xorl    %ecx, %ecx
113         movl    $SYS_gettimeofday, %eax
114         ENTER_KERNEL
115         movl    %edx, %ebx
116
117         /* Compute relative timeout.  */
118         movl    8(%esp), %eax
119         movl    $1000, %edx
120         mul     %edx            /* Milli seconds to nano seconds.  */
121         movl    (%ebp), %ecx
122         movl    4(%ebp), %edx
123         subl    4(%esp), %ecx
124         subl    %eax, %edx
125         jns     12f
126         addl    $1000000000, %edx
127         decl    %ecx
128 12:     testl   %ecx, %ecx
129         js      13f
130
131         /* Store relative timeout.  */
132         movl    %ecx, 4(%esp)
133         movl    %edx, 8(%esp)
134         leal    4(%esp), %esi
135         xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
136         movl    %edi, %edx
137         addl    $wakeup_seq-cond_lock, %ebx
138         movl    $SYS_futex, %eax
139         ENTER_KERNEL
140         subl    $wakeup_seq-cond_lock, %ebx
141         movl    %eax, %esi
142
143         call    __pthread_disable_asynccancel
144
145         /* Lock.  */
146         movl    $1, %eax
147         LOCK
148 #if cond_lock == 0
149         xaddl   %eax, (%ebx)
150 #else
151         xaddl   %eax, cond_lock(%ebx)
152 #endif
153         testl   %eax, %eax
154         jne     5f
155
156 6:      movl    woken_seq(%ebx), %eax
157         movl    woken_seq+4(%ebx), %ecx
158
159         movl    wakeup_seq(%ebx), %edi
160         movl    wakeup_seq+4(%ebx), %edx
161
162         cmpl    16(%esp), %ecx
163         ja      7f
164         jb      15f
165         cmpl    12(%esp), %eax
166         jb      15f
167
168 7:      cmpl    %ecx, %edx
169         ja      9f
170         jb      15f
171         cmp     %eax, %edi
172         ja      9f
173
174 15:     cmpl    $-ETIMEDOUT, %esi
175         jne     8b
176
177 13:     addl    $1, wakeup_seq(%ebx)
178         adcl    $0, wakeup_seq+4(%ebx)
179         movl    $ETIMEDOUT, %esi
180         jmp     14f
181
182 9:      xorl    %esi, %esi
183 14:     addl    $1, woken_seq(%ebx)
184         adcl    $0, woken_seq+4(%ebx)
185
186         LOCK
187 #if cond_lock == 0
188         decl    (%ebx)
189 #else
190         decl    cond_lock(%ebx)
191 #endif
192         jne     10f
193
194         /* Remove cancellation handler.  */
195 11:     leal    20(%esp), %edx
196         movl    $0, 4(%esp)
197         movl    %edx, (%esp)
198         call    __pthread_cleanup_pop
199
200         movl    60(%esp), %ecx
201         movl    %ecx, (%esp)
202         call    __pthread_mutex_lock_internal
203         addl    $36, %esp
204
205         movl    %esi, %eax
206
207         popl    %ebx
208         popl    %esi
209         popl    %edi
210         popl    %ebp
211
212         /* We return the result of the mutex_lock operation.  */
213         ret
214
215         /* Initial locking failed.  */
216 1:
217 #if cond_lock == 0
218         movl    %ebx, %ecx
219 #else
220         leal    cond_lock(%ebx), %ecx
221 #endif
222         call    __lll_mutex_lock_wait
223         jmp     2b
224
225         /* Unlock in loop requires waekup.  */
226 3:
227 #if cond_lock == 0
228         movl    %ebx, %eax
229 #else
230         leal    cond_lock(%ebx), %eax
231 #endif
232         call    __lll_mutex_unlock_wake
233         jmp     4b
234
235         /* Locking in loop failed.  */
236 5:
237 #if cond_lock == 0
238         movl    %ebx, %ecx
239 #else
240         leal    cond_lock(%ebx), %ecx
241 #endif
242         call    __lll_mutex_lock_wait
243         jmp     6b
244
245         /* Unlock after loop requires waekup.  */
246 10:
247 #if cond_lock == 0
248         movl    %ebx, %eax
249 #else
250         leal    cond_lock(%ebx), %eax
251 #endif
252         call    __lll_mutex_unlock_wake
253         jmp     11b
254         .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
255 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
256                   GLIBC_2_3_2)