(pthread_barrier_wait): Don't save, load, and restore %esi for last thread.
[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
55         /* Get internal lock.  */
56         movl    $1, %eax
57         LOCK
58 #if cond_lock == 0
59         xaddl   %eax, (%ebx)
60 #else
61         xaddl   %eax, cond_lock(%ebx)
62 #endif
63         testl   %eax, %eax
64         jne     1f
65
66         /* Unlock the mutex.  */
67 2:      pushl   24(%esp)
68         call    __pthread_mutex_unlock_internal
69
70         testl   %eax, %eax
71         jne     16f
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    $40, %esp
85         leal    28(%esp), %edx
86         movl    %esp, 8(%esp)
87         movl    %eax, 4(%esp)
88         movl    %edx, (%esp)
89         call    __pthread_cleanup_push
90
91         /* Address of the mutex.  */
92         movl    68(%esp), %ecx
93         /* Get and store current wakeup_seq value.  */
94         movl    wakeup_seq(%ebx), %edi
95         movl    wakeup_seq+4(%ebx), %edx
96         movl    %edi, 20(%esp)
97         movl    %edx, 24(%esp)
98         /* Prepare structure passed to cancellation handler.  */
99         movl    %ebx, 4(%esp)
100         movl    %ecx, 8(%esp)
101
102         /* Unlock.  */
103 8:      LOCK
104 #if cond_lock == 0
105         decl    (%ebx)
106 #else
107         decl    cond_lock(%ebx)
108 #endif
109         jne     3f
110
111 4:      call    __pthread_enable_asynccancel
112         movl    %eax, (%esp)
113
114         /* Get the current time.  */
115         movl    %ebx, %edx
116         leal    12(%esp), %ebx
117         xorl    %ecx, %ecx
118         movl    $SYS_gettimeofday, %eax
119         ENTER_KERNEL
120         movl    %edx, %ebx
121
122         /* Compute relative timeout.  */
123         movl    16(%esp), %eax
124         movl    $1000, %edx
125         mul     %edx            /* Milli seconds to nano seconds.  */
126         movl    (%ebp), %ecx
127         movl    4(%ebp), %edx
128         subl    12(%esp), %ecx
129         subl    %eax, %edx
130         jns     12f
131         addl    $1000000000, %edx
132         decl    %ecx
133 12:     testl   %ecx, %ecx
134         js      13f
135
136         /* Store relative timeout.  */
137         movl    %ecx, 12(%esp)
138         movl    %edx, 16(%esp)
139         leal    12(%esp), %esi
140         xorl    %ecx, %ecx      /* movl $FUTEX_WAIT, %ecx */
141         movl    %edi, %edx
142         addl    $wakeup_seq, %ebx
143         movl    $SYS_futex, %eax
144         ENTER_KERNEL
145         subl    $wakeup_seq, %ebx
146         movl    %eax, %esi
147
148         call    __pthread_disable_asynccancel
149
150         /* Lock.  */
151         movl    $1, %eax
152         LOCK
153 #if cond_lock == 0
154         xaddl   %eax, (%ebx)
155 #else
156         xaddl   %eax, cond_lock(%ebx)
157 #endif
158         testl   %eax, %eax
159         jne     5f
160
161 6:      movl    woken_seq(%ebx), %eax
162         movl    woken_seq+4(%ebx), %ecx
163
164         movl    wakeup_seq(%ebx), %edi
165         movl    wakeup_seq+4(%ebx), %edx
166
167         cmpl    24(%esp), %ecx
168         ja      7f
169         jb      15f
170         cmpl    20(%esp), %eax
171         jb      15f
172
173 7:      cmpl    %ecx, %edx
174         ja      9f
175         jb      15f
176         cmp     %eax, %edi
177         ja      9f
178
179 15:     cmpl    $-ETIMEDOUT, %esi
180         jne     8b
181
182 13:     addl    $1, wakeup_seq(%ebx)
183         adcl    $0, wakeup_seq+4(%ebx)
184         movl    $ETIMEDOUT, %esi
185         jmp     14f
186
187 9:      xorl    %esi, %esi
188 14:     addl    $1, woken_seq(%ebx)
189         adcl    $0, woken_seq+4(%ebx)
190
191         LOCK
192 #if cond_lock == 0
193         decl    (%ebx)
194 #else
195         decl    cond_lock(%ebx)
196 #endif
197         jne     10f
198
199         /* Remove cancellation handler.  */
200 11:     leal    28(%esp), %edx
201         movl    $0, 4(%esp)
202         movl    %edx, (%esp)
203         call    __pthread_cleanup_pop
204
205         /* Trick ahead:  8(%esp) contains the address of the mutex.  */
206         addl    $8, %esp
207         call    __pthread_mutex_lock_internal
208         addl    $36, %esp
209
210         movl    %esi, %eax
211
212 18:     popl    %ebx
213         popl    %esi
214         popl    %edi
215         popl    %ebp
216
217         /* We return the result of the mutex_lock operation.  */
218         ret
219
220         /* Initial locking failed.  */
221 1:
222 #if cond_lock == 0
223         movl    %ebx, %ecx
224 #else
225         leal    cond_lock(%ebx), %ecx
226 #endif
227         call    __lll_mutex_lock_wait
228         jmp     2b
229
230         /* Unlock in loop requires waekup.  */
231 3:
232 #if cond_lock == 0
233         movl    %ebx, %eax
234 #else
235         leal    cond_lock(%ebx), %eax
236 #endif
237         call    __lll_mutex_unlock_wake
238         jmp     4b
239
240         /* Locking in loop failed.  */
241 5:
242 #if cond_lock == 0
243         movl    %ebx, %ecx
244 #else
245         leal    cond_lock(%ebx), %ecx
246 #endif
247         call    __lll_mutex_lock_wait
248         jmp     6b
249
250         /* Unlock after loop requires waekup.  */
251 10:
252 #if cond_lock == 0
253         movl    %ebx, %eax
254 #else
255         leal    cond_lock(%ebx), %eax
256 #endif
257         call    __lll_mutex_unlock_wake
258         jmp     11b
259
260         /* The initial unlocking of the mutex failed.  */
261 16:     movl    %eax, (%esp)
262         LOCK
263 #if cond_lock == 0
264         decl    (%ebx)
265 #else
266         decl    cond_lock(%ebx)
267 #endif
268         jne     17f
269
270 #if cond_lock == 0
271         movl    %ebx, %eax
272 #else
273         leal    cond_lock(%ebx), %eax
274 #endif
275         call    __lll_mutex_unlock_wake
276
277 17:     popl    %eax
278         jmp     18b
279         .size   __pthread_cond_wait, .-__pthread_cond_wait
280         .size   __pthread_cond_timedwait, .-__pthread_cond_timedwait
281 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
282                   GLIBC_2_3_2)