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