diff options
49 files changed, 1083 insertions, 89 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 701b429e7c..073106c297 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,63 @@ +2006-07-28 Ulrich Drepper <drepper@redhat.com> + Jakub Jelinek <jakub@redhat.com> + + * descr.h: Change ENQUEUE_MUTEX and DEQUEUE_MUTEX for bit 0 + notification of PI mutex. Add ENQUEUE_MUTEX_PI. + * pthreadP.h: Define PTHREAD_MUTEX_PI_* macros for PI mutex types. + * pthread_mutex_setprioceilining.c: Adjust for mutex type name change. + * pthread_mutex_init.c: Add support for priority inheritance mutex. + * pthread_mutex_lock.c: Likewise. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_trylock.c: Likewise. + * pthread_mutex_unlock.c: Likewise. + * sysdeps/pthread/pthread_cond_broadcast.c: For PI mutexes wake + all mutexes. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.c: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.c: Likewise. + * sysdeps/unix/sysv/linux/pthread-pi-defines.sym: New file. + * sysdeps/unix/sysv/linux/Makefile (gen-as-const-header): Add + pthread-pi-defines.sym. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define FUTEX_LOCK_PI, + FUTEX_UNLOCK_PI, and FUTEX_TRYLOCK_PI. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_THREAD_PRIO_INHERIT to 200112L. + * tst-mutex1.c: Adjust to allow use in PI mutex test. + * tst-mutex2.c: Likewise. + * tst-mutex3.c: Likewise. + * tst-mutex4.c: Likewise. + * tst-mutex5.c: Likewise. + * tst-mutex6.c: Likewise. + * tst-mutex7.c: Likewise. + * tst-mutex7a.c: Likewise. + * tst-mutex8.c: Likewise. + * tst-mutex9.c: Likewise. + * tst-robust1.c: Likewise. + * tst-robust7.c: Likewise. + * tst-robust8.c: Likewise. + * tst-mutexpi1.c: New file. + * tst-mutexpi2.c: New file. + * tst-mutexpi3.c: New file. + * tst-mutexpi4.c: New file. + * tst-mutexpi5.c: New file. + * tst-mutexpi6.c: New file. + * tst-mutexpi7.c: New file. + * tst-mutexpi7a.c: New file. + * tst-mutexpi8.c: New file. + * tst-mutexpi9.c: New file. + * tst-robust1.c: New file. + * tst-robust2.c: New file. + * tst-robust3.c: New file. + * tst-robust4.c: New file. + * tst-robust5.c: New file. + * tst-robust6.c: New file. + * tst-robust7.c: New file. + * tst-robust8.c: New file. + * Makefile (tests): Add the new tests. + + * pthread_create.c (start_thread): Add some casts to avoid warnings. + * pthread_mutex_destroy.c: Remove unneeded label. + 2006-07-01 Ulrich Drepper <drepper@redhat.com> * pthread_mutex_init.c (__pthread_mutex_init): Move some diff --git a/nptl/Makefile b/nptl/Makefile index 8229486a25..a4c6174c42 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -200,6 +200,9 @@ tests = tst-typesizes \ tst-attr1 tst-attr2 tst-attr3 \ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \ + tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ + tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \ + tst-mutexpi9 \ tst-spin1 tst-spin2 tst-spin3 \ tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \ tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \ @@ -207,6 +210,8 @@ tests = tst-typesizes \ tst-cond20 tst-cond21 \ tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \ tst-robust6 tst-robust7 tst-robust8 \ + tst-robustpi1 tst-robustpi2 tst-robustpi3 tst-robustpi4 \ + tst-robustpi5 tst-robustpi6 tst-robustpi7 tst-robustpi8 \ tst-rwlock1 tst-rwlock2 tst-rwlock3 tst-rwlock4 tst-rwlock5 \ tst-rwlock6 tst-rwlock7 tst-rwlock8 tst-rwlock9 tst-rwlock10 \ tst-rwlock11 tst-rwlock12 tst-rwlock13 tst-rwlock14 \ diff --git a/nptl/descr.h b/nptl/descr.h index f89d3240da..607aa9fcdb 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -155,23 +155,28 @@ struct pthread first. */ # define QUEUE_PTR_ADJUST (offsetof (__pthread_list_t, __next)) -# define ENQUEUE_MUTEX(mutex) \ +# define ENQUEUE_MUTEX_BOTH(mutex, val) \ do { \ - __pthread_list_t *next = (THREAD_GETMEM (THREAD_SELF, robust_head.list) \ - - QUEUE_PTR_ADJUST); \ + __pthread_list_t *next = (__pthread_list_t *) \ + ((((uintptr_t) THREAD_GETMEM (THREAD_SELF, robust_head.list)) & ~1ul) \ + - QUEUE_PTR_ADJUST); \ next->__prev = (void *) &mutex->__data.__list.__next; \ - mutex->__data.__list.__next = (void *) &next->__next; \ + mutex->__data.__list.__next = THREAD_GETMEM (THREAD_SELF, \ + robust_head.list); \ mutex->__data.__list.__prev = (void *) &THREAD_SELF->robust_head; \ THREAD_SETMEM (THREAD_SELF, robust_head.list, \ - &mutex->__data.__list.__next); \ + (void *) (((uintptr_t) &mutex->__data.__list.__next) \ + | val)); \ } while (0) # define DEQUEUE_MUTEX(mutex) \ do { \ __pthread_list_t *next = (__pthread_list_t *) \ - ((char *) mutex->__data.__list.__next - QUEUE_PTR_ADJUST); \ + ((char *) (((uintptr_t) mutex->__data.__list.__next) & ~1ul) \ + - QUEUE_PTR_ADJUST); \ next->__prev = mutex->__data.__list.__prev; \ __pthread_list_t *prev = (__pthread_list_t *) \ - ((char *) mutex->__data.__list.__prev - QUEUE_PTR_ADJUST); \ + ((char *) (((uintptr_t) mutex->__data.__list.__prev) & ~1ul) \ + - QUEUE_PTR_ADJUST); \ prev->__next = mutex->__data.__list.__next; \ mutex->__data.__list.__prev = NULL; \ mutex->__data.__list.__next = NULL; \ @@ -183,27 +188,36 @@ struct pthread struct robust_list_head robust_head; }; -# define ENQUEUE_MUTEX(mutex) \ +# define ENQUEUE_MUTEX_BOTH(mutex, val) \ do { \ mutex->__data.__list.__next \ = THREAD_GETMEM (THREAD_SELF, robust_list.__next); \ - THREAD_SETMEM (THREAD_SELF, robust_list.__next, &mutex->__data.__list); \ + THREAD_SETMEM (THREAD_SELF, robust_list.__next, \ + ((uintptr_t) &mutex->__data.__list) | val); \ } while (0) # define DEQUEUE_MUTEX(mutex) \ do { \ - __pthread_slist_t *runp = THREAD_GETMEM (THREAD_SELF, robust_list.__next);\ + __pthread_slist_t *runp = (__pthread_slist_t *) \ + (((uintptr_t) THREAD_GETMEM (THREAD_SELF, robust_list.__next)) & ~1ul); \ if (runp == &mutex->__data.__list) \ THREAD_SETMEM (THREAD_SELF, robust_list.__next, runp->__next); \ else \ { \ - while (runp->__next != &mutex->__data.__list) \ - runp = runp->__next; \ + __pthread_slist_t *next = (__pthread_slist_t *) \ + (((uintptr_t) runp->__next) & ~1ul); \ + while (next != &mutex->__data.__list) \ + { \ + runp = next; \ + next = (__pthread_slist_t *) (((uintptr_t) runp->__next) & ~1ul); \ + } \ \ - runp->__next = runp->__next->__next; \ + runp->__next = next->__next; \ mutex->__data.__list.__next = NULL; \ } \ } while (0) #endif +#define ENQUEUE_MUTEX(mutex) ENQUEUE_MUTEX_BOTH (mutex, 0) +#define ENQUEUE_MUTEX_PI(mutex) ENQUEUE_MUTEX_BOTH (mutex, 1) /* List of cleanup buffers. */ struct _pthread_cleanup_buffer *cleanup; diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index c7f57e235a..dc98bb19c0 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -61,6 +61,7 @@ /* Internal mutex type value. */ enum { + PTHREAD_MUTEX_KIND_MASK_NP = 3, PTHREAD_MUTEX_ROBUST_NORMAL_NP = 16, PTHREAD_MUTEX_ROBUST_RECURSIVE_NP = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_RECURSIVE_NP, @@ -68,8 +69,24 @@ enum = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ERRORCHECK_NP, PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ADAPTIVE_NP, - PTHREAD_MUTEX_PRIO_INHERIT_PRIVATE_NP = 32, - PTHREAD_MUTEX_PRIO_PROTECT_PRIVATE_NP = 64 + PTHREAD_MUTEX_PRIO_INHERIT_NP = 32, + PTHREAD_MUTEX_PI_NORMAL_NP + = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_NORMAL, + PTHREAD_MUTEX_PI_RECURSIVE_NP + = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_PI_ERRORCHECK_NP + = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_PI_ADAPTIVE_NP + = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ADAPTIVE_NP, + PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP + = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP, + PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP + = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_RECURSIVE_NP, + PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP + = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP, + PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP + = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP, + PTHREAD_MUTEX_PRIO_PROTECT_NP = 64 }; #define PTHREAD_MUTEX_PRIO_CEILING_SHIFT 16 #define PTHREAD_MUTEX_PRIO_CEILING_MASK 0x00ff0000 diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c index 71365a17e8..c1ac199bb9 100644 --- a/nptl/pthread_create.c +++ b/nptl/pthread_create.c @@ -330,9 +330,11 @@ start_thread (void *arg) # else __pthread_slist_t *robust = pd->robust_list.__next; # endif -/* We let the kernel do the notification if it is able to do so. */ + /* We let the kernel do the notification if it is able to do so. + If we have to do it here there for sure are no PI mutexes involved + since the kernel support for them is even more recent. */ if (__set_robust_list_avail < 0 - && __builtin_expect (robust != &pd->robust_head, 0)) + && __builtin_expect (robust != (void *) &pd->robust_head, 0)) { do { @@ -348,7 +350,7 @@ start_thread (void *arg) lll_robust_mutex_dead (this->__lock); } - while (robust != &pd->robust_head); + while (robust != (void *) &pd->robust_head); } #endif diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c index 7829979f35..e2c9f8a39f 100644 --- a/nptl/pthread_mutex_destroy.c +++ b/nptl/pthread_mutex_destroy.c @@ -30,7 +30,6 @@ __pthread_mutex_destroy (mutex) return EBUSY; /* Set to an invalid value. */ - dead_robust_mutex: mutex->__data.__kind = -1; return 0; diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c index c3f9c2d1c0..6ceca86052 100644 --- a/nptl/pthread_mutex_init.c +++ b/nptl/pthread_mutex_init.c @@ -29,6 +29,11 @@ static const struct pthread_mutexattr default_attr = }; +#ifndef __ASSUME_FUTEX_LOCK_PI +static int tpi_supported; +#endif + + int __pthread_mutex_init (mutex, mutexattr) pthread_mutex_t *mutex; @@ -41,8 +46,7 @@ __pthread_mutex_init (mutex, mutexattr) imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr; /* Sanity checks. */ - // XXX For now we don't support priority inherited or priority protected - // XXX mutexes. + // XXX For now we don't support priority protected mutexes. switch (__builtin_expect (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK, PTHREAD_PRIO_NONE @@ -51,6 +55,22 @@ __pthread_mutex_init (mutex, mutexattr) case PTHREAD_PRIO_NONE << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: break; + case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: +#ifndef __ASSUME_FUTEX_LOCK_PI + if (__builtin_expect (tpi_supported == 0, 0)) + { + int lock = 0; + INTERNAL_SYSCALL_DECL (err); + int ret = INTERNAL_SYSCALL (futex, err, 4, &lock, FUTEX_UNLOCK_PI, + 0, 0); + assert (INTERNAL_SYSCALL_ERROR_P (ret, err)); + tpi_supported = INTERNAL_SYSCALL_ERRNO (ret, err) == ENOSYS ? -1 : 1; + } + if (__builtin_expect (tpi_supported < 0, 0)) + return ENOTSUP; +#endif + break; + default: return ENOTSUP; } @@ -75,11 +95,11 @@ __pthread_mutex_init (mutex, mutexattr) switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK) { case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: - mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_PRIVATE_NP; + mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP; break; case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: - mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_PRIVATE_NP; + mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; if (PTHREAD_MUTEX_PRIO_CEILING_MASK == PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) mutex->__data.__kind |= (imutexattr->mutexkind diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c index 06eef49c71..5345766883 100644 --- a/nptl/pthread_mutex_lock.c +++ b/nptl/pthread_mutex_lock.c @@ -20,6 +20,7 @@ #include <assert.h> #include <errno.h> #include <stdlib.h> +#include <unistd.h> #include "pthreadP.h" #include <lowlevellock.h> @@ -205,6 +206,134 @@ __pthread_mutex_lock (mutex) THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); break; + case PTHREAD_MUTEX_PI_RECURSIVE_NP: + case PTHREAD_MUTEX_PI_ERRORCHECK_NP: + case PTHREAD_MUTEX_PI_NORMAL_NP: + case PTHREAD_MUTEX_PI_ADAPTIVE_NP: + case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP: + case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP: + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + { + int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + + if (robust) + /* Note: robust PI futexes are signaled by setting bit 0. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + (void *) (((uintptr_t) &mutex->__data.__list.__next) + | 1)); + + oldval = mutex->__data.__lock; + + /* Check whether we already hold the mutex. */ + if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0)) + { + if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) + { + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return EDEADLK; + } + + if (kind == PTHREAD_MUTEX_RECURSIVE_NP) + { + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + return 0; + } + } + + int newval = id; +#ifdef NO_INCR + newval |= FUTEX_WAITERS; +#endif + oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + newval, 0); + + if (oldval != 0) + { + /* The mutex is locked. The kernel will now take care of + everything. */ + INTERNAL_SYSCALL_DECL (__err); + int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock, + FUTEX_LOCK_PI, 1, 0); + + if (INTERNAL_SYSCALL_ERROR_P (e, __err) + && (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH + || INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK)) + { + assert (INTERNAL_SYSCALL_ERRNO (e, __err) != EDEADLK + || (kind != PTHREAD_MUTEX_ERRORCHECK_NP + && kind != PTHREAD_MUTEX_RECURSIVE_NP)); + /* ESRCH can happen only for non-robust PI mutexes where + the owner of the lock died. */ + assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH || !robust); + + /* Delay the thread indefinitely. */ + while (1) + __pause_nocancel (); + } + + oldval = mutex->__data.__lock; + + assert (robust || (oldval & FUTEX_OWNER_DIED) == 0); + } + + if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0)) + { + atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED); + + /* We got the mutex. */ + mutex->__data.__count = 1; + /* But it is inconsistent unless marked otherwise. */ + mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + + ENQUEUE_MUTEX_PI (mutex); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Note that we deliberately exit here. If we fall + through to the end of the function __nusers would be + incremented which is not correct because the old owner + has to be discounted. If we are not supposed to + increment __nusers we actually have to decrement it here. */ +#ifdef NO_INCR + --mutex->__data.__nusers; +#endif + + return EOWNERDEAD; + } + + if (robust + && __builtin_expect (mutex->__data.__owner + == PTHREAD_MUTEX_NOTRECOVERABLE, 0)) + { + /* This mutex is now not recoverable. */ + mutex->__data.__count = 0; + + INTERNAL_SYSCALL_DECL (__err); + INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock, + FUTEX_UNLOCK_PI, 0, 0); + + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return ENOTRECOVERABLE; + } + + mutex->__data.__count = 1; + if (robust) + { + ENQUEUE_MUTEX_PI (mutex); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + } + } + break; + default: /* Correct code cannot set any other type. */ return EINVAL; diff --git a/nptl/pthread_mutex_setprioceiling.c b/nptl/pthread_mutex_setprioceiling.c index 999b635ac1..3271f8833a 100644 --- a/nptl/pthread_mutex_setprioceiling.c +++ b/nptl/pthread_mutex_setprioceiling.c @@ -30,7 +30,7 @@ pthread_mutex_setprioceiling (mutex, prioceiling, old_ceiling) { /* The low bits of __kind aren't ever changed after pthread_mutex_init, so we don't need a lock yet. */ - if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_PRIVATE_NP) == 0) + if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) return EINVAL; if (prioceiling < 0 || __builtin_expect (prioceiling > 255, 0)) diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c index 7c48c7ce6b..12f6c997bb 100644 --- a/nptl/pthread_mutex_timedlock.c +++ b/nptl/pthread_mutex_timedlock.c @@ -35,7 +35,7 @@ pthread_mutex_timedlock (mutex, abstime) /* We must not check ABSTIME here. If the thread does not block abstime must not be checked for a valid value. */ - switch (mutex->__data.__kind) + switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) { /* Recursive mutex. */ case PTHREAD_MUTEX_RECURSIVE_NP: @@ -65,7 +65,7 @@ pthread_mutex_timedlock (mutex, abstime) /* Error checking mutex. */ case PTHREAD_MUTEX_ERRORCHECK_NP: /* Check whether we already hold the mutex. */ - if (mutex->__data.__owner == id) + if (__builtin_expect (mutex->__data.__owner == id, 0)) return EDEADLK; /* FALLTHROUGH */ @@ -134,7 +134,7 @@ pthread_mutex_timedlock (mutex, abstime) ENQUEUE_MUTEX (mutex); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); - /* Note that we deliberately exist here. If we fall + /* Note that we deliberately exit here. If we fall through to the end of the function __nusers would be incremented which is not correct because the old owner has to be discounted. */ @@ -194,6 +194,150 @@ pthread_mutex_timedlock (mutex, abstime) THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); break; + case PTHREAD_MUTEX_PI_RECURSIVE_NP: + case PTHREAD_MUTEX_PI_ERRORCHECK_NP: + case PTHREAD_MUTEX_PI_NORMAL_NP: + case PTHREAD_MUTEX_PI_ADAPTIVE_NP: + case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP: + case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP: + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + { + int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + + if (robust) + /* Note: robust PI futexes are signaled by setting bit 0. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + (void *) (((uintptr_t) &mutex->__data.__list.__next) + | 1)); + + oldval = mutex->__data.__lock; + + /* Check whether we already hold the mutex. */ + if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0)) + { + if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) + { + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return EDEADLK; + } + + if (kind == PTHREAD_MUTEX_RECURSIVE_NP) + { + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + return 0; + } + } + + oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + id, 0); + + if (oldval != 0) + { + /* The mutex is locked. The kernel will now take care of + everything. The timeout value must be a relative value. + Convert it. */ + INTERNAL_SYSCALL_DECL (__err); + + int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock, + FUTEX_LOCK_PI, 1, abstime); + if (INTERNAL_SYSCALL_ERROR_P (e, __err)) + { + if (INTERNAL_SYSCALL_ERRNO (e, __err) == ETIMEDOUT) + return ETIMEDOUT; + + if (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH + || INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK) + { + assert (INTERNAL_SYSCALL_ERRNO (e, __err) != EDEADLK + || (kind != PTHREAD_MUTEX_ERRORCHECK_NP + && kind != PTHREAD_MUTEX_RECURSIVE_NP)); + /* ESRCH can happen only for non-robust PI mutexes where + the owner of the lock died. */ + assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH + || !robust); + + /* Delay the thread until the timeout is reached. + Then return ETIMEDOUT. */ + struct timespec reltime; + struct timespec now; + + INTERNAL_SYSCALL (clock_gettime, __err, 2, CLOCK_REALTIME, + &now); + reltime.tv_sec = abstime->tv_sec - now.tv_sec; + reltime.tv_nsec = abstime->tv_nsec - now.tv_nsec; + if (reltime.tv_nsec < 0) + { + reltime.tv_nsec += 1000000000; + --reltime.tv_sec; + } + if (reltime.tv_sec >= 0) + while (__nanosleep_nocancel (&reltime, &reltime) != 0) + continue; + + return ETIMEDOUT; + } + + return INTERNAL_SYSCALL_ERRNO (e, __err); + } + + oldval = mutex->__data.__lock; + + assert (robust || (oldval & FUTEX_OWNER_DIED) == 0); + } + + if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0)) + { + atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED); + + /* We got the mutex. */ + mutex->__data.__count = 1; + /* But it is inconsistent unless marked otherwise. */ + mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + + ENQUEUE_MUTEX_PI (mutex); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Note that we deliberately exit here. If we fall + through to the end of the function __nusers would be + incremented which is not correct because the old owner + has to be discounted. */ + return EOWNERDEAD; + } + + if (robust + && __builtin_expect (mutex->__data.__owner + == PTHREAD_MUTEX_NOTRECOVERABLE, 0)) + { + /* This mutex is now not recoverable. */ + mutex->__data.__count = 0; + + INTERNAL_SYSCALL_DECL (__err); + INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock, + FUTEX_UNLOCK_PI, 0, 0); + + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return ENOTRECOVERABLE; + } + + mutex->__data.__count = 1; + if (robust) + { + ENQUEUE_MUTEX_PI (mutex); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + } + } + break; + default: /* Correct code cannot set any other type. */ return EINVAL; diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c index 148a6e919f..f3a18569a1 100644 --- a/nptl/pthread_mutex_trylock.c +++ b/nptl/pthread_mutex_trylock.c @@ -152,7 +152,6 @@ __pthread_mutex_trylock (mutex) return EBUSY; } - robust: if (__builtin_expect (mutex->__data.__owner == PTHREAD_MUTEX_NOTRECOVERABLE, 0)) { @@ -175,6 +174,129 @@ __pthread_mutex_trylock (mutex) return 0; + case PTHREAD_MUTEX_PI_RECURSIVE_NP: + case PTHREAD_MUTEX_PI_ERRORCHECK_NP: + case PTHREAD_MUTEX_PI_NORMAL_NP: + case PTHREAD_MUTEX_PI_ADAPTIVE_NP: + case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP: + case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP: + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + { + int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + + if (robust) + /* Note: robust PI futexes are signaled by setting bit 0. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + (void *) (((uintptr_t) &mutex->__data.__list.__next) + | 1)); + + oldval = mutex->__data.__lock; + + /* Check whether we already hold the mutex. */ + if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0)) + { + if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) + { + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return EDEADLK; + } + + if (kind == PTHREAD_MUTEX_RECURSIVE_NP) + { + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + return 0; + } + } + + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + id, 0); + + if (oldval != 0) + { + if ((oldval & FUTEX_OWNER_DIED) == 0) + { + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; + } + + assert (robust); + + /* The mutex owner died. The kernel will now take care of + everything. */ + INTERNAL_SYSCALL_DECL (__err); + int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock, + FUTEX_TRYLOCK_PI, 0, 0); + + if (INTERNAL_SYSCALL_ERROR_P (e, __err) + && INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK) + { + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; + } + + oldval = mutex->__data.__lock; + } + + if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0)) + { + atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED); + + /* We got the mutex. */ + mutex->__data.__count = 1; + /* But it is inconsistent unless marked otherwise. */ + mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + + ENQUEUE_MUTEX (mutex); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Note that we deliberately exit here. If we fall + through to the end of the function __nusers would be + incremented which is not correct because the old owner + has to be discounted. */ + return EOWNERDEAD; + } + + if (robust + && __builtin_expect (mutex->__data.__owner + == PTHREAD_MUTEX_NOTRECOVERABLE, 0)) + { + /* This mutex is now not recoverable. */ + mutex->__data.__count = 0; + + INTERNAL_SYSCALL_DECL (__err); + INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock, + FUTEX_UNLOCK_PI, 0, 0); + + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return ENOTRECOVERABLE; + } + + if (robust) + { + ENQUEUE_MUTEX_PI (mutex); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + } + + mutex->__data.__owner = id; + ++mutex->__data.__nusers; + mutex->__data.__count = 1; + + return 0; + } + default: /* Correct code cannot set any other type. */ return EINVAL; diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c index bf9aa7625f..2b5064fbac 100644 --- a/nptl/pthread_mutex_unlock.c +++ b/nptl/pthread_mutex_unlock.c @@ -119,6 +119,89 @@ __pthread_mutex_unlock_usercnt (mutex, decr) THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); break; + case PTHREAD_MUTEX_PI_RECURSIVE_NP: + /* Recursive mutex. */ + if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) + return EPERM; + + if (--mutex->__data.__count != 0) + /* We still hold the mutex. */ + return 0; + goto continue_pi; + + case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP: + /* Recursive mutex. */ + if ((mutex->__data.__lock & FUTEX_TID_MASK) + == THREAD_GETMEM (THREAD_SELF, tid) + && __builtin_expect (mutex->__data.__owner + == PTHREAD_MUTEX_INCONSISTENT, 0)) + { + if (--mutex->__data.__count != 0) + /* We still hold the mutex. */ + return ENOTRECOVERABLE; + + goto pi_notrecoverable; + } + + if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) + return EPERM; + + if (--mutex->__data.__count != 0) + /* We still hold the mutex. */ + return 0; + + goto continue_pi; + + case PTHREAD_MUTEX_PI_ERRORCHECK_NP: + case PTHREAD_MUTEX_PI_NORMAL_NP: + case PTHREAD_MUTEX_PI_ADAPTIVE_NP: + case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP: + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + if ((mutex->__data.__lock & FUTEX_TID_MASK) + != THREAD_GETMEM (THREAD_SELF, tid) + || ! lll_mutex_islocked (mutex->__data.__lock)) + return EPERM; + + /* If the previous owner died and the caller did not succeed in + making the state consistent, mark the mutex as unrecoverable + and make all waiters. */ + if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 + && __builtin_expect (mutex->__data.__owner + == PTHREAD_MUTEX_INCONSISTENT, 0)) + pi_notrecoverable: + newowner = PTHREAD_MUTEX_NOTRECOVERABLE; + + continue_pi: + if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) + { + /* Remove mutex from the list. + Note: robust PI futexes are signaled by setting bit 0. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + (void *) (((uintptr_t) &mutex->__data.__list.__next) + | 1)); + DEQUEUE_MUTEX (mutex); + } + + mutex->__data.__owner = newowner; + if (decr) + /* One less user. */ + --mutex->__data.__nusers; + + /* Unlock. */ + if ((mutex->__data.__lock & FUTEX_WAITERS) != 0 + || atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, 0, + THREAD_GETMEM (THREAD_SELF, + tid))) + { + INTERNAL_SYSCALL_DECL (__err); + INTERNAL_SYSCALL (futex, __err, 2, &mutex->__data.__lock, + FUTEX_UNLOCK_PI); + } + + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + break; + default: /* Correct code cannot set any other type. */ return EINVAL; diff --git a/nptl/sysdeps/pthread/pthread_cond_broadcast.c b/nptl/sysdeps/pthread/pthread_cond_broadcast.c index 1eac8ecf83..2b8b5460f4 100644 --- a/nptl/sysdeps/pthread/pthread_cond_broadcast.c +++ b/nptl/sysdeps/pthread/pthread_cond_broadcast.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. @@ -55,6 +55,12 @@ __pthread_cond_broadcast (cond) /* Wake everybody. */ pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex; + + /* XXX: Kernel so far doesn't support requeue to PI futex. */ + if (__builtin_expect (mut->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP, + 0)) + goto wake_all; + /* lll_futex_requeue returns 0 for success and non-zero for errors. */ if (__builtin_expect (lll_futex_requeue (&cond->__data.__futex, 1, diff --git a/nptl/sysdeps/unix/sysv/linux/Makefile b/nptl/sysdeps/unix/sysv/linux/Makefile index 88dce1a886..cfcdb6d97f 100644 --- a/nptl/sysdeps/unix/sysv/linux/Makefile +++ b/nptl/sysdeps/unix/sysv/linux/Makefile @@ -25,7 +25,7 @@ libpthread-sysdep_routines += pt-fork pthread_mutex_cond_lock gen-as-const-headers += lowlevelcond.sym lowlevelrwlock.sym \ lowlevelbarrier.sym unwindbuf.sym \ - lowlevelrobustlock.sym + lowlevelrobustlock.sym pthread-pi-defines.sym endif ifeq ($(subdir),posix) diff --git a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h index 92c2d32827..d8eced1f22 100644 --- a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h +++ b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -1,5 +1,5 @@ /* Define POSIX options for Linux. - Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1996-2004, 2006 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 @@ -79,6 +79,9 @@ /* We support user-defined stacks. */ #define _POSIX_THREAD_ATTR_STACKADDR 200112L +/* We support priority inheritence. */ +#define _POSIX_THREAD_PRIO_INHERIT 200112L + /* We support POSIX.1b semaphores. */ #define _POSIX_SEMAPHORES 200112L @@ -171,8 +174,7 @@ /* Typed memory objects are not available. */ #define _POSIX_TYPED_MEMORY_OBJECTS -1 -/* No support for priority inheritance or protection so far. */ -#define _POSIX_THREAD_PRIO_INHERIT -1 +/* No support for priority protection so far. */ #define _POSIX_THREAD_PRIO_PROTECT -1 #endif /* posix_opt.h */ diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S index 5471c1c927..56f7be8246 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -21,6 +21,7 @@ #include <shlib-compat.h> #include <lowlevelcond.h> #include <kernel-features.h> +#include <pthread-pi-defines.h> #ifdef UP # define LOCK @@ -94,6 +95,10 @@ __pthread_cond_broadcast: 8: cmpl $-1, %edi je 9f + /* XXX: The kernel so far doesn't support requeue to PI futex. */ + testl $PI_BIT, MUTEX_KIND(%edi) + jne 9f + /* Wake up all threads. */ movl $FUTEX_CMP_REQUEUE, %ecx movl $SYS_futex, %eax diff --git a/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym b/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym new file mode 100644 index 0000000000..a1b6794260 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym @@ -0,0 +1,6 @@ +#include <pthreadP.h> + +-- These PI macros are used by assembly code. + +MUTEX_KIND offsetof (pthread_mutex_t, __data.__kind) +PI_BIT PTHREAD_MUTEX_PRIO_INHERIT_NP diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S index 72e7bc5b24..006de2696e 100644 --- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S +++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -21,6 +21,7 @@ #include <shlib-compat.h> #include <lowlevelcond.h> #include <kernel-features.h> +#include <pthread-pi-defines.h> #ifdef UP # define LOCK @@ -80,6 +81,10 @@ __pthread_cond_broadcast: 8: cmpq $-1, %r8 je 9f + /* XXX: The kernel so far doesn't support requeue to PI futex. */ + testl $PI_BIT, MUTEX_KIND(%r8) + jne 9f + /* Wake up all threads. */ movl $FUTEX_CMP_REQUEUE, %esi movl $SYS_futex, %eax diff --git a/nptl/tst-mutex1.c b/nptl/tst-mutex1.c index 50b5ccaf0e..c3ef5b2b51 100644 --- a/nptl/tst-mutex1.c +++ b/nptl/tst-mutex1.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -19,6 +19,12 @@ #include <pthread.h> #include <stdio.h> +#include <errno.h> + + +#ifndef ATTR +# define ATTR NULL +#endif static int @@ -26,12 +32,24 @@ do_test (void) { pthread_mutex_t m; - if (pthread_mutex_init (&m, NULL) != 0) + int e = pthread_mutex_init (&m, ATTR); + if (ATTR != NULL && e == ENOTSUP) + { + puts ("cannot support selected type of mutexes"); + return 0; + } + else if (e != 0) { puts ("mutex_init failed"); return 1; } + if (ATTR != NULL && pthread_mutexattr_destroy (ATTR) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + if (pthread_mutex_lock (&m) != 0) { puts ("mutex_lock failed"); diff --git a/nptl/tst-mutex2.c b/nptl/tst-mutex2.c index f589a1ea17..b09f569a5a 100644 --- a/nptl/tst-mutex2.c +++ b/nptl/tst-mutex2.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -105,115 +105,134 @@ do_test (void) if (pthread_mutexattr_init (&a) != 0) { puts ("mutexattr_init failed"); - exit (1); + return 1; } if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_ERRORCHECK) != 0) { puts ("mutexattr_settype failed"); - exit (1); + return 1; } - if (pthread_mutex_init (&m, &a) != 0) +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + e = pthread_mutex_init (&m, &a); + if (e != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif puts ("mutex_init failed"); - exit (1); + return 1; } if (pthread_barrier_init (&b, NULL, 2) != 0) { puts ("barrier_init failed"); - exit (1); + return 1; } - if ((e = pthread_mutex_unlock (&m)) == 0) + e = pthread_mutex_unlock (&m); + if (e == 0) { puts ("1st mutex_unlock succeeded"); - exit (1); + return 1; } else if (e != EPERM) { puts ("1st mutex_unlock error != EPERM"); - exit (1); + return 1; } if (pthread_mutex_lock (&m) != 0) { puts ("mutex_lock failed"); - exit (1); + return 1; } - if ((e = pthread_mutex_lock (&m)) == 0) + e = pthread_mutex_lock (&m); + if (e == 0) { puts ("2nd mutex_lock succeeded"); - exit (1); + return 1; } else if (e != EDEADLK) { puts ("2nd mutex_lock error != EDEADLK"); - exit (1); + return 1; } pthread_t th; if (pthread_create (&th, NULL, tf, NULL) != 0) { puts ("create failed"); - exit (1); + return 1; } e = pthread_barrier_wait (&b); if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) { puts ("1st barrier_wait failed"); - exit (1); + return 1; } if (pthread_mutex_unlock (&m) != 0) { puts ("2nd mutex_unlock failed"); - exit (1); + return 1; } - if ((e = pthread_mutex_unlock (&m)) == 0) + e = pthread_mutex_unlock (&m); + if (e == 0) { puts ("3rd mutex_unlock succeeded"); - exit (1); + return 1; } else if (e != EPERM) { puts ("3rd mutex_unlock error != EPERM"); - exit (1); + return 1; } e = pthread_barrier_wait (&b); if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) { puts ("2nd barrier_wait failed"); - exit (1); + return 1; } if (pthread_join (th, NULL) != 0) { puts ("join failed"); - exit (1); + return 1; } if (pthread_mutex_destroy (&m) != 0) { puts ("mutex_destroy failed"); - exit (1); + return 1; } if (pthread_barrier_destroy (&b) != 0) { puts ("barrier_destroy failed"); - exit (1); + return 1; } if (pthread_mutexattr_destroy (&a) != 0) { puts ("mutexattr_destroy failed"); - exit (1); + return 1; } return 0; diff --git a/nptl/tst-mutex3.c b/nptl/tst-mutex3.c index 8e57924ba6..2848096538 100644 --- a/nptl/tst-mutex3.c +++ b/nptl/tst-mutex3.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -113,8 +113,25 @@ do_test (void) return 1; } - if (pthread_mutex_init (&m, &a) != 0) +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + int e; + e = pthread_mutex_init (&m, &a); + if (e != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif puts ("mutex_init failed"); return 1; } @@ -162,7 +179,7 @@ do_test (void) return 1; } - int e = pthread_barrier_wait (&b); + e = pthread_barrier_wait (&b); if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) { puts ("barrier_wait failed"); diff --git a/nptl/tst-mutex4.c b/nptl/tst-mutex4.c index 0ce7313caf..9699c2db45 100644 --- a/nptl/tst-mutex4.c +++ b/nptl/tst-mutex4.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -42,6 +42,8 @@ do_test (void) char *p; int err; int s; + pthread_barrier_t *b; + pthread_barrierattr_t ba; fd = mkstemp (tmpfname); if (fd == -1) @@ -70,9 +72,12 @@ do_test (void) return 1; } - m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t)) + m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t) - 1) & ~(__alignof (pthread_mutex_t) - 1)); - p = (char *) (m + 1); + b = (pthread_barrier_t *) (((uintptr_t) (m + 1) + + __alignof (pthread_barrier_t) - 1) + & ~(__alignof (pthread_barrier_t) - 1)); + p = (char *) (b + 1); if (pthread_mutexattr_init (&a) != 0) { @@ -110,8 +115,23 @@ do_test (void) return 1; } - if (pthread_mutex_init (m, &a) != 0) +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + if ((err = pthread_mutex_init (m, &a)) != 0) + { +#ifdef ENABLE_PI + if (err == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif puts ("mutex_init failed"); return 1; } @@ -128,6 +148,30 @@ do_test (void) return 1; } + if (pthread_barrierattr_init (&ba) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + return 1; + } + + if (pthread_barrier_init (b, &ba, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&ba) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + err = pthread_mutex_trylock (m); if (err == 0) { @@ -142,6 +186,12 @@ do_test (void) *p = 0; + if (pthread_mutex_unlock (m) != 0) + { + puts ("parent: 1st mutex_unlock failed"); + return 1; + } + puts ("going to fork now"); pid = fork (); if (pid == -1) @@ -151,7 +201,19 @@ do_test (void) } else if (pid == 0) { - /* Play some lock ping-pong. It's our turn to unlock first. */ + if (pthread_mutex_lock (m) != 0) + { + puts ("child: mutex_lock failed"); + return 1; + } + + int e = pthread_barrier_wait (b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + return 1; + } + if ((*p)++ != 0) { puts ("child: *p != 0"); @@ -160,7 +222,7 @@ do_test (void) if (pthread_mutex_unlock (m) != 0) { - puts ("child: 1st mutex_unlock failed"); + puts ("child: mutex_unlock failed"); return 1; } @@ -168,6 +230,13 @@ do_test (void) } else { + int e = pthread_barrier_wait (b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: barrier_wait failed"); + return 1; + } + if (pthread_mutex_lock (m) != 0) { puts ("parent: 2nd mutex_lock failed"); @@ -180,6 +249,24 @@ do_test (void) return 1; } + if (pthread_mutex_unlock (m) != 0) + { + puts ("parent: 2nd mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_barrier_destroy (b) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + puts ("parent done"); } diff --git a/nptl/tst-mutex5.c b/nptl/tst-mutex5.c index eb35b78d36..291274fee5 100644 --- a/nptl/tst-mutex5.c +++ b/nptl/tst-mutex5.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -52,8 +52,24 @@ do_test (void) return 1; } - if (pthread_mutex_init (&m, &a) != 0) +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + err = pthread_mutex_init (&m, &a); + if (err != 0) + { +#ifdef ENABLE_PI + if (err == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif puts ("mutex_init failed"); return 1; } diff --git a/nptl/tst-mutex6.c b/nptl/tst-mutex6.c index f066c62edc..e5698c3eb0 100644 --- a/nptl/tst-mutex6.c +++ b/nptl/tst-mutex6.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -21,6 +21,12 @@ #include <signal.h> #include <stdio.h> #include <unistd.h> +#include <errno.h> + + +#ifndef ATTR +# define ATTR NULL +#endif static int @@ -28,12 +34,24 @@ do_test (void) { pthread_mutex_t m; - if (pthread_mutex_init (&m, NULL) != 0) + int e = pthread_mutex_init (&m, ATTR); + if (ATTR != NULL && e == ENOTSUP) + { + puts ("cannot support selected type of mutexes"); + e = pthread_mutex_init (&m, NULL); + } + if (e != 0) { puts ("mutex_init failed"); return 1; } + if (ATTR != NULL && pthread_mutexattr_destroy (ATTR) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + if (pthread_mutex_lock (&m) != 0) { puts ("1st mutex_lock failed"); diff --git a/nptl/tst-mutex7.c b/nptl/tst-mutex7.c index a9b9f318cb..27e5d8eb28 100644 --- a/nptl/tst-mutex7.c +++ b/nptl/tst-mutex7.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -17,17 +17,19 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <errno.h> #include <pthread.h> #include <stdio.h> +#include <stdlib.h> #include <time.h> -#ifndef INIT -# define INIT PTHREAD_MUTEX_INITIALIZER +#ifndef TYPE +# define TYPE PTHREAD_MUTEX_DEFAULT #endif -static pthread_mutex_t lock = INIT; +static pthread_mutex_t lock; #define ROUNDS 1000 @@ -65,6 +67,48 @@ tf (void *arg) static int do_test (void) { + pthread_mutexattr_t a; + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_settype (&a, TYPE) != 0) + { + puts ("mutexattr_settype failed"); + exit (1); + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + int e = pthread_mutex_init (&lock, &a); + if (e != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + pthread_attr_t at; pthread_t th[N]; int cnt; diff --git a/nptl/tst-mutex7a.c b/nptl/tst-mutex7a.c index f08799ae79..30d46b81af 100644 --- a/nptl/tst-mutex7a.c +++ b/nptl/tst-mutex7a.c @@ -1,2 +1,2 @@ -#define INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP #include "tst-mutex7.c" diff --git a/nptl/tst-mutex9.c b/nptl/tst-mutex9.c index 5ea2f0ac99..f9d379343d 100644 --- a/nptl/tst-mutex9.c +++ b/nptl/tst-mutex9.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -88,8 +88,24 @@ do_test (void) return 1; } - if (pthread_mutex_init (m, &a) != 0) +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + int e; + if ((e = pthread_mutex_init (m, &a)) != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI mutexes unsupported"); + return 0; + } +#endif puts ("mutex_init failed"); return 1; } @@ -138,7 +154,7 @@ do_test (void) ts.tv_nsec -= 1000000000; } - int e = pthread_mutex_timedlock (m, &ts); + e = pthread_mutex_timedlock (m, &ts); if (e == 0) { puts ("child: mutex_timedlock succeeded"); diff --git a/nptl/tst-mutexpi1.c b/nptl/tst-mutexpi1.c new file mode 100644 index 0000000000..623ede9fa5 --- /dev/null +++ b/nptl/tst-mutexpi1.c @@ -0,0 +1,27 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutexattr_t a; + +static void +prepare (void) +{ + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("mutexattr_setprotocol failed"); + exit (1); + } +} +#define PREPARE(argc, argv) prepare () + + +#define ATTR &a +#include "tst-mutex1.c" diff --git a/nptl/tst-mutexpi2.c b/nptl/tst-mutexpi2.c new file mode 100644 index 0000000000..fbe48716fd --- /dev/null +++ b/nptl/tst-mutexpi2.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex2.c" diff --git a/nptl/tst-mutexpi3.c b/nptl/tst-mutexpi3.c new file mode 100644 index 0000000000..e338ebfff9 --- /dev/null +++ b/nptl/tst-mutexpi3.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex3.c" diff --git a/nptl/tst-mutexpi4.c b/nptl/tst-mutexpi4.c new file mode 100644 index 0000000000..177b17b475 --- /dev/null +++ b/nptl/tst-mutexpi4.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex4.c" diff --git a/nptl/tst-mutexpi5.c b/nptl/tst-mutexpi5.c new file mode 100644 index 0000000000..287465c23f --- /dev/null +++ b/nptl/tst-mutexpi5.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex5.c" diff --git a/nptl/tst-mutexpi5a.c b/nptl/tst-mutexpi5a.c new file mode 100644 index 0000000000..2f85c94ff3 --- /dev/null +++ b/nptl/tst-mutexpi5a.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex5a.c" diff --git a/nptl/tst-mutexpi6.c b/nptl/tst-mutexpi6.c new file mode 100644 index 0000000000..42cda377d1 --- /dev/null +++ b/nptl/tst-mutexpi6.c @@ -0,0 +1,27 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutexattr_t a; + +static void +prepare (void) +{ + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("mutexattr_setprotocol failed"); + exit (1); + } +} +#define PREPARE(argc, argv) prepare () + + +#define ATTR &a +#include "tst-mutex6.c" diff --git a/nptl/tst-mutexpi7.c b/nptl/tst-mutexpi7.c new file mode 100644 index 0000000000..1e7e929380 --- /dev/null +++ b/nptl/tst-mutexpi7.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex7.c" diff --git a/nptl/tst-mutexpi7a.c b/nptl/tst-mutexpi7a.c new file mode 100644 index 0000000000..c59083cf6e --- /dev/null +++ b/nptl/tst-mutexpi7a.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex7a.c" diff --git a/nptl/tst-mutexpi8.c b/nptl/tst-mutexpi8.c new file mode 100644 index 0000000000..cea60309a8 --- /dev/null +++ b/nptl/tst-mutexpi8.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex8.c" diff --git a/nptl/tst-mutexpi9.c b/nptl/tst-mutexpi9.c new file mode 100644 index 0000000000..3710d9e080 --- /dev/null +++ b/nptl/tst-mutexpi9.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-mutex9.c" diff --git a/nptl/tst-robust1.c b/nptl/tst-robust1.c index 9806ca467a..bc48700e4a 100644 --- a/nptl/tst-robust1.c +++ b/nptl/tst-robust1.c @@ -97,6 +97,30 @@ do_test (void) puts ("mutexattr_setrobust failed"); return 1; } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } + else + { + int e = pthread_mutex_init (&m1, &a); + if (e == ENOTSUP) + { + puts ("PI robust mutexes not supported"); + return 0; + } + else if (e != 0) + { + puts ("mutex_init m1 failed"); + return 1; + } + pthread_mutex_destroy (&m1); + } +#endif + #ifndef NOT_CONSISTENT if (pthread_mutex_init (&m1, &a) != 0) { @@ -236,14 +260,14 @@ do_test (void) e = pthread_mutex_unlock (&m1); if (e != 0) { - printf ("%ld: mutex_unlock m1 failed\n", round); + printf ("%ld: mutex_unlock m1 failed with %d\n", round, e); return 1; } e = pthread_mutex_unlock (&m2); if (e != 0) { - printf ("%ld: mutex_unlock m2 failed\n", round); + printf ("%ld: mutex_unlock m2 failed with %d\n", round, e); return 1; } diff --git a/nptl/tst-robust7.c b/nptl/tst-robust7.c index 2c5acb44ce..d0bc91cc8e 100644 --- a/nptl/tst-robust7.c +++ b/nptl/tst-robust7.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2005. @@ -95,8 +95,25 @@ do_test (void) return 1; } - if (pthread_mutex_init (&m, &a) != 0) +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + int e; + e = pthread_mutex_init (&m, &a); + if (e != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI robust mutexes not supported"); + return 0; + } +#endif puts ("mutex_init failed"); return 1; } @@ -123,7 +140,7 @@ do_test (void) return 1; } - int e = pthread_barrier_wait (&b); + e = pthread_barrier_wait (&b); if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) { printf ("parent: barrier_wait failed in round %ld\n", n + 1); @@ -164,7 +181,7 @@ do_test (void) } } - int e = pthread_mutex_lock (&m); + e = pthread_mutex_lock (&m); if (e == 0) { puts ("parent: 2nd mutex_lock succeeded"); diff --git a/nptl/tst-robust8.c b/nptl/tst-robust8.c index 19682e594f..9c636250d4 100644 --- a/nptl/tst-robust8.c +++ b/nptl/tst-robust8.c @@ -15,7 +15,7 @@ static void prepare (void); #define PREPARE(argc, argv) prepare () static int do_test (void); #define TEST_FUNCTION do_test () -#define TIMEOUT 3 +#define TIMEOUT 5 #include "../test-skeleton.c" @@ -173,6 +173,13 @@ do_test (void) puts ("mutexattr_setpshared failed"); return 1; } +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif for (int round = 1; round <= ROUNDS; ++round) { @@ -181,7 +188,11 @@ do_test (void) int e = pthread_mutex_init (&map[n], &ma); if (e == ENOTSUP) { +#ifdef ENABLE_PI + puts ("cannot support pshared robust PI mutexes"); +#else puts ("cannot support pshared robust mutexes"); +#endif return 0; } if (e != 0) diff --git a/nptl/tst-robustpi1.c b/nptl/tst-robustpi1.c new file mode 100644 index 0000000000..031291b296 --- /dev/null +++ b/nptl/tst-robustpi1.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust1.c" diff --git a/nptl/tst-robustpi2.c b/nptl/tst-robustpi2.c new file mode 100644 index 0000000000..ac411c7736 --- /dev/null +++ b/nptl/tst-robustpi2.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust2.c" diff --git a/nptl/tst-robustpi3.c b/nptl/tst-robustpi3.c new file mode 100644 index 0000000000..7dcf691e82 --- /dev/null +++ b/nptl/tst-robustpi3.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust3.c" diff --git a/nptl/tst-robustpi4.c b/nptl/tst-robustpi4.c new file mode 100644 index 0000000000..6c7b0aa7be --- /dev/null +++ b/nptl/tst-robustpi4.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust4.c" diff --git a/nptl/tst-robustpi5.c b/nptl/tst-robustpi5.c new file mode 100644 index 0000000000..a494c332f1 --- /dev/null +++ b/nptl/tst-robustpi5.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust5.c" diff --git a/nptl/tst-robustpi6.c b/nptl/tst-robustpi6.c new file mode 100644 index 0000000000..3b1482fc22 --- /dev/null +++ b/nptl/tst-robustpi6.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust6.c" diff --git a/nptl/tst-robustpi7.c b/nptl/tst-robustpi7.c new file mode 100644 index 0000000000..f8892f3521 --- /dev/null +++ b/nptl/tst-robustpi7.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust7.c" diff --git a/nptl/tst-robustpi8.c b/nptl/tst-robustpi8.c new file mode 100644 index 0000000000..cbea3d6d77 --- /dev/null +++ b/nptl/tst-robustpi8.c @@ -0,0 +1,2 @@ +#define ENABLE_PI 1 +#include "tst-robust8.c" |