diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-12-12 18:13:35 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2007-12-12 18:13:35 +0000 |
commit | 574e283890a6ca92325a06dafa76ff307a8019a2 (patch) | |
tree | 055e44e24a55fb4863e5d9cdc04e320cde52ffe9 /nptl | |
parent | a162e5955f7e324be82d9318bbcbe869c66ffb86 (diff) |
Updated to fedora-glibc-20071212T1051
Diffstat (limited to 'nptl')
20 files changed, 357 insertions, 152 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 62e6ae3120..9e0e839f19 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,96 @@ +2007-12-12 Ulrich Drepper <drepper@redhat.com> + + [BZ #5465] + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S [!SHARED] + (__pthread_cond_timedwait): Don't use VDSO. + Patch by Michal Januszewski. + +2007-12-07 Ulrich Drepper <drepper@redhat.com> + + [BZ #5455] + * sysdeps/pthread/pthread.h [!__EXCEPTIONS] (pthread_cleanup_pop): + Allow label before pthread_cleanup_pop. + (pthread_cleanup_pop_restore_np): Likewise. + +2007-12-04 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S (__lll_timedlock_wait): + Store 2 before returning ETIMEDOUT. + +2007-11-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S (__lll_timedlock_wait): + Store 2 before returning ETIMEDOUT. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise + * sysdeps/unix/sysv/linux/lowlevellock.c: Likewise. + (__lll_lock_wait_private): Optimize. + (__lll_lock_wait): Likewise. + +2007-11-20 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_cleanup_push, + pthread_cleanup_push_defer_np): Add extra (void *) cast to shut up + g++ 4.1 and 4.2 -Wstrict-aliasing warnings. + +2007-11-08 Ulrich Drepper <drepper@redhat.com> + + [BZ #5240] + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait): + If we time out, try one last time to lock the futex to avoid + losing a wakeup signal. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise. + + [BZ #5245] + * sysdeps/pthread/createthread.c (do_clone): Translate clone error + if necessary. + +2007-11-07 Ulrich Drepper <drepper@redhat.com> + + [BZ #5245] + * allocatestack.c (allocate_stack): Change ENOMEM error in case + mmap failed to EAGAIN. + * Makefile (tests): Add tst-basic7. + * tst-basic7.c: New file. + +2007-11-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/register-atfork.c (__register_atfork): + Use __linkin_atfork. + +2007-11-03 Mike Frysinger <vapier@gentoo.org> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S (LOAD_FUTEX_WAIT): Add + missing line continuations. + * sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S (LOAD_FUTEX_WAIT, + LOAD_FUTEX_WAKE): Likewise. Also add missing 3rd parameter. + +2007-10-28 Ulrich Drepper <drepper@redhat.com> + + [BZ #5220] + * sysdeps/unix/sysv/linux/kernel-posix-timers.h: Declare + __active_timer_sigev_thread and __active_timer_sigev_thread_lock. + (struct timer): Add next element. + * sysdeps/unix/sysv/linux/timer_create.c: For SIGEV_THREAD timers, + enqueue timer structure into __active_timer_sigev_thread list. + * sysdeps/unix/sysv/linux/timer_delete.c: For SIGEV_THREAD timers, + remove timer struct from __active_timer_sigev_thread. + * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread): + Before using timer structure make sure it is still on the + __active_timer_sigev_thread list. Keep lock until done. + Define __active_timer_sigev_thread and + __active_timer_sigev_thread_lock. + +2007-10-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/malloc-machine.h: Define ATFORK_MEM. + Redefine thread_atfork for use of ATFORK_MEM. + * sysdeps/unix/sysv/linux/fork.h: Define __linkin_atfork. + * sysdeps/unix/sysv/linux/register-atfork.c (__linkin_atfork): New + function. + * sysdeps/unix/sysv/linux/unregister-atfork.c (__unregister_atfork): + Use atomic operation when removing first element of list. + 2007-10-17 Jakub Jelinek <jakub@redhat.com> * sysdeps/unix/sysv/linux/i386/i486/sem_post.S (__old_sem_post): New diff --git a/nptl/Makefile b/nptl/Makefile index 5ed2c21145..407ccecaa9 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -222,6 +222,7 @@ tests = tst-typesizes \ tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \ tst-align tst-align2 tst-align3 \ tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \ + tst-basic7 \ tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \ tst-raise1 \ tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 \ diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index c894e96a28..f75599c668 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -462,7 +462,12 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, mem = ARCH_RETRY_MMAP (size); if (__builtin_expect (mem == MAP_FAILED, 0)) #endif - return errno; + { + if (errno == ENOMEM) + errno = EAGAIN; + + return errno; + } } /* SIZE is guaranteed to be greater than zero. diff --git a/nptl/sysdeps/pthread/createthread.c b/nptl/sysdeps/pthread/createthread.c index 66571b2175..59e62c2dcf 100644 --- a/nptl/sysdeps/pthread/createthread.c +++ b/nptl/sysdeps/pthread/createthread.c @@ -56,8 +56,8 @@ do_clone (struct pthread *pd, const struct pthread_attr *attr, PREPARE_CREATE; #endif - if (stopped) - /* We Make sure the thread does not run far by forcing it to get a + if (__builtin_expect (stopped != 0, 0)) + /* We make sure the thread does not run far by forcing it to get a lock. We lock it here too so that the new thread cannot continue until we tell it to. */ lll_lock (pd->lock, LLL_PRIVATE); @@ -84,7 +84,8 @@ do_clone (struct pthread *pd, const struct pthread_attr *attr, if (IS_DETACHED (pd)) __deallocate_stack (pd); - return errno; + /* We have to translate error codes. */ + return errno == ENOMEM ? EAGAIN : errno; } /* Now we have the possibility to set scheduling parameters etc. */ diff --git a/nptl/sysdeps/pthread/malloc-machine.h b/nptl/sysdeps/pthread/malloc-machine.h index efab230aa8..33a3d20531 100644 --- a/nptl/sysdeps/pthread/malloc-machine.h +++ b/nptl/sysdeps/pthread/malloc-machine.h @@ -1,6 +1,6 @@ /* Basic platform-independent macro definitions for mutexes, thread-specific data and parameters for malloc. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -38,13 +38,24 @@ extern void *__dso_handle __attribute__ ((__weak__)); #include <fork.h> +#define ATFORK_MEM static struct fork_handler atfork_mem + #ifdef SHARED # define thread_atfork(prepare, parent, child) \ - __register_atfork (prepare, parent, child, __dso_handle) + atfork_mem.prepare_handler = prepare; \ + atfork_mem.parent_handler = parent; \ + atfork_mem.child_handler = child; \ + atfork_mem.dso_handle = __dso_handle; \ + atfork_mem.refcntr = 1; \ + __linkin_atfork (&atfork_mem) #else # define thread_atfork(prepare, parent, child) \ - __register_atfork (prepare, parent, child, \ - &__dso_handle == NULL ? NULL : __dso_handle) + atfork_mem.prepare_handler = prepare; \ + atfork_mem.parent_handler = parent; \ + atfork_mem.child_handler = child; \ + atfork_mem.dso_handle = &__dso_handle == NULL ? NULL : __dso_handle; \ + atfork_mem.refcntr = 1; \ + __linkin_atfork (&atfork_mem) #endif /* thread specific data for glibc */ diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h index d175f312ee..f3ab0ae711 100644 --- a/nptl/sysdeps/pthread/pthread.h +++ b/nptl/sysdeps/pthread/pthread.h @@ -638,7 +638,7 @@ __pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame) __pthread_unwind_buf_t __cancel_buf; \ void (*__cancel_routine) (void *) = (routine); \ void *__cancel_arg = (arg); \ - int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) \ + int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) \ __cancel_buf.__cancel_jmp_buf, 0); \ if (__builtin_expect (not_first_call, 0)) \ { \ @@ -655,6 +655,7 @@ extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) /* Remove a cleanup handler installed by the matching pthread_cleanup_push. If EXECUTE is non-zero, the handler function is called. */ # define pthread_cleanup_pop(execute) \ + do; while (0); /* Empty to allow label before pthread_cleanup_pop. */ \ } while (0); \ __pthread_unregister_cancel (&__cancel_buf); \ if (execute) \ @@ -672,7 +673,7 @@ extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf) __pthread_unwind_buf_t __cancel_buf; \ void (*__cancel_routine) (void *) = (routine); \ void *__cancel_arg = (arg); \ - int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) \ + int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) \ __cancel_buf.__cancel_jmp_buf, 0); \ if (__builtin_expect (not_first_call, 0)) \ { \ @@ -690,6 +691,7 @@ extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf) restores the cancellation type that was in effect when the matching pthread_cleanup_push_defer was called. */ # define pthread_cleanup_pop_restore_np(execute) \ + do; while (0); /* Empty to allow label before pthread_cleanup_pop. */ \ } while (0); \ __pthread_unregister_cancel_restore (&__cancel_buf); \ if (execute) \ diff --git a/nptl/sysdeps/unix/sysv/linux/fork.h b/nptl/sysdeps/unix/sysv/linux/fork.h index 032b68f083..a00cfabe26 100644 --- a/nptl/sysdeps/unix/sysv/linux/fork.h +++ b/nptl/sysdeps/unix/sysv/linux/fork.h @@ -55,3 +55,6 @@ extern int __register_atfork (void (*__prepare) (void), void (*__child) (void), void *dso_handle); libc_hidden_proto (__register_atfork) + +/* Add a new element to the fork list. */ +extern void __linkin_atfork (struct fork_handler *newp) attribute_hidden; diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S index 745ab91239..9c8a68f5b2 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S @@ -184,6 +184,12 @@ __lll_timedlock_wait: movl %ecx, %ebp movl %edx, %edi + movl $2, %edx + xchgl %edx, (%ebp) + + test %edx, %edx + je 6f + 1: /* Get current time. */ movl %esp, %ebx @@ -203,36 +209,30 @@ __lll_timedlock_wait: addl $1000000000, %edx subl $1, %ecx 4: testl %ecx, %ecx - js 5f /* Time is already up. */ + js 2f /* Time is already up. */ /* Store relative timeout. */ movl %ecx, (%esp) movl %edx, 4(%esp) + /* Futex call. */ movl %ebp, %ebx - - movl $1, %eax movl $2, %edx - LOCK - cmpxchgl %edx, (%ebx) - - testl %eax, %eax - je 8f - - /* Futex call. */ movl %esp, %esi movl 16(%esp), %ecx LOAD_FUTEX_WAIT (%ecx) movl $SYS_futex, %eax ENTER_KERNEL - movl %eax, %ecx -8: /* NB: %edx == 2 */ - xorl %eax, %eax - LOCK - cmpxchgl %edx, (%ebx) + /* NB: %edx == 2 */ + xchgl %edx, (%ebp) + + testl %edx, %edx + je 6f - jnz 7f + cmpl $-ETIMEDOUT, %eax + jne 1b +2: movl $ETIMEDOUT, %edx 6: addl $8, %esp cfi_adjust_cfa_offset(-8) @@ -248,29 +248,11 @@ __lll_timedlock_wait: popl %edi cfi_adjust_cfa_offset(-4) cfi_restore(%edi) + movl %edx, %eax ret 3: movl $EINVAL, %eax ret - - cfi_adjust_cfa_offset(24) - cfi_offset(%edi, -8) - cfi_offset(%esi, -12) - cfi_offset(%ebx, -16) - cfi_offset(%ebp, -20) - /* Check whether the time expired. */ -7: cmpl $-ETIMEDOUT, %ecx - je 5f - - /* Make sure the current holder knows we are going to sleep. */ - movl %edx, %eax - xchgl %eax, (%ebx) - testl %eax, %eax - jz 6b - jmp 1b - -5: movl $ETIMEDOUT, %eax - jmp 6b cfi_endproc .size __lll_timedlock_wait,.-__lll_timedlock_wait #endif diff --git a/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h b/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h index 3ff4cda3f4..5f419c2144 100644 --- a/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h +++ b/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2003 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -35,6 +35,11 @@ extern pthread_once_t __helper_once attribute_hidden; /* TID of the helper thread. */ extern pid_t __helper_tid attribute_hidden; +/* List of active SIGEV_THREAD timers. */ +extern struct timer *__active_timer_sigev_thread attribute_hidden; +/* Lock for the __active_timer_sigev_thread. */ +extern pthread_mutex_t __active_timer_sigev_thread_lock attribute_hidden; + /* Type of timers in the kernel. */ typedef int kernel_timer_t; @@ -57,4 +62,7 @@ struct timer void (*thrfunc) (sigval_t); sigval_t sival; pthread_attr_t attr; + + /* Next element in list of active SIGEV_THREAD timers. */ + struct timer *next; }; diff --git a/nptl/sysdeps/unix/sysv/linux/lowlevellock.c b/nptl/sysdeps/unix/sysv/linux/lowlevellock.c index f0e42957c2..01c4f4861a 100644 --- a/nptl/sysdeps/unix/sysv/linux/lowlevellock.c +++ b/nptl/sysdeps/unix/sysv/linux/lowlevellock.c @@ -27,13 +27,11 @@ void __lll_lock_wait_private (int *futex) { - do - { - int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); - if (oldval != 0) - lll_futex_wait (futex, 2, LLL_PRIVATE); - } - while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); + if (*futex == 2) + lll_futex_wait (futex, 2, LLL_PRIVATE); + + while (atomic_exchange_acq (futex, 2) != 0) + lll_futex_wait (futex, 2, LLL_PRIVATE); } @@ -42,13 +40,11 @@ __lll_lock_wait_private (int *futex) void __lll_lock_wait (int *futex, int private) { - do - { - int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); - if (oldval != 0) - lll_futex_wait (futex, 2, private); - } - while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); + if (*futex == 2) + lll_futex_wait (futex, 2, private); + + while (atomic_exchange_acq (futex, 2) != 0) + lll_futex_wait (futex, 2, private); } @@ -59,15 +55,16 @@ __lll_timedlock_wait (int *futex, const struct timespec *abstime, int private) if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) return EINVAL; - do + /* Try locking. */ + while (atomic_exchange_acq (futex, 2) != 0) { struct timeval tv; - struct timespec rt; /* Get the current time. */ (void) __gettimeofday (&tv, NULL); /* Compute relative timeout. */ + struct timespec rt; rt.tv_sec = abstime->tv_sec - tv.tv_sec; rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; if (rt.tv_nsec < 0) @@ -76,16 +73,12 @@ __lll_timedlock_wait (int *futex, const struct timespec *abstime, int private) --rt.tv_sec; } - /* Already timed out? */ if (rt.tv_sec < 0) return ETIMEDOUT; /* Wait. */ - int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); - if (oldval != 0) - lll_futex_timed_wait (futex, 2, &rt, private); + lll_futex_timed_wait (futex, 2, &rt, private); } - while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); return 0; } diff --git a/nptl/sysdeps/unix/sysv/linux/register-atfork.c b/nptl/sysdeps/unix/sysv/linux/register-atfork.c index 231fc9b091..bd103295fb 100644 --- a/nptl/sysdeps/unix/sysv/linux/register-atfork.c +++ b/nptl/sysdeps/unix/sysv/linux/register-atfork.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include <string.h> #include <fork.h> +#include <atomic.h> /* Lock to protect allocation and deallocation of fork handlers. */ @@ -97,8 +98,7 @@ __register_atfork (prepare, parent, child, dso_handle) newp->child_handler = child; newp->dso_handle = dso_handle; - newp->next = __fork_handlers; - __fork_handlers = newp; + __linkin_atfork (newp); } /* Release the lock. */ @@ -109,6 +109,17 @@ __register_atfork (prepare, parent, child, dso_handle) libc_hidden_def (__register_atfork) +void +attribute_hidden +__linkin_atfork (struct fork_handler *newp) +{ + do + newp->next = __fork_handlers; + while (catomic_compare_and_exchange_bool_acq (&__fork_handlers, + newp, newp->next) != 0); +} + + libc_freeres_fn (free_mem) { /* Get the lock to not conflict with running forks. */ diff --git a/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S index e929e28499..afcf0be299 100644 --- a/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S +++ b/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S @@ -76,7 +76,7 @@ add tmp2, tmp ; \ mov.l @tmp, tmp2 ; \ bra 98f ; \ - mov #FUTEX_PRIVATE_FLAG, tmp + mov #FUTEX_PRIVATE_FLAG, tmp ; \ 99: .word PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ 98: extu.b tmp, tmp ; \ xor tmp, reg ; \ @@ -88,7 +88,7 @@ add tmp2, tmp ; \ mov.l @tmp, tmp2 ; \ bra 98f ; \ - mov #FUTEX_PRIVATE_FLAG, tmp + mov #FUTEX_PRIVATE_FLAG, tmp ; \ 99: .word PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ 98: extu.b tmp, tmp ; \ xor tmp, reg ; \ @@ -96,13 +96,13 @@ mov #FUTEX_WAIT, tmp ; \ or tmp, reg # endif -# define LOAD_FUTEX_WAKE(reg,tmp) \ +# define LOAD_FUTEX_WAKE(reg,tmp,tmp2) \ stc gbr, tmp ; \ mov.w 99f, tmp2 ; \ add tmp2, tmp ; \ mov.l @tmp, tmp2 ; \ bra 98f ; \ - mov #FUTEX_PRIVATE_FLAG, tmp + mov #FUTEX_PRIVATE_FLAG, tmp ; \ 99: .word PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ 98: extu.b tmp, tmp ; \ xor tmp, reg ; \ @@ -225,6 +225,12 @@ __lll_timedlock_wait: add #-8, r15 cfi_adjust_cfa_offset(8) + mov #2, r2 + XCHG (r2, @r8, r3) + + tst r3, r3 + bt 6f + 1: /* Get current time. */ mov r15, r4 @@ -250,17 +256,11 @@ __lll_timedlock_wait: add #-1, r2 4: cmp/pz r2 - bf 5f /* Time is already up. */ + bf 2f /* Time is already up. */ mov.l r2, @r15 /* Store relative timeout. */ mov.l r3, @(4,r15) - mov #1, r3 - mov #2, r4 - CMPXCHG (r3, @r8, r4, r2) - tst r2, r2 - bt 8f - mov r8, r4 mov r11, r5 LOAD_FUTEX_WAIT (r5, r0, r1) @@ -272,39 +272,29 @@ __lll_timedlock_wait: SYSCALL_INST_PAD mov r0, r5 -8: - mov #0, r3 - mov #2, r4 - CMPXCHG (r3, @r8, r4, r2) - bf/s 7f - mov #0, r0 + mov #2, r2 + XCHG (r2, @r8, r3) + + tst r3, r3 + bt/s 6f + mov #-ETIMEDOUT, r1 + cmp/eq r5, r1 + bf 1b + +2: mov #ETIMEDOUT, r3 6: + mov r3, r0 add #8, r15 mov.l @r15+, r8 mov.l @r15+, r9 mov.l @r15+, r10 rts mov.l @r15+, r11 -7: - /* Check whether the time expired. */ - mov #-ETIMEDOUT, r1 - cmp/eq r5, r1 - bt 5f - /* Make sure the current holder knows we are going to sleep. */ - XCHG (r2, @r8, r3) - tst r3, r3 - bt/s 6b - mov #0, r0 - bra 1b - nop 3: rts mov #EINVAL, r0 -5: - bra 6b - mov #ETIMEDOUT, r0 cfi_endproc .L1k: diff --git a/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S b/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S index 0ebfbfe8c9..13093422a3 100644 --- a/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S +++ b/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S @@ -42,7 +42,7 @@ add tmp2, tmp ; \ mov.l @tmp, tmp2 ; \ bra 98f ; \ - mov #FUTEX_PRIVATE_FLAG, tmp + mov #FUTEX_PRIVATE_FLAG, tmp ; \ 99: .word PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ 98: extu.b tmp, tmp ; \ xor tmp, reg ; \ @@ -54,7 +54,7 @@ add tmp2, tmp ; \ mov.l @tmp, tmp2 ; \ bra 98f ; \ - mov #FUTEX_PRIVATE_FLAG, tmp + mov #FUTEX_PRIVATE_FLAG, tmp ; \ 99: .word PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ 98: extu.b tmp, tmp ; \ xor tmp, reg ; \ diff --git a/nptl/sysdeps/unix/sysv/linux/timer_create.c b/nptl/sysdeps/unix/sysv/linux/timer_create.c index 497068b554..a07234d7d1 100644 --- a/nptl/sysdeps/unix/sysv/linux/timer_create.c +++ b/nptl/sysdeps/unix/sysv/linux/timer_create.c @@ -206,6 +206,13 @@ timer_create (clock_id, evp, timerid) syscall_clockid, &sev, &newp->ktimerid); if (! INTERNAL_SYSCALL_ERROR_P (res, err)) { + /* Add to the queue of active timers with thread + delivery. */ + pthread_mutex_lock (&__active_timer_sigev_thread_lock); + newp->next = __active_timer_sigev_thread; + __active_timer_sigev_thread = newp; + pthread_mutex_unlock (&__active_timer_sigev_thread_lock); + *timerid = (timer_t) newp; return 0; } diff --git a/nptl/sysdeps/unix/sysv/linux/timer_delete.c b/nptl/sysdeps/unix/sysv/linux/timer_delete.c index 35055212a3..510541fc2a 100644 --- a/nptl/sysdeps/unix/sysv/linux/timer_delete.c +++ b/nptl/sysdeps/unix/sysv/linux/timer_delete.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -54,6 +54,27 @@ timer_delete (timerid) if (res == 0) { + if (kt->sigev_notify == SIGEV_THREAD) + { + /* Remove the timer from the list. */ + pthread_mutex_lock (&__active_timer_sigev_thread_lock); + if (__active_timer_sigev_thread == kt) + __active_timer_sigev_thread = kt->next; + else + { + struct timer *prevp = __active_timer_sigev_thread; + while (prevp->next != NULL) + if (prevp->next == kt) + { + prevp->next = kt->next; + break; + } + else + prevp = prevp->next; + } + pthread_mutex_unlock (&__active_timer_sigev_thread_lock); + } + # ifndef __ASSUME_POSIX_TIMERS /* We know the syscall support is available. */ __no_posix_timers = 1; diff --git a/nptl/sysdeps/unix/sysv/linux/timer_routines.c b/nptl/sysdeps/unix/sysv/linux/timer_routines.c index a5eb442251..b159316fb2 100644 --- a/nptl/sysdeps/unix/sysv/linux/timer_routines.c +++ b/nptl/sysdeps/unix/sysv/linux/timer_routines.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -27,6 +27,12 @@ #include "kernel-posix-timers.h" +/* List of active SIGEV_THREAD timers. */ +struct timer *__active_timer_sigev_thread; +/* Lock for the __active_timer_sigev_thread. */ +pthread_mutex_t __active_timer_sigev_thread_lock = PTHREAD_MUTEX_INITIALIZER; + + struct thread_start_data { void (*thrfunc) (sigval_t); @@ -95,19 +101,36 @@ timer_helper_thread (void *arg) if (si.si_code == SI_TIMER) { struct timer *tk = (struct timer *) si.si_ptr; - struct thread_start_data *td = malloc (sizeof (*td)); - /* There is not much we can do if the allocation fails. */ - if (td != NULL) - { - /* That is the signal we are waiting for. */ - td->thrfunc = tk->thrfunc; - td->sival = tk->sival; + /* Check the timer is still used and will not go away + while we are reading the values here. */ + pthread_mutex_lock (&__active_timer_sigev_thread_lock); - pthread_t th; - (void) pthread_create (&th, &tk->attr, timer_sigev_thread, - td); + struct timer *runp = __active_timer_sigev_thread; + while (runp != NULL) + if (runp == tk) + break; + else + runp = runp->next; + + if (runp != NULL) + { + struct thread_start_data *td = malloc (sizeof (*td)); + + /* There is not much we can do if the allocation fails. */ + if (td != NULL) + { + /* This is the signal we are waiting for. */ + td->thrfunc = tk->thrfunc; + td->sival = tk->sival; + + pthread_t th; + (void) pthread_create (&th, &tk->attr, + timer_sigev_thread, td); + } } + + pthread_mutex_unlock (&__active_timer_sigev_thread_lock); } else if (si.si_code == SI_TKILL) /* The thread is canceled. */ diff --git a/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c b/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c index 56a4f149e1..c738acd0c3 100644 --- a/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c +++ b/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c @@ -67,10 +67,21 @@ __unregister_atfork (dso_handle) It's a single linked list so readers are. */ do { + again: if (runp->dso_handle == dso_handle) { if (lastp == NULL) - __fork_handlers = runp->next; + { + /* We have to use an atomic operation here because + __linkin_atfork also uses one. */ + if (catomic_compare_and_exchange_bool_acq (&__fork_handlers, + runp->next, runp) + != 0) + { + runp = __fork_handlers; + goto again; + } + } else lastp->next = runp->next; diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S index 7065cfac32..4505e2cec6 100644 --- a/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S +++ b/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S @@ -178,6 +178,12 @@ __lll_timedlock_wait: movq %rdi, %r12 movq %rdx, %r13 + movl $2, %edx + xchgl %edx, (%r12) + + testl %edx, %edx + je 6f + 1: /* Get current time. */ movq %rsp, %rdi @@ -199,33 +205,31 @@ __lll_timedlock_wait: addq $1000000000, %rsi decq %rdi 4: testq %rdi, %rdi - js 5f /* Time is already up. */ + js 2f /* Time is already up. */ - /* Futex call. */ - movq %rdi, (%rsp) /* Store relative timeout. */ + /* Store relative timeout. */ + movq %rdi, (%rsp) movq %rsi, 8(%rsp) - movl $1, %eax + /* Futex call. */ movl $2, %edx - LOCK - cmpxchgl %edx, (%r12) - - testl %eax, %eax - je 8f - + movl $1, %eax movq %rsp, %r10 movl 24(%rsp), %esi LOAD_FUTEX_WAIT (%esi) movq %r12, %rdi movl $SYS_futex, %eax syscall - movq %rax, %rcx -8: /* NB: %edx == 2 */ - xorl %eax, %eax - LOCK - cmpxchgl %edx, (%r12) - jnz 7f + /* NB: %edx == 2 */ + xchgl %edx, (%r12) + + testl %edx, %edx + je 6f + + cmpl $-ETIMEDOUT, %eax + jne 1b +2: movl $ETIMEDOUT, %edx 6: addq $32, %rsp cfi_adjust_cfa_offset(-32) @@ -244,30 +248,11 @@ __lll_timedlock_wait: popq %r8 cfi_adjust_cfa_offset(-8) cfi_restore(%r8) + movl %edx, %eax retq 3: movl $EINVAL, %eax retq - - cfi_adjust_cfa_offset(72) - cfi_offset(%r8, -16) - cfi_offset(%r9, -24) - cfi_offset(%r12, -32) - cfi_offset(%r13, -40) - cfi_offset(%r14, -48) - /* Check whether the time expired. */ -7: cmpq $-ETIMEDOUT, %rcx - je 5f - - /* Make sure the current holder knows we are going to sleep. */ - movl %edx, %eax - xchgl %eax, (%rdi) - testl %eax, %eax - jz 6b - jmp 1b - -5: movl $ETIMEDOUT, %eax - jmp 6b cfi_endproc .size __lll_timedlock_wait,.-__lll_timedlock_wait #endif diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S index d730a7e12d..20bc59db9c 100644 --- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S +++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S @@ -134,12 +134,14 @@ __pthread_cond_timedwait: /* Only clocks 0 and 1 are allowed so far. Both are handled in the kernel. */ leaq 24(%rsp), %rsi +# ifdef SHARED movq __vdso_clock_gettime@GOTPCREL(%rip), %rax movq (%rax), %rax PTR_DEMANGLE (%rax) jz 26f call *%rax jmp 27f +# endif 26: movl $__NR_clock_gettime, %eax syscall 27: diff --git a/nptl/tst-basic7.c b/nptl/tst-basic7.c new file mode 100644 index 0000000000..da461e43df --- /dev/null +++ b/nptl/tst-basic7.c @@ -0,0 +1,56 @@ +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/resource.h> + +static void +use_up_memory (void) +{ + struct rlimit rl; + getrlimit (RLIMIT_AS, &rl); + rl.rlim_cur = 10 * 1024 * 1024; + setrlimit (RLIMIT_AS, &rl); + + char *c; + int PAGESIZE = getpagesize (); + while (1) + { + c = mmap (NULL, PAGESIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (c == MAP_FAILED) + break; + } +} + +static void * +child (void *arg) +{ + sleep (1); + return arg; +} + +static int +do_test (void) +{ + int err; + pthread_t tid; + + use_up_memory (); + + err = pthread_create (&tid, NULL, child, NULL); + if (err != 0) + { + printf ("pthread_create returns %d: %s\n", err, + err == EAGAIN ? "OK" : "FAIL"); + return err != EAGAIN; + } + + /* We did not fail to allocate memory despite the preparation. Oh well. */ + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |