]> git.ipfire.org Git - thirdparty/glibc.git/blob - nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S
5afe53d48471b4f8479221b80ade9d4cbf02aff1
[thirdparty/glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / i486 / lowlevelcond.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
23 #ifdef UP
24 # define LOCK
25 #else
26 # define LOCK lock
27 #endif
28
29 #define SYS_gettimeofday __NR_gettimeofday
30 #define SYS_futex 240
31 #define FUTEX_WAIT 0
32 #define FUTEX_WAKE 1
33
34 #define ETIMEDOUT 110
35
36 #define cond_lock 0
37 #define total_seq 4
38 #define wakeup_seq 12
39 #define woken_seq 20
40
41
42 .text
43
44 .align 16
45 .type condvar_cleanup, @function
46 condvar_cleanup:
47 pushl %ebx
48 movl 8(%esp), %ebx
49 #if cond_lock != 0
50 addl $cond_lock, %ebx
51 #endif
52
53 /* Get internal lock. */
54 movl $1, %eax
55 LOCK
56 #if cond_lock == 0
57 xaddl %eax, (%ebx)
58 #else
59 xaddl %eax, cond_lock(%ebx)
60 #endif
61 testl %eax, %eax
62 je 1f
63
64 #if cond_lock == 0
65 movl %ebx, %ecx
66 #else
67 leal cond_lock(%ebx), %ecx
68 #endif
69 call __lll_mutex_lock_wait
70
71 1: addl $1, wakeup_seq(%ebx)
72 adcl $0, wakeup_seq+4(%ebx)
73
74 addl $1, woken_seq(%ebx)
75 adcl $0, woken_seq+4(%ebx)
76
77 LOCK
78 decl (%ebx)
79 je 2f
80 #if cond_lock == 0
81 movl %ebx, %eax
82 #else
83 leal cond_lock(%ebx), %eax
84 #endif
85 call __lll_mutex_unlock_wake
86
87 2: popl %ebx
88 ret
89 .size condvar_cleanup, .-condvar_cleanup
90
91
92 /* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
93 .globl __pthread_cond_wait
94 .type __pthread_cond_wait, @function
95 .align 16
96 __pthread_cond_wait:
97
98 pushl %edi
99 pushl %esi
100 pushl %ebx
101
102 xorl %esi, %esi
103 movl 16(%esp), %ebx
104 #if cond_lock != 0
105 addl $cond_lock, %ebx
106 #endif
107
108 /* Get internal lock. */
109 movl $1, %eax
110 LOCK
111 #if cond_lock == 0
112 xaddl %eax, (%ebx)
113 #else
114 xaddl %eax, cond_lock(%ebx)
115 #endif
116 testl %eax, %eax
117 jne 1f
118
119 /* Unlock the mutex. */
120 2: pushl 20(%esp)
121 call __pthread_mutex_unlock_internal
122
123 addl $1, total_seq(%ebx)
124 adcl $0, total_seq+4(%ebx)
125
126 /* Install cancellation handler. */
127 #ifdef PIC
128 call __i686.get_pc_thunk.cx
129 addl $_GLOBAL_OFFSET_TABLE_, %ecx
130 leal condvar_cleanup@GOTOFF(%ecx), %eax
131 #else
132 leal condvar_cleanup, %eax
133 #endif
134 subl $24, %esp
135 leal 12(%esp), %edx
136 movl %ebx, 8(%esp)
137 movl %eax, 4(%esp)
138 movl %edx, (%esp)
139 call _GI_pthread_cleanup_push
140
141 /* Get and store current wakeup_seq value. */
142 movl wakeup_seq(%ebx), %edi
143 movl wakeup_seq+4(%ebx), %edx
144 movl %edi, 4(%esp)
145 movl %edx, 8(%esp)
146
147 /* Unlock. */
148 8: LOCK
149 #if cond_lock == 0
150 decl (%ebx)
151 #else
152 decl cond_lock(%ebx)
153 #endif
154 jne 3f
155
156 4: call __pthread_enable_asynccancel
157 movl %eax, (%esp)
158
159 movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */
160 movl %edi, %edx
161 addl $wakeup_seq-cond_lock, %ebx
162 movl $SYS_futex, %eax
163 ENTER_KERNEL
164 subl $wakeup_seq-cond_lock, %ebx
165
166 call __pthread_disable_asynccancel
167
168 /* Lock. */
169 movl $1, %eax
170 LOCK
171 #if cond_lock == 0
172 xaddl %eax, (%ebx)
173 #else
174 xaddl %eax, cond_lock(%ebx)
175 #endif
176 testl %eax, %eax
177 jne 5f
178
179 6: movl woken_seq(%ebx), %eax
180 movl woken_seq+4(%ebx), %ecx
181
182 movl wakeup_seq(%ebx), %edi
183 movl wakeup_seq+4(%ebx), %edx
184
185 cmpl 8(%esp), %ecx
186 ja 7f
187 jb 8b
188 cmpl 4(%esp), %eax
189 jb 8b
190
191 7: cmpl %ecx, %edx
192 ja 9f
193 jb 8b
194 cmp %eax, %edi
195 jna 8b
196
197 9: addl $1, woken_seq(%ebx)
198 adcl $0, woken_seq+4(%ebx)
199
200 LOCK
201 #if cond_lock == 0
202 decl (%ebx)
203 #else
204 decl cond_lock(%ebx)
205 #endif
206 jne 10f
207
208 /* Remove cancellation handler. */
209 11: leal 12(%esp), %edx
210 movl $0, 4(%esp)
211 movl %edx, (%esp)
212 call _GI_pthread_cleanup_pop
213
214 movl 48(%esp), %eax
215 movl %eax, (%esp)
216 call __pthread_mutex_lock_internal
217 addl $28, %esp
218
219 popl %ebx
220 popl %esi
221 popl %edi
222
223 /* We return the result of the mutex_lock operation. */
224 ret
225
226 /* Initial locking failed. */
227 1:
228 #if cond_lock == 0
229 movl %ebx, %ecx
230 #else
231 leal cond_lock(%ebx), %ecx
232 #endif
233 call __lll_mutex_lock_wait
234 jmp 2b
235
236 /* Unlock in loop requires waekup. */
237 3:
238 #if cond_lock == 0
239 movl %ebx, %eax
240 #else
241 leal cond_lock(%ebx), %eax
242 #endif
243 call __lll_mutex_unlock_wake
244 jmp 4b
245
246 /* Locking in loop failed. */
247 5:
248 #if cond_lock == 0
249 movl %ebx, %ecx
250 #else
251 leal cond_lock(%ebx), %ecx
252 #endif
253 call __lll_mutex_lock_wait
254 jmp 6b
255
256 /* Unlock after loop requires waekup. */
257 10:
258 #if cond_lock == 0
259 movl %ebx, %eax
260 #else
261 leal cond_lock(%ebx), %eax
262 #endif
263 call __lll_mutex_unlock_wake
264 jmp 11b
265 .size __pthread_cond_wait, .-__pthread_cond_wait
266 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
267 GLIBC_2_3_2)
268
269
270 /* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
271 const struct timespec *abstime) */
272 .globl __pthread_cond_timedwait
273 .type __pthread_cond_timedwait, @function
274 .align 16
275 __pthread_cond_timedwait:
276
277 pushl %ebp
278 pushl %edi
279 pushl %esi
280 pushl %ebx
281
282 movl 20(%esp), %ebx
283 movl 28(%esp), %ebp
284 #if cond_lock != 0
285 addl $cond_lock, %ebx
286 #endif
287
288 /* Get internal lock. */
289 movl $1, %eax
290 LOCK
291 #if cond_lock == 0
292 xaddl %eax, (%ebx)
293 #else
294 xaddl %eax, cond_lock(%ebx)
295 #endif
296 testl %eax, %eax
297 jne 1f
298
299 /* Unlock the mutex. */
300 2: pushl 24(%esp)
301 call __pthread_mutex_unlock_internal
302
303 addl $1, total_seq(%ebx)
304 adcl $0, total_seq+4(%ebx)
305
306 /* Install cancellation handler. */
307 #ifdef PIC
308 call __i686.get_pc_thunk.cx
309 addl $_GLOBAL_OFFSET_TABLE_, %ecx
310 leal condvar_cleanup@GOTOFF(%ecx), %eax
311 #else
312 leal condvar_cleanup, %eax
313 #endif
314 subl $32, %esp
315 leal 16(%esp), %edx
316 movl %ebx, 8(%esp)
317 movl %eax, 4(%esp)
318 movl %edx, (%esp)
319 call _GI_pthread_cleanup_push
320
321 /* Get and store current wakeup_seq value. */
322 movl wakeup_seq(%ebx), %edi
323 movl wakeup_seq+4(%ebx), %edx
324 movl %edi, 12(%esp)
325 movl %edx, 16(%esp)
326
327 /* Unlock. */
328 8: LOCK
329 #if cond_lock == 0
330 decl (%ebx)
331 #else
332 decl cond_lock(%ebx)
333 #endif
334 jne 3f
335
336 4: call __pthread_enable_asynccancel
337 movl %eax, (%esp)
338
339 /* Get the current time. */
340 movl %ebx, %edx
341 leal 4(%esp), %ebx
342 xorl %ecx, %ecx
343 movl $SYS_gettimeofday, %eax
344 ENTER_KERNEL
345 movl %edx, %ebx
346
347 /* Compute relative timeout. */
348 movl 8(%esp), %eax
349 movl $1000, %edx
350 mul %edx /* Milli seconds to nano seconds. */
351 movl (%ebp), %ecx
352 movl 4(%ebp), %edx
353 subl 4(%esp), %ecx
354 subl %eax, %edx
355 jns 12f
356 addl $1000000000, %edx
357 decl %ecx
358 12: testl %ecx, %ecx
359 js 13f
360
361 /* Store relative timeout. */
362 movl %ecx, 4(%esp)
363 movl %edx, 8(%esp)
364 leal 4(%esp), %esi
365 xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
366 movl %edi, %edx
367 addl $wakeup_seq-cond_lock, %ebx
368 movl $SYS_futex, %eax
369 ENTER_KERNEL
370 subl $wakeup_seq-cond_lock, %ebx
371 movl %eax, %esi
372
373 call __pthread_disable_asynccancel
374
375 /* Lock. */
376 movl $1, %eax
377 LOCK
378 #if cond_lock == 0
379 xaddl %eax, (%ebx)
380 #else
381 xaddl %eax, cond_lock(%ebx)
382 #endif
383 testl %eax, %eax
384 jne 5f
385
386 6: movl woken_seq(%ebx), %eax
387 movl woken_seq+4(%ebx), %ecx
388
389 movl wakeup_seq(%ebx), %edi
390 movl wakeup_seq+4(%ebx), %edx
391
392 cmpl 16(%esp), %ecx
393 ja 7f
394 jb 15f
395 cmpl 12(%esp), %eax
396 jb 15f
397
398 7: cmpl %ecx, %edx
399 ja 9f
400 jb 15f
401 cmp %eax, %edi
402 ja 9f
403
404 15: cmpl $-ETIMEDOUT, %esi
405 jne 8b
406
407 13: addl $1, wakeup_seq(%ebx)
408 adcl $0, wakeup_seq+4(%ebx)
409 movl $ETIMEDOUT, %esi
410 jmp 14f
411
412 9: xorl %esi, %esi
413 14: addl $1, woken_seq(%ebx)
414 adcl $0, woken_seq+4(%ebx)
415
416 LOCK
417 #if cond_lock == 0
418 decl (%ebx)
419 #else
420 decl cond_lock(%ebx)
421 #endif
422 jne 10f
423
424 /* Remove cancellation handler. */
425 11: leal 20(%esp), %edx
426 movl $0, 4(%esp)
427 movl %edx, (%esp)
428 call _GI_pthread_cleanup_pop
429
430 movl 60(%esp), %ecx
431 movl %ecx, (%esp)
432 call __pthread_mutex_lock_internal
433 addl $36, %esp
434
435 movl %esi, %eax
436
437 popl %ebx
438 popl %esi
439 popl %edi
440 popl %ebp
441
442 /* We return the result of the mutex_lock operation. */
443 ret
444
445 /* Initial locking failed. */
446 1:
447 #if cond_lock == 0
448 movl %ebx, %ecx
449 #else
450 leal cond_lock(%ebx), %ecx
451 #endif
452 call __lll_mutex_lock_wait
453 jmp 2b
454
455 /* Unlock in loop requires waekup. */
456 3:
457 #if cond_lock == 0
458 movl %ebx, %eax
459 #else
460 leal cond_lock(%ebx), %eax
461 #endif
462 call __lll_mutex_unlock_wake
463 jmp 4b
464
465 /* Locking in loop failed. */
466 5:
467 #if cond_lock == 0
468 movl %ebx, %ecx
469 #else
470 leal cond_lock(%ebx), %ecx
471 #endif
472 call __lll_mutex_lock_wait
473 jmp 6b
474
475 /* Unlock after loop requires waekup. */
476 10:
477 #if cond_lock == 0
478 movl %ebx, %eax
479 #else
480 leal cond_lock(%ebx), %eax
481 #endif
482 call __lll_mutex_unlock_wake
483 jmp 11b
484 .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
485 versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
486 GLIBC_2_3_2)
487
488
489 /* int pthread_cond_signal (pthread_cond_t *cond) */
490 .globl __pthread_cond_signal
491 .type __pthread_cond_signal, @function
492 .align 16
493 __pthread_cond_signal:
494
495 pushl %esi
496 pushl %ebx
497 #if cond_lock != 0
498 addl $cond_lock, %ebx
499 #endif
500
501 movl 12(%esp), %ebx
502
503 /* Get internal lock. */
504 movl $1, %eax
505 LOCK
506 #if cond_lock == 0
507 xaddl %eax, (%ebx)
508 #else
509 xaddl %eax, cond_lock(%ebx)
510 #endif
511 testl %eax, %eax
512 jne 1f
513
514 2: movl total_seq+4(%ebx), %eax
515 movl total_seq(%ebx), %ecx
516 cmpl wakeup_seq+4(%ebx), %eax
517 ja 3f
518 jb 4f
519 cmpl wakeup_seq(%ebx), %ecx
520 jbe 4f
521
522 /* Bump the wakeup number. */
523 3: addl $1, wakeup_seq(%ebx)
524 adcl $0, wakeup_seq+4(%ebx)
525
526 /* Wake up one thread. */
527 addl $wakeup_seq-cond_lock, %ebx
528 movl $FUTEX_WAKE, %ecx
529 xorl %esi, %esi
530 movl $SYS_futex, %eax
531 movl %ecx, %edx /* movl $1, %edx */
532 ENTER_KERNEL
533
534 subl $wakeup_seq-cond_lock, %ebx
535
536 /* Unlock. */
537 4: LOCK
538 #if cond_lock == 0
539 decl (%ebx)
540 #else
541 decl cond_lock(%ebx)
542 #endif
543 jne 5f
544
545 6: xorl %eax, %eax
546 popl %ebx
547 popl %esi
548 ret
549
550 /* Initial locking failed. */
551 1:
552 #if cond_lock == 0
553 movl %ebx, %ecx
554 #else
555 leal cond_lock(%ebx), %ecx
556 #endif
557 call __lll_mutex_lock_wait
558 jmp 2b
559
560 /* Unlock in loop requires waekup. */
561 5:
562 #if cond_lock == 0
563 movl %ebx, %eax
564 #else
565 leal cond_lock(%ebx), %eax
566 #endif
567 call __lll_mutex_unlock_wake
568 jmp 6b
569 .size __pthread_cond_signal, .-__pthread_cond_signal
570 versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal,
571 GLIBC_2_3_2)
572
573
574 /* int pthread_cond_broadcast (pthread_cond_t *cond) */
575 .globl __pthread_cond_broadcast
576 .type __pthread_cond_broadcast, @function
577 .align 16
578 __pthread_cond_broadcast:
579
580 pushl %esi
581 pushl %ebx
582
583 movl 12(%esp), %ebx
584 #if cond_lock != 0
585 addl $cond_lock, %ebx
586 #endif
587
588 /* Get internal lock. */
589 movl $1, %eax
590 LOCK
591 #if cond_lock == 0
592 xaddl %eax, (%ebx)
593 #else
594 xaddl %eax, cond_lock(%ebx)
595 #endif
596 testl %eax, %eax
597 jne 1f
598
599 2: movl total_seq+4(%ebx), %eax
600 movl total_seq(%ebx), %ecx
601 cmpl wakeup_seq+4(%ebx), %eax
602 ja 3f
603 jb 4f
604 cmpl wakeup_seq(%ebx), %ecx
605 jna 4f
606
607 /* Case all currently waiting threads to wake up. */
608 3: movl %ecx, wakeup_seq(%ebx)
609 movl %eax, wakeup_seq+4(%ebx)
610
611 /* Wake up all threads. */
612 addl $wakeup_seq-cond_lock, %ebx
613 movl $FUTEX_WAKE, %ecx
614 xorl %esi, %esi
615 movl $SYS_futex, %eax
616 movl $0x7fffffff, %edx
617 ENTER_KERNEL
618
619 subl $wakeup_seq-cond_lock, %ebx
620
621 /* Unlock. */
622 4: LOCK
623 #if cond_lock == 0
624 decl (%ebx)
625 #else
626 decl cond_lock(%ebx)
627 #endif
628 jne 5f
629
630 6: xorl %eax, %eax
631 popl %ebx
632 popl %esi
633 ret
634
635 /* Initial locking failed. */
636 1:
637 #if cond_lock == 0
638 movl %ebx, %ecx
639 #else
640 leal cond_lock(%ebx), %ecx
641 #endif
642 call __lll_mutex_lock_wait
643 jmp 2b
644
645 /* Unlock in loop requires waekup. */
646 5:
647 #if cond_lock == 0
648 movl %ebx, %eax
649 #else
650 leal cond_lock(%ebx), %eax
651 #endif
652 call __lll_mutex_unlock_wake
653 jmp 6b
654 .size __pthread_cond_broadcast, .-__pthread_cond_broadcast
655 versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
656 GLIBC_2_3_2)
657
658
659 #ifdef PIC
660 .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
661 .globl __i686.get_pc_thunk.cx
662 .hidden __i686.get_pc_thunk.cx
663 .type __i686.get_pc_thunk.cx,@function
664 __i686.get_pc_thunk.cx:
665 movl (%esp), %ecx;
666 ret
667 .size __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
668 #endif