]> git.ipfire.org Git - thirdparty/glibc.git/blob - nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
Fix offset of cleanupbuf.__prev.
[thirdparty/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
46 pushl %ebp
47 pushl %edi
48 pushl %esi
49 pushl %ebx
50
51 movl 20(%esp), %ebx
52 movl 28(%esp), %ebp
53
54 /* Get internal lock. */
55 movl $1, %eax
56 LOCK
57 #if cond_lock == 0
58 xaddl %eax, (%ebx)
59 #else
60 xaddl %eax, cond_lock(%ebx)
61 #endif
62 testl %eax, %eax
63 jne 1f
64
65 /* Unlock the mutex. */
66 2: pushl 24(%esp)
67 call __pthread_mutex_unlock_internal
68
69 testl %eax, %eax
70 jne 16f
71
72 addl $1, total_seq(%ebx)
73 adcl $0, total_seq+4(%ebx)
74
75 /* Install cancellation handler. */
76 #ifdef PIC
77 call __i686.get_pc_thunk.cx
78 addl $_GLOBAL_OFFSET_TABLE_, %ecx
79 leal __condvar_cleanup@GOTOFF(%ecx), %eax
80 #else
81 leal __condvar_cleanup, %eax
82 #endif
83 subl $40, %esp
84 leal 28(%esp), %edx
85 movl %esp, 8(%esp)
86 movl %eax, 4(%esp)
87 movl %edx, (%esp)
88 call __pthread_cleanup_push
89
90 /* Address of the mutex. */
91 movl 68(%esp), %ecx
92 /* Get and store current wakeup_seq value. */
93 movl wakeup_seq(%ebx), %edi
94 movl wakeup_seq+4(%ebx), %edx
95 movl %edi, 20(%esp)
96 movl %edx, 24(%esp)
97 /* Prepare structure passed to cancellation handler. */
98 movl %ecx, (%esp)
99 movl %ebx, 4(%esp)
100
101 /* Unlock. */
102 8: LOCK
103 #if cond_lock == 0
104 subl $1, (%ebx)
105 #else
106 subl $1, cond_lock(%ebx)
107 #endif
108 jne 3f
109
110 4: leal 8(%esp), %eax
111 call __pthread_enable_asynccancel_2
112
113 /* Get the current time. */
114 movl %ebx, %edx
115 #ifdef __NR_clock_gettime
116 /* Get the clock number. Note that the field in the condvar
117 structure stores the number minus 1. */
118 movl cond_clock(%ebx), %ebx
119 /* Only clocks 0 and 1 are allowed. Both are handled in the
120 kernel. */
121 leal 12(%esp), %ecx
122 movl $__NR_clock_gettime, %eax
123 ENTER_KERNEL
124 # ifndef __ASSUME_POSIX_TIMERS
125 cmpl $-ENOSYS, %eax
126 je 19f
127 # endif
128 movl %edx, %ebx
129
130 /* Compute relative timeout. */
131 movl (%ebp), %ecx
132 movl 4(%ebp), %edx
133 subl 12(%esp), %ecx
134 subl 16(%esp), %edx
135 #else
136 /* Get the current time. */
137 leal 12(%esp), %ebx
138 xorl %ecx, %ecx
139 movl $SYS_gettimeofday, %eax
140 ENTER_KERNEL
141 movl %edx, %ebx
142
143 /* Compute relative timeout. */
144 movl 16(%esp), %eax
145 movl $1000, %edx
146 mul %edx /* Milli seconds to nano seconds. */
147 movl (%ebp), %ecx
148 movl 4(%ebp), %edx
149 subl 12(%esp), %ecx
150 subl %eax, %edx
151 #endif
152 jns 12f
153 addl $1000000000, %edx
154 subl $1, %ecx
155 12: testl %ecx, %ecx
156 js 13f
157
158 /* Store relative timeout. */
159 21: movl %ecx, 12(%esp)
160 movl %edx, 16(%esp)
161 leal 12(%esp), %esi
162 xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
163 movl %edi, %edx
164 addl $wakeup_seq, %ebx
165 movl $SYS_futex, %eax
166 ENTER_KERNEL
167 subl $wakeup_seq, %ebx
168 movl %eax, %esi
169
170 movl 8(%esp), %eax
171 call __pthread_disable_asynccancel
172
173 /* Lock. */
174 movl $1, %eax
175 LOCK
176 #if cond_lock == 0
177 xaddl %eax, (%ebx)
178 #else
179 xaddl %eax, cond_lock(%ebx)
180 #endif
181 testl %eax, %eax
182 jne 5f
183
184 6: movl woken_seq(%ebx), %eax
185 movl woken_seq+4(%ebx), %ecx
186
187 movl wakeup_seq(%ebx), %edi
188 movl wakeup_seq+4(%ebx), %edx
189
190 cmpl 24(%esp), %edx
191 ja 7f
192 jb 15f
193 cmpl 20(%esp), %edi
194 jbe 15f
195
196 7: cmpl %ecx, %edx
197 ja 9f
198 jb 15f
199 cmp %eax, %edi
200 ja 9f
201
202 15: cmpl $-ETIMEDOUT, %esi
203 jne 8b
204
205 13: addl $1, wakeup_seq(%ebx)
206 adcl $0, wakeup_seq+4(%ebx)
207 movl $ETIMEDOUT, %esi
208 jmp 14f
209
210 9: xorl %esi, %esi
211 14: addl $1, woken_seq(%ebx)
212 adcl $0, woken_seq+4(%ebx)
213
214 LOCK
215 #if cond_lock == 0
216 subl $1, (%ebx)
217 #else
218 subl $1, cond_lock(%ebx)
219 #endif
220 jne 10f
221
222 /* Remove cancellation handler. */
223 11: movl 28+CLEANUP_PREV(%esp), %edx
224 movl %edx, %gs:CLEANUP
225
226 /* Trick ahead: (%esp) contains the address of the mutex. */
227 call __pthread_mutex_lock_internal
228 addl $44, %esp
229
230 /* We return the result of the mutex_lock operation if it failed. */
231 testl %eax, %eax
232 cmovel %esi, %eax
233
234 18: popl %ebx
235 popl %esi
236 popl %edi
237 popl %ebp
238
239 ret
240
241 /* Initial locking failed. */
242 1:
243 #if cond_lock == 0
244 movl %ebx, %ecx
245 #else
246 leal cond_lock(%ebx), %ecx
247 #endif
248 call __lll_mutex_lock_wait
249 jmp 2b
250
251 /* Unlock in loop requires waekup. */
252 3:
253 #if cond_lock == 0
254 movl %ebx, %eax
255 #else
256 leal cond_lock(%ebx), %eax
257 #endif
258 call __lll_mutex_unlock_wake
259 jmp 4b
260
261 /* Locking in loop failed. */
262 5:
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 6b
270
271 /* Unlock after loop requires waekup. */
272 10:
273 #if cond_lock == 0
274 movl %ebx, %eax
275 #else
276 leal cond_lock(%ebx), %eax
277 #endif
278 call __lll_mutex_unlock_wake
279 jmp 11b
280
281 /* The initial unlocking of the mutex failed. */
282 16: movl %eax, (%esp)
283 LOCK
284 #if cond_lock == 0
285 subl $1, (%ebx)
286 #else
287 subl $1, cond_lock(%ebx)
288 #endif
289 jne 17f
290
291 #if cond_lock == 0
292 movl %ebx, %eax
293 #else
294 leal cond_lock(%ebx), %eax
295 #endif
296 call __lll_mutex_unlock_wake
297
298 17: popl %eax
299 jmp 18b
300
301 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
302 /* clock_gettime not available. */
303 19: leal 12(%esp), %ebx
304 xorl %ecx, %ecx
305 movl $SYS_gettimeofday, %eax
306 ENTER_KERNEL
307 movl %edx, %ebx
308
309 /* Compute relative timeout. */
310 movl 16(%esp), %eax
311 movl $1000, %edx
312 mul %edx /* Milli seconds to nano seconds. */
313 movl (%ebp), %ecx
314 movl 4(%ebp), %edx
315 subl 12(%esp), %ecx
316 subl %eax, %edx
317 jns 20f
318 addl $1000000000, %edx
319 subl $1, %ecx
320 20: testl %ecx, %ecx
321 js 13b
322 jmp 21b
323 #endif
324 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
325 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
326 GLIBC_2_3_2)