summaryrefslogtreecommitdiff
path: root/nptl
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2006-08-14 23:11:18 +0000
committerUlrich Drepper <drepper@redhat.com>2006-08-14 23:11:18 +0000
commitf17efcb43e500d4af62b71bd6f286af831069b5a (patch)
treebf062a11f158b5bc8e33e42cc85e625751bacf94 /nptl
parent107b8a922a9f72bae8d066549c675062bee0897f (diff)
downloadglibc-f17efcb43e500d4af62b71bd6f286af831069b5a.tar.gz
* sysdeps/powerpc/powerpc32/dl-trampoline.S (_dl_runtime_resolve):
Don't clobber caller's LRSAVE. (_dl_prof_resolve): Likewise.
Diffstat (limited to 'nptl')
-rw-r--r--nptl/ChangeLog39
-rw-r--r--nptl/descr.h11
-rw-r--r--nptl/pthreadP.h32
-rw-r--r--nptl/pthread_create.c9
-rw-r--r--nptl/pthread_mutex_getprioceiling.c7
-rw-r--r--nptl/pthread_mutex_init.c27
-rw-r--r--nptl/pthread_mutex_lock.c84
-rw-r--r--nptl/pthread_mutex_setprioceiling.c81
-rw-r--r--nptl/pthread_mutex_timedlock.c113
-rw-r--r--nptl/pthread_mutex_trylock.c73
-rw-r--r--nptl/pthread_mutex_unlock.c43
-rw-r--r--nptl/pthread_mutexattr_getprioceiling.c15
-rw-r--r--nptl/pthread_mutexattr_setprioceiling.c10
-rw-r--r--nptl/pthread_setschedparam.c17
-rw-r--r--nptl/pthread_setschedprio.c6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h7
-rw-r--r--nptl/tpp.c172
-rw-r--r--nptl/tst-mutex1.c4
-rw-r--r--nptl/tst-mutex6.c4
-rw-r--r--nptl/tst-mutexpp1.c45
-rw-r--r--nptl/tst-mutexpp10.c334
-rw-r--r--nptl/tst-mutexpp6.c45
-rw-r--r--nptl/tst-tpp.h94
23 files changed, 1235 insertions, 37 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 8e156c5299..4b5b094091 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,42 @@
+2006-08-14 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/bits/posix_opt.h
+ (_POSIX_THREAD_PRIO_PROTECT): Define to 200112L.
+ * descr.h (struct priority_protection_data): New type.
+ (struct pthread): Add tpp field.
+ * pthreadP.h (PTHREAD_MUTEX_PP_NORMAL_NP,
+ PTHREAD_MUTEX_PP_RECURSIVE_NP, PTHREAD_MUTEX_PP_ERRORCHECK_NP,
+ PTHREAD_MUTEX_PP_ADAPTIVE_NP): New enum values.
+ * pthread_mutex_init.c (__pthread_mutex_init): Handle non-robust
+ TPP mutexes.
+ * pthread_mutex_lock.c (__pthread_mutex_lock): Handle TPP mutexes.
+ * pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise.
+ * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise.
+ * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Likewise.
+ * tpp.c: New file.
+ * pthread_setschedparam.c (__pthread_setschedparam): Handle priority
+ boosted by TPP.
+ * pthread_setschedprio.c (pthread_setschedprio): Likewise.
+ * pthread_mutexattr_getprioceiling.c
+ (pthread_mutexattr_getprioceiling): If ceiling is 0, ensure it is
+ in the SCHED_FIFO priority range.
+ * pthread_mutexattr_setprioceiling.c
+ (pthread_mutexattr_setprioceiling): Fix prioceiling validation.
+ * pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling): Fail
+ if mutex is not TPP. Ceiling is now in __data.__lock.
+ * pthread_mutex_setprioceiling.c: Include stdbool.h.
+ (pthread_mutex_setprioceiling): Fix prioceiling validation. Ceiling
+ is now in __data.__lock. Add locking.
+ * pthread_create.c (__free_tcb): Free pd->tpp structure.
+ * Makefile (libpthread-routines): Add tpp.
+ (xtests): Add tst-mutexpp1, tst-mutexpp6 and tst-mutexpp10.
+ * tst-tpp.h: New file.
+ * tst-mutexpp1.c: New file.
+ * tst-mutexpp6.c: New file.
+ * tst-mutexpp10.c: New file.
+ * tst-mutex1.c (TEST_FUNCTION): Don't redefine if already defined.
+ * tst-mutex6.c (TEST_FUNCTION): Likewise.
+
2006-08-12 Ulrich Drepper <drepper@redhat.com>
[BZ #2843]
diff --git a/nptl/descr.h b/nptl/descr.h
index 607aa9fcdb..7acd2f4f22 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -111,6 +111,14 @@ struct robust_list_head
};
+/* Data strcture used to handle thread priority protection. */
+struct priority_protection_data
+{
+ int priomax;
+ unsigned int priomap[];
+};
+
+
/* Thread descriptor data structure. */
struct pthread
{
@@ -343,6 +351,9 @@ struct pthread
/* This is what the user specified and what we will report. */
size_t reported_guardsize;
+ /* Thread Priority Protection data. */
+ struct priority_protection_data *tpp;
+
/* Resolver state. */
struct __res_state res;
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index dc98bb19c0..503e99b2b4 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -86,17 +86,31 @@ enum
= 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
+ PTHREAD_MUTEX_PRIO_PROTECT_NP = 64,
+ PTHREAD_MUTEX_PP_NORMAL_NP
+ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_NORMAL,
+ PTHREAD_MUTEX_PP_RECURSIVE_NP
+ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_PP_ERRORCHECK_NP
+ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_PP_ADAPTIVE_NP
+ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ADAPTIVE_NP
};
-#define PTHREAD_MUTEX_PRIO_CEILING_SHIFT 16
-#define PTHREAD_MUTEX_PRIO_CEILING_MASK 0x00ff0000
+
+/* Ceiling in __data.__lock. __data.__lock is signed, so don't
+ use the MSB bit in there, but in the mask also include that bit,
+ so that the compiler can optimize & PTHREAD_MUTEX_PRIO_CEILING_MASK
+ masking if the value is then shifted down by
+ PTHREAD_MUTEX_PRIO_CEILING_SHIFT. */
+#define PTHREAD_MUTEX_PRIO_CEILING_SHIFT 19
+#define PTHREAD_MUTEX_PRIO_CEILING_MASK 0xfff80000
/* Flags in mutex attr. */
#define PTHREAD_MUTEXATTR_PROTOCOL_SHIFT 28
#define PTHREAD_MUTEXATTR_PROTOCOL_MASK 0x30000000
-#define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT 16
-#define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK 0x00ff0000
+#define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT 12
+#define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK 0x00fff000
#define PTHREAD_MUTEXATTR_FLAG_ROBUST 0x40000000
#define PTHREAD_MUTEXATTR_FLAG_PSHARED 0x80000000
#define PTHREAD_MUTEXATTR_FLAG_BITS \
@@ -151,6 +165,14 @@ extern unsigned int __nptl_nthreads attribute_hidden;
extern int __set_robust_list_avail attribute_hidden;
#endif
+/* Thread Priority Protection. */
+extern int __sched_fifo_min_prio attribute_hidden;
+extern int __sched_fifo_max_prio attribute_hidden;
+extern void __init_sched_fifo_prio (void) attribute_hidden;
+extern int __pthread_tpp_change_priority (int prev_prio, int new_prio)
+ attribute_hidden;
+extern int __pthread_current_priority (void) attribute_hidden;
+
/* The library can run in debugging mode where it performs a lot more
tests. */
extern int __pthread_debug attribute_hidden;
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index c1ac199bb9..315722643b 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -206,6 +206,15 @@ __free_tcb (struct pthread *pd)
running thread is gone. */
abort ();
+ /* Free TPP data. */
+ if (__builtin_expect (pd->tpp != NULL, 0))
+ {
+ struct priority_protection_data *tpp = pd->tpp;
+
+ pd->tpp = NULL;
+ free (tpp);
+ }
+
/* Queue the stack memory block for reuse and exit the process. The
kernel will signal via writing to the address returned by
QUEUE-STACK when the stack is available. */
diff --git a/nptl/pthread_mutex_getprioceiling.c b/nptl/pthread_mutex_getprioceiling.c
index 4d1bc28431..1ce5eaebef 100644
--- a/nptl/pthread_mutex_getprioceiling.c
+++ b/nptl/pthread_mutex_getprioceiling.c
@@ -18,6 +18,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <errno.h>
#include <pthreadP.h>
@@ -26,7 +27,11 @@ pthread_mutex_getprioceiling (mutex, prioceiling)
const pthread_mutex_t *mutex;
int *prioceiling;
{
- *prioceiling = (mutex->__data.__kind & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+ if (__builtin_expect ((mutex->__data.__kind
+ & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0))
+ return EINVAL;
+
+ *prioceiling = (mutex->__data.__lock & PTHREAD_MUTEX_PRIO_CEILING_MASK)
>> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
return 0;
diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c
index 6ceca86052..96f1fb00f8 100644
--- a/nptl/pthread_mutex_init.c
+++ b/nptl/pthread_mutex_init.c
@@ -46,7 +46,6 @@ __pthread_mutex_init (mutex, mutexattr)
imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
/* Sanity checks. */
- // XXX For now we don't support priority protected mutexes.
switch (__builtin_expect (imutexattr->mutexkind
& PTHREAD_MUTEXATTR_PROTOCOL_MASK,
PTHREAD_PRIO_NONE
@@ -72,7 +71,10 @@ __pthread_mutex_init (mutex, mutexattr)
break;
default:
- return ENOTSUP;
+ /* XXX: For now we don't support robust priority protected mutexes. */
+ if (imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST)
+ return ENOTSUP;
+ break;
}
/* Clear the whole variable. */
@@ -100,15 +102,18 @@ __pthread_mutex_init (mutex, mutexattr)
case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
- if (PTHREAD_MUTEX_PRIO_CEILING_MASK
- == PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
- mutex->__data.__kind |= (imutexattr->mutexkind
- & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK);
- else
- mutex->__data.__kind |= ((imutexattr->mutexkind
- & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
- >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT)
- << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+ int ceiling = (imutexattr->mutexkind
+ & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
+ >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT;
+ if (! ceiling)
+ {
+ if (__sched_fifo_min_prio == -1)
+ __init_sched_fifo_prio ();
+ if (ceiling < __sched_fifo_min_prio)
+ ceiling = __sched_fifo_min_prio;
+ }
+ mutex->__data.__lock = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
break;
default:
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
index a19c907695..52cc47f4cc 100644
--- a/nptl/pthread_mutex_lock.c
+++ b/nptl/pthread_mutex_lock.c
@@ -335,6 +335,90 @@ __pthread_mutex_lock (mutex)
}
break;
+ case PTHREAD_MUTEX_PP_RECURSIVE_NP:
+ case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
+ case PTHREAD_MUTEX_PP_NORMAL_NP:
+ case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
+ {
+ int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+
+ oldval = mutex->__data.__lock;
+
+ /* Check whether we already hold the mutex. */
+ if (mutex->__data.__owner == id)
+ {
+ if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+ return EDEADLK;
+
+ if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+ {
+ /* 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 oldprio = -1, ceilval;
+ do
+ {
+ int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+ >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+ if (__pthread_current_priority () > ceiling)
+ {
+ if (oldprio != -1)
+ __pthread_tpp_change_priority (oldprio, -1);
+ return EINVAL;
+ }
+
+ retval = __pthread_tpp_change_priority (oldprio, ceiling);
+ if (retval)
+ return retval;
+
+ ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+ oldprio = ceiling;
+
+ oldval
+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+#ifdef NO_INCR
+ ceilval | 2,
+#else
+ ceilval | 1,
+#endif
+ ceilval);
+
+ if (oldval == ceilval)
+ break;
+
+ do
+ {
+ oldval
+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ ceilval | 2,
+ ceilval | 1);
+
+ if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
+ break;
+
+ if (oldval != ceilval)
+ lll_futex_wait (&mutex->__data.__lock, ceilval | 2);
+ }
+ while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ ceilval | 2, ceilval)
+ != ceilval);
+ }
+ while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
+
+ assert (mutex->__data.__owner == 0);
+ mutex->__data.__count = 1;
+ }
+ 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 3271f8833a..cd13d1c14c 100644
--- a/nptl/pthread_mutex_setprioceiling.c
+++ b/nptl/pthread_mutex_setprioceiling.c
@@ -18,6 +18,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <stdbool.h>
#include <errno.h>
#include <pthreadP.h>
@@ -33,23 +34,83 @@ pthread_mutex_setprioceiling (mutex, prioceiling, old_ceiling)
if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
return EINVAL;
- if (prioceiling < 0 || __builtin_expect (prioceiling > 255, 0))
+ if (__sched_fifo_min_prio == -1)
+ __init_sched_fifo_prio ();
+
+ if (__builtin_expect (prioceiling < __sched_fifo_min_prio, 0)
+ || __builtin_expect (prioceiling > __sched_fifo_max_prio, 0)
+ || __builtin_expect ((prioceiling
+ & (PTHREAD_MUTEXATTR_PRIO_CEILING_MASK
+ >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT))
+ != prioceiling, 0))
return EINVAL;
- /* XXX This needs to lock with TID, but shouldn't obey priority protect
- protocol. */
- /* lll_xxx_mutex_lock (mutex->__data.__lock); */
+ /* Check whether we already hold the mutex. */
+ bool locked = false;
+ if (mutex->__data.__owner == THREAD_GETMEM (THREAD_SELF, tid))
+ {
+ if (mutex->__data.__kind == PTHREAD_MUTEX_PP_ERRORCHECK_NP)
+ return EDEADLK;
+
+ if (mutex->__data.__kind == PTHREAD_MUTEX_PP_RECURSIVE_NP)
+ locked = true;
+ }
+
+ int oldval = mutex->__data.__lock;
+ if (! locked)
+ do
+ {
+ /* Need to lock the mutex, but without obeying the priority
+ protect protocol. */
+ int ceilval = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK);
+
+ oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ ceilval | 1, ceilval);
+ if (oldval == ceilval)
+ break;
+
+ do
+ {
+ oldval
+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ ceilval | 2,
+ ceilval | 1);
+
+ if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
+ break;
+
+ if (oldval != ceilval)
+ lll_futex_wait (&mutex->__data.__lock, ceilval | 2);
+ }
+ while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ ceilval | 2, ceilval)
+ != ceilval);
+
+ if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
+ continue;
+ }
+ while (0);
+
+ int oldprio = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+ >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+ if (locked)
+ {
+ int ret = __pthread_tpp_change_priority (oldprio, prioceiling);
+ if (ret)
+ return ret;
+ }
if (old_ceiling != NULL)
- *old_ceiling = (mutex->__data.__kind & PTHREAD_MUTEX_PRIO_CEILING_MASK)
- >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+ *old_ceiling = oldprio;
- int newkind = (mutex->__data.__kind & ~PTHREAD_MUTEX_PRIO_CEILING_MASK);
- mutex->__data.__kind = newkind
+ int newlock = 0;
+ if (locked)
+ newlock = (mutex->__data.__lock & ~PTHREAD_MUTEX_PRIO_CEILING_MASK);
+ mutex->__data.__lock = newlock
| (prioceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT);
+ atomic_full_barrier ();
- /* XXX This needs to unlock the above special kind of lock. */
- /* lll_xxx_mutex_unlock (mutex->__data.__lock); */
+ lll_futex_wake (&mutex->__data.__lock, INT_MAX);
return 0;
}
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index dcff4f81a8..c8e6b8507a 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -340,6 +340,119 @@ pthread_mutex_timedlock (mutex, abstime)
}
break;
+ case PTHREAD_MUTEX_PP_RECURSIVE_NP:
+ case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
+ case PTHREAD_MUTEX_PP_NORMAL_NP:
+ case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
+ {
+ int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+
+ oldval = mutex->__data.__lock;
+
+ /* Check whether we already hold the mutex. */
+ if (mutex->__data.__owner == id)
+ {
+ if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+ return EDEADLK;
+
+ if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+ {
+ /* 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 oldprio = -1, ceilval;
+ do
+ {
+ int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+ >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+ if (__pthread_current_priority () > ceiling)
+ {
+ result = EINVAL;
+ failpp:
+ if (oldprio != -1)
+ __pthread_tpp_change_priority (oldprio, -1);
+ return result;
+ }
+
+ result = __pthread_tpp_change_priority (oldprio, ceiling);
+ if (result)
+ return result;
+
+ ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+ oldprio = ceiling;
+
+ oldval
+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ ceilval | 1, ceilval);
+
+ if (oldval == ceilval)
+ break;
+
+ do
+ {
+ oldval
+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ ceilval | 2,
+ ceilval | 1);
+
+ if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
+ break;
+
+ if (oldval != ceilval)
+ {
+ /* Reject invalid timeouts. */
+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+ {
+ result = EINVAL;
+ goto failpp;
+ }
+
+ struct timeval tv;
+ struct timespec rt;
+
+ /* Get the current time. */
+ (void) __gettimeofday (&tv, NULL);
+
+ /* Compute relative timeout. */
+ rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+ rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+ if (rt.tv_nsec < 0)
+ {
+ rt.tv_nsec += 1000000000;
+ --rt.tv_sec;
+ }
+
+ /* Already timed out? */
+ if (rt.tv_sec < 0)
+ {
+ result = ETIMEDOUT;
+ goto failpp;
+ }
+
+ lll_futex_timed_wait (&mutex->__data.__lock,
+ ceilval | 2, &rt);
+ }
+ }
+ while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ ceilval | 2, ceilval)
+ != ceilval);
+ }
+ while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
+
+ assert (mutex->__data.__owner == 0);
+ mutex->__data.__count = 1;
+ }
+ 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 f3a18569a1..94d519233b 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -297,6 +297,79 @@ __pthread_mutex_trylock (mutex)
return 0;
}
+ case PTHREAD_MUTEX_PP_RECURSIVE_NP:
+ case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
+ case PTHREAD_MUTEX_PP_NORMAL_NP:
+ case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
+ {
+ int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+
+ oldval = mutex->__data.__lock;
+
+ /* Check whether we already hold the mutex. */
+ if (mutex->__data.__owner == id)
+ {
+ if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+ return EDEADLK;
+
+ if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+ {
+ /* 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 oldprio = -1, ceilval;
+ do
+ {
+ int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+ >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+
+ if (__pthread_current_priority () > ceiling)
+ {
+ if (oldprio != -1)
+ __pthread_tpp_change_priority (oldprio, -1);
+ return EINVAL;
+ }
+
+ int retval = __pthread_tpp_change_priority (oldprio, ceiling);
+ if (retval)
+ return retval;
+
+ ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+ oldprio = ceiling;
+
+ oldval
+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ ceilval | 1, ceilval);
+
+ if (oldval == ceilval)
+ break;
+ }
+ while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
+
+ if (oldval != ceilval)
+ {
+ __pthread_tpp_change_priority (oldprio, -1);
+ break;
+ }
+
+ assert (mutex->__data.__owner == 0);
+ /* Record the ownership. */
+ mutex->__data.__owner = id;
+ ++mutex->__data.__nusers;
+ mutex->__data.__count = 1;
+
+ return 0;
+ }
+ break;
+
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 2b5064fbac..33919d60af 100644
--- a/nptl/pthread_mutex_unlock.c
+++ b/nptl/pthread_mutex_unlock.c
@@ -202,6 +202,49 @@ __pthread_mutex_unlock_usercnt (mutex, decr)
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
break;
+ case PTHREAD_MUTEX_PP_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 pp;
+
+ case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
+ /* Error checking mutex. */
+ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
+ || (mutex->__data.__lock & ~ PTHREAD_MUTEX_PRIO_CEILING_MASK) == 0)
+ return EPERM;
+ /* FALLTHROUGH */
+
+ case PTHREAD_MUTEX_PP_NORMAL_NP:
+ case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
+ /* Always reset the owner field. */
+ pp:
+ mutex->__data.__owner = 0;
+
+ if (decr)
+ /* One less user. */
+ --mutex->__data.__nusers;
+
+ /* Unlock. */
+ int newval, oldval;
+ do
+ {
+ oldval = mutex->__data.__lock;
+ newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK;
+ }
+ while (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock,
+ newval, oldval));
+
+ if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1)
+ lll_futex_wake (&mutex->__data.__lock, 1);
+
+ int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
+ return __pthread_tpp_change_priority (oldprio, -1);
+
default:
/* Correct code cannot set any other type. */
return EINVAL;
diff --git a/nptl/pthread_mutexattr_getprioceiling.c b/nptl/pthread_mutexattr_getprioceiling.c
index da1beabf46..792e9a43d6 100644
--- a/nptl/pthread_mutexattr_getprioceiling.c
+++ b/nptl/pthread_mutexattr_getprioceiling.c
@@ -27,11 +27,22 @@ pthread_mutexattr_getprioceiling (attr, prioceiling)
int *prioceiling;
{
const struct pthread_mutexattr *iattr;
+ int ceiling;
iattr = (const struct pthread_mutexattr *) attr;
- *prioceiling = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
- >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT);
+ ceiling = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
+ >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT);
+
+ if (! ceiling)
+ {
+ if (__sched_fifo_min_prio == -1)
+ __init_sched_fifo_prio ();
+ if (ceiling < __sched_fifo_min_prio)
+ ceiling = __sched_fifo_min_prio;
+ }
+
+ *prioceiling = ceiling;
return 0;
}
diff --git a/nptl/pthread_mutexattr_setprioceiling.c b/nptl/pthread_mutexattr_setprioceiling.c
index 6c15b46833..9b7874f739 100644
--- a/nptl/pthread_mutexattr_setprioceiling.c
+++ b/nptl/pthread_mutexattr_setprioceiling.c
@@ -27,7 +27,15 @@ pthread_mutexattr_setprioceiling (attr, prioceiling)
pthread_mutexattr_t *attr;
int prioceiling;
{
- if (prioceiling < 0 || __builtin_expect (prioceiling > 255, 0))
+ if (__sched_fifo_min_prio == -1)
+ __init_sched_fifo_prio ();
+
+ if (__builtin_expect (prioceiling < __sched_fifo_min_prio, 0)
+ || __builtin_expect (prioceiling > __sched_fifo_max_prio, 0)
+ || __builtin_expect ((prioceiling
+ & (PTHREAD_MUTEXATTR_PRIO_CEILING_MASK
+ >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT))
+ != prioceiling, 0))
return EINVAL;
struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr;
diff --git a/nptl/pthread_setschedparam.c b/nptl/pthread_setschedparam.c
index 5889cc98a9..30ac6b3e89 100644
--- a/nptl/pthread_setschedparam.c
+++ b/nptl/pthread_setschedparam.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.
@@ -45,6 +45,19 @@ __pthread_setschedparam (threadid, policy, param)
lll_lock (pd->lock);
+ struct sched_param p;
+ const struct sched_param *orig_param = param;
+
+ /* If the thread should have higher priority because of some
+ PTHREAD_PRIO_PROTECT mutexes it holds, adjust the priority. */
+ if (__builtin_expect (pd->tpp != NULL, 0)
+ && pd->tpp->priomax > param->sched_priority)
+ {
+ p = *param;
+ p.sched_priority = pd->tpp->priomax;
+ param = &p;
+ }
+
/* Try to set the scheduler information. */
if (__builtin_expect (__sched_setscheduler (pd->tid, policy,
param) == -1, 0))
@@ -54,7 +67,7 @@ __pthread_setschedparam (threadid, policy, param)
/* We succeeded changing the kernel information. Reflect this
change in the thread descriptor. */
pd->schedpolicy = policy;
- memcpy (&pd->schedparam, param, sizeof (struct sched_param));
+ memcpy (&pd->schedparam, orig_param, sizeof (struct sched_param));
pd->flags |= ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET;
}
diff --git a/nptl/pthread_setschedprio.c b/nptl/pthread_setschedprio.c
index 063f5232f5..4a71f6c7b3 100644
--- a/nptl/pthread_setschedprio.c
+++ b/nptl/pthread_setschedprio.c
@@ -47,6 +47,11 @@ pthread_setschedprio (threadid, prio)
lll_lock (pd->lock);
+ /* If the thread should have higher priority because of some
+ PTHREAD_PRIO_PROTECT mutexes it holds, adjust the priority. */
+ if (__builtin_expect (pd->tpp != NULL, 0) && pd->tpp->priomax > prio)
+ param.sched_priority = pd->tpp->priomax;
+
/* Try to set the scheduler information. */
if (__builtin_expect (sched_setparam (pd->tid, &param) == -1, 0))
result = errno;
@@ -54,6 +59,7 @@ pthread_setschedprio (threadid, prio)
{
/* We succeeded changing the kernel information. Reflect this
change in the thread descriptor. */
+ param.sched_priority = prio;
memcpy (&pd->schedparam, &param, sizeof (struct sched_param));
pd->flags |= ATTR_FLAG_SCHED_SET;
}
diff --git a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
index d8eced1f22..40160c54de 100644
--- a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
+++ b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
@@ -82,6 +82,10 @@
/* We support priority inheritence. */
#define _POSIX_THREAD_PRIO_INHERIT 200112L
+/* We support priority protection, though only for non-robust
+ mutexes. */
+#define _POSIX_THREAD_PRIO_PROTECT 200112L
+
/* We support POSIX.1b semaphores. */
#define _POSIX_SEMAPHORES 200112L
@@ -174,7 +178,4 @@
/* Typed memory objects are not available. */
#define _POSIX_TYPED_MEMORY_OBJECTS -1
-/* No support for priority protection so far. */
-#define _POSIX_THREAD_PRIO_PROTECT -1
-
#endif /* posix_opt.h */
diff --git a/nptl/tpp.c b/nptl/tpp.c
new file mode 100644
index 0000000000..367dd8162a
--- /dev/null
+++ b/nptl/tpp.c
@@ -0,0 +1,172 @@
+/* Thread Priority Protect helpers.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <assert.h>
+#include <atomic.h>
+#include <errno.h>
+#include <pthreadP.h>
+#include <sched.h>
+#include <stdlib.h>
+
+
+int __sched_fifo_min_prio = -1;
+int __sched_fifo_max_prio = -1;
+
+void
+__init_sched_fifo_prio (void)
+{
+ __sched_fifo_max_prio = sched_get_priority_max (SCHED_FIFO);
+ atomic_write_barrier ();
+ __sched_fifo_min_prio = sched_get_priority_min (SCHED_FIFO);
+}
+
+int
+__pthread_tpp_change_priority (int previous_prio, int new_prio)
+{
+ struct pthread *self = THREAD_SELF;
+ struct priority_protection_data *tpp = THREAD_GETMEM (self, tpp);
+
+ if (tpp == NULL)
+ {
+ if (__sched_fifo_min_prio == -1)
+ __init_sched_fifo_prio ();
+
+ size_t size = sizeof *tpp;
+ size += (__sched_fifo_max_prio - __sched_fifo_min_prio + 1)
+ * sizeof (tpp->priomap[0]);
+ tpp = calloc (size, 1);
+ if (tpp == NULL)
+ return ENOMEM;
+ tpp->priomax = __sched_fifo_min_prio - 1;
+ THREAD_SETMEM (self, tpp, tpp);
+ }
+
+ assert (new_prio == -1
+ || (new_prio >= __sched_fifo_min_prio
+ && new_prio <= __sched_fifo_max_prio));
+ assert (previous_prio == -1
+ || (previous_prio >= __sched_fifo_min_prio
+ && previous_prio <= __sched_fifo_max_prio));
+
+ int priomax = tpp->priomax;
+ int newpriomax = priomax;
+ if (new_prio != -1)
+ {
+ if (tpp->priomap[new_prio - __sched_fifo_min_prio] + 1 == 0)
+ return EAGAIN;
+ ++tpp->priomap[new_prio - __sched_fifo_min_prio];
+ if (new_prio > priomax)
+ newpriomax = new_prio;
+ }
+
+ if (previous_prio != -1)
+ {
+ if (--tpp->priomap[previous_prio - __sched_fifo_min_prio] == 0
+ && priomax == previous_prio
+ && previous_prio > new_prio)
+ {
+ int i;
+ for (i = previous_prio - 1; i >= __sched_fifo_min_prio; --i)
+ if (tpp->priomap[i - __sched_fifo_min_prio])
+ break;
+ newpriomax = i;
+ }
+ }
+
+ if (priomax == newpriomax)
+ return 0;
+
+ lll_lock (self->lock);
+
+ tpp->priomax = newpriomax;
+
+ int result = 0;
+
+ if ((self->flags & ATTR_FLAG_SCHED_SET) == 0)
+ {
+ if (__sched_getparam (self->tid, &self->schedparam) != 0)
+ result = errno;
+ else
+ self->flags |= ATTR_FLAG_SCHED_SET;
+ }
+
+ if ((self->flags & ATTR_FLAG_POLICY_SET) == 0)
+ {
+ self->schedpolicy = __sched_getscheduler (self->tid);
+ if (self->schedpolicy == -1)
+ result = errno;
+ else
+ self->flags |= ATTR_FLAG_POLICY_SET;
+ }
+
+ if (result == 0)
+ {
+ struct sched_param sp = self->schedparam;
+ if (sp.sched_priority < newpriomax || sp.sched_priority < priomax)
+ {
+ if (sp.sched_priority < newpriomax)
+ sp.sched_priority = newpriomax;
+
+ if (__sched_setscheduler (self->tid, self->schedpolicy, &sp) < 0)
+ result = errno;
+ }
+ }
+
+ lll_unlock (self->lock);
+
+ return result;
+}
+
+int
+__pthread_current_priority (void)
+{
+ struct pthread *self = THREAD_SELF;
+ if ((self->flags & (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET))
+ == (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET))
+ return self->schedparam.sched_priority;
+
+ int result = 0;
+
+ lll_lock (self->lock);
+
+ if ((self->flags & ATTR_FLAG_SCHED_SET) == 0)
+ {
+ if (__sched_getparam (self->tid, &self->schedparam) != 0)
+ result = -1;
+ else
+ self->flags |= ATTR_FLAG_SCHED_SET;
+ }
+
+ if ((self->flags & ATTR_FLAG_POLICY_SET) == 0)
+ {
+ self->schedpolicy = __sched_getscheduler (self->tid);
+ if (self->schedpolicy == -1)
+ result = -1;
+ else
+ self->flags |= ATTR_FLAG_POLICY_SET;
+ }
+
+ if (result != -1)
+ result = self->schedparam.sched_priority;
+
+ lll_unlock (self->lock);
+
+ return result;
+}
diff --git a/nptl/tst-mutex1.c b/nptl/tst-mutex1.c
index c3ef5b2b51..9453f04918 100644
--- a/nptl/tst-mutex1.c
+++ b/nptl/tst-mutex1.c
@@ -71,5 +71,7 @@ do_test (void)
return 0;
}
-#define TEST_FUNCTION do_test ()
+#ifndef TEST_FUNCTION
+# define TEST_FUNCTION do_test ()
+#endif
#include "../test-skeleton.c"
diff --git a/nptl/tst-mutex6.c b/nptl/tst-mutex6.c
index e5698c3eb0..de64bdb435 100644
--- a/nptl/tst-mutex6.c
+++ b/nptl/tst-mutex6.c
@@ -69,5 +69,7 @@ do_test (void)
}
#define EXPECTED_SIGNAL SIGALRM
-#define TEST_FUNCTION do_test ()
+#ifndef TEST_FUNCTION
+# define TEST_FUNCTION do_test ()
+#endif
#include "../test-skeleton.c"
diff --git a/nptl/tst-mutexpp1.c b/nptl/tst-mutexpp1.c
new file mode 100644
index 0000000000..9b7d7fe263
--- /dev/null
+++ b/nptl/tst-mutexpp1.c
@@ -0,0 +1,45 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tst-tpp.h"
+
+static pthread_mutexattr_t a;
+
+static void
+prepare (void)
+{
+ init_tpp_test ();
+
+ if (pthread_mutexattr_init (&a) != 0)
+ {
+ puts ("mutexattr_init failed");
+ exit (1);
+ }
+
+ if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_PROTECT) != 0)
+ {
+ puts ("mutexattr_setprotocol failed");
+ exit (1);
+ }
+
+ if (pthread_mutexattr_setprioceiling (&a, 6) != 0)
+ {
+ puts ("mutexattr_setprioceiling failed");
+ exit (1);
+ }
+}
+#define PREPARE(argc, argv) prepare ()
+
+static int do_test (void);
+
+static int
+do_test_wrapper (void)
+{
+ init_tpp_test ();
+ return do_test ();
+}
+#define TEST_FUNCTION do_test_wrapper ()
+
+#define ATTR &a
+#include "tst-mutex1.c"
diff --git a/nptl/tst-mutexpp10.c b/nptl/tst-mutexpp10.c
new file mode 100644
index 0000000000..78281a4d3b
--- /dev/null
+++ b/nptl/tst-mutexpp10.c
@@ -0,0 +1,334 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tst-tpp.h"
+
+static int
+do_test (void)
+{
+ int ret = 0;
+
+ init_tpp_test ();
+
+ pthread_mutexattr_t ma;
+ if (pthread_mutexattr_init (&ma))
+ {
+ puts ("mutexattr_init failed");
+ return 1;
+ }
+ if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_PROTECT))
+ {
+ puts ("mutexattr_setprotocol failed");
+ return 1;
+ }
+
+ int prioceiling;
+ if (pthread_mutexattr_getprioceiling (&ma, &prioceiling))
+ {
+ puts ("mutexattr_getprioceiling failed");
+ return 1;
+ }
+
+ if (prioceiling < fifo_min || prioceiling > fifo_max)
+ {
+ printf ("prioceiling %d not in %d..%d range\n",
+ prioceiling, fifo_min, fifo_max);
+ return 1;
+ }
+
+ if (fifo_max < INT_MAX
+ && pthread_mutexattr_setprioceiling (&ma, fifo_max + 1) != EINVAL)
+ {
+ printf ("mutexattr_setprioceiling %d did not fail with EINVAL\n",
+ fifo_max + 1);
+ return 1;
+ }
+
+ if (fifo_min > 0
+ && pthread_mutexattr_setprioceiling (&ma, fifo_min - 1) != EINVAL)
+ {
+ printf ("mutexattr_setprioceiling %d did not fail with EINVAL\n",
+ fifo_min - 1);
+ return 1;
+ }
+
+ if (pthread_mutexattr_setprioceiling (&ma, fifo_min))
+ {
+ puts ("mutexattr_setprioceiling failed");
+ return 1;
+ }
+
+ if (pthread_mutexattr_setprioceiling (&ma, fifo_max))
+ {
+ puts ("mutexattr_setprioceiling failed");
+ return 1;
+ }
+
+ if (pthread_mutexattr_setprioceiling (&ma, 6))
+ {
+ puts ("mutexattr_setprioceiling failed");
+ return 1;
+ }
+
+ if (pthread_mutexattr_getprioceiling (&ma, &prioceiling))
+ {
+ puts ("mutexattr_getprioceiling failed");
+ return 1;
+ }
+
+ if (prioceiling != 6)
+ {
+ printf ("mutexattr_getprioceiling returned %d != 6\n",
+ prioceiling);
+ return 1;
+ }
+
+ pthread_mutex_t m1, m2, m3;
+ int e = pthread_mutex_init (&m1, &ma);
+ if (e == ENOTSUP)
+ {
+ puts ("cannot support selected type of mutexes");
+ return 0;
+ }
+ else if (e != 0)
+ {
+ puts ("mutex_init failed");
+ return 1;
+ }
+
+ if (pthread_mutexattr_setprioceiling (&ma, 8))
+ {
+ puts ("mutexattr_setprioceiling failed");
+ return 1;
+ }
+
+ if (pthread_mutex_init (&m2, &ma))
+ {
+ puts ("mutex_init failed");
+ return 1;
+ }
+
+ if (pthread_mutexattr_setprioceiling (&ma, 5))
+ {
+ puts ("mutexattr_setprioceiling failed");
+ return 1;
+ }
+
+ if (pthread_mutex_init (&m3, &ma))
+ {
+ puts ("mutex_init failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 4);
+
+ if (pthread_mutex_lock (&m1) != 0)
+ {
+ puts ("mutex_lock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 6);
+
+ if (pthread_mutex_trylock (&m2) != 0)
+ {
+ puts ("mutex_lock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 8);
+
+ if (pthread_mutex_lock (&m3) != 0)
+ {
+ puts ("mutex_lock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 8);
+
+ if (pthread_mutex_unlock (&m2) != 0)
+ {
+ puts ("mutex_unlock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 6);
+
+ if (pthread_mutex_unlock (&m1) != 0)
+ {
+ puts ("mutex_unlock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 5);
+
+ if (pthread_mutex_lock (&m2) != 0)
+ {
+ puts ("mutex_lock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 8);
+
+ if (pthread_mutex_unlock (&m2) != 0)
+ {
+ puts ("mutex_unlock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 5);
+
+ if (pthread_mutex_getprioceiling (&m1, &prioceiling))
+ {
+ puts ("mutex_getprioceiling m1 failed");
+ return 1;
+ }
+ else if (prioceiling != 6)
+ {
+ printf ("unexpected m1 prioceiling %d != 6\n", prioceiling);
+ return 1;
+ }
+
+ if (pthread_mutex_getprioceiling (&m2, &prioceiling))
+ {
+ puts ("mutex_getprioceiling m2 failed");
+ return 1;
+ }
+ else if (prioceiling != 8)
+ {
+ printf ("unexpected m2 prioceiling %d != 8\n", prioceiling);
+ return 1;
+ }
+
+ if (pthread_mutex_getprioceiling (&m3, &prioceiling))
+ {
+ puts ("mutex_getprioceiling m3 failed");
+ return 1;
+ }
+ else if (prioceiling != 5)
+ {
+ printf ("unexpected m3 prioceiling %d != 5\n", prioceiling);
+ return 1;
+ }
+
+ if (pthread_mutex_setprioceiling (&m1, 7, &prioceiling))
+ {
+ printf ("mutex_setprioceiling failed");
+ return 1;
+ }
+ else if (prioceiling != 6)
+ {
+ printf ("unexpected m1 old prioceiling %d != 6\n", prioceiling);
+ return 1;
+ }
+
+ if (pthread_mutex_getprioceiling (&m1, &prioceiling))
+ {
+ puts ("mutex_getprioceiling m1 failed");
+ return 1;
+ }
+ else if (prioceiling != 7)
+ {
+ printf ("unexpected m1 prioceiling %d != 7\n", prioceiling);
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 5);
+
+ if (pthread_mutex_unlock (&m3) != 0)
+ {
+ puts ("mutex_unlock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 4);
+
+ if (pthread_mutex_trylock (&m1) != 0)
+ {
+ puts ("mutex_lock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (4, 7);
+
+ struct sched_param sp;
+ memset (&sp, 0, sizeof (sp));
+ sp.sched_priority = 8;
+ if (pthread_setschedparam (pthread_self (), SCHED_FIFO, &sp))
+ {
+ puts ("cannot set scheduling params");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (8, 8);
+
+ if (pthread_mutex_unlock (&m1) != 0)
+ {
+ puts ("mutex_unlock failed");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (8, 8);
+
+ if (pthread_mutex_lock (&m3) != EINVAL)
+ {
+ puts ("pthread_mutex_lock didn't fail with EINVAL");
+ return 1;
+ }
+
+ CHECK_TPP_PRIORITY (8, 8);
+
+ if (pthread_mutex_destroy (&m1) != 0)
+ {
+ puts ("mutex_destroy failed");
+ return 1;
+ }
+
+ if (pthread_mutex_destroy (&m2) != 0)
+ {
+ puts ("mutex_destroy failed");
+ return 1;
+ }
+
+ if (pthread_mutex_destroy (&m3) != 0)
+ {
+ puts ("mutex_destroy failed");
+ return 1;
+ }
+
+ if (pthread_mutexattr_destroy (&ma) != 0)
+ {
+ puts ("mutexattr_destroy failed");
+ return 1;
+ }
+
+ return ret;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-mutexpp6.c b/nptl/tst-mutexpp6.c
new file mode 100644
index 0000000000..2ddf6b45c6
--- /dev/null
+++ b/nptl/tst-mutexpp6.c
@@ -0,0 +1,45 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tst-tpp.h"
+
+static pthread_mutexattr_t a;
+
+static void
+prepare (void)
+{
+ init_tpp_test ();
+
+ if (pthread_mutexattr_init (&a) != 0)
+ {
+ puts ("mutexattr_init failed");
+ exit (1);
+ }
+
+ if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_PROTECT) != 0)
+ {
+ puts ("mutexattr_setprotocol failed");
+ exit (1);
+ }
+
+ if (pthread_mutexattr_setprioceiling (&a, 6) != 0)
+ {
+ puts ("mutexattr_setprioceiling failed");
+ exit (1);
+ }
+}
+#define PREPARE(argc, argv) prepare ()
+
+static int do_test (void);
+
+static int
+do_test_wrapper (void)
+{
+ init_tpp_test ();
+ return do_test ();
+}
+#define TEST_FUNCTION do_test_wrapper ()
+
+#define ATTR &a
+#include "tst-mutex6.c"
diff --git a/nptl/tst-tpp.h b/nptl/tst-tpp.h
new file mode 100644
index 0000000000..c5844b26dd
--- /dev/null
+++ b/nptl/tst-tpp.h
@@ -0,0 +1,94 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+/* This test is Linux specific. */
+#define CHECK_TPP_PRIORITY(normal, boosted) \
+ do \
+ { \
+ pid_t tid = syscall (__NR_gettid); \
+ \
+ struct sched_param cep_sp; \
+ int cep_policy; \
+ if (pthread_getschedparam (pthread_self (), &cep_policy, \
+ &cep_sp) != 0) \
+ { \
+ puts ("getschedparam failed"); \
+ ret = 1; \
+ } \
+ else if (cep_sp.sched_priority != (normal)) \
+ { \
+ printf ("unexpected priority %d != %d\n", \
+ cep_sp.sched_priority, (normal)); \
+ } \
+ if (syscall (__NR_sched_getparam, tid, &cep_sp) == 0 \
+ && cep_sp.sched_priority != (boosted)) \
+ { \
+ printf ("unexpected boosted priority %d != %d\n", \
+ cep_sp.sched_priority, (boosted)); \
+ ret = 1; \
+ } \
+ } \
+ while (0)
+
+int fifo_min, fifo_max;
+
+void
+init_tpp_test (void)
+{
+ fifo_min = sched_get_priority_min (SCHED_FIFO);
+ if (fifo_min < 0)
+ {
+ printf ("couldn't get min priority for SCHED_FIFO: %m\n");
+ exit (1);
+ }
+
+ fifo_max = sched_get_priority_max (SCHED_FIFO);
+ if (fifo_max < 0)
+ {
+ printf ("couldn't get max priority for SCHED_FIFO: %m\n");
+ exit (1);
+ }
+
+ if (fifo_min > 4 || fifo_max < 10)
+ {
+ printf ("%d..%d SCHED_FIFO priority interval not suitable for this test\n",
+ fifo_min, fifo_max);
+ exit (0);
+ }
+
+ struct sched_param sp;
+ memset (&sp, 0, sizeof (sp));
+ sp.sched_priority = 4;
+ int e = pthread_setschedparam (pthread_self (), SCHED_FIFO, &sp);
+ if (e != 0)
+ {
+ errno = e;
+ printf ("cannot set scheduling params: %m\n");
+ exit (0);
+ }
+}