mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00:00
* sysdeps/powerpc/powerpc32/dl-trampoline.S (_dl_runtime_resolve):
Don't clobber caller's LRSAVE. (_dl_prof_resolve): Likewise.
This commit is contained in:
parent
107b8a922a
commit
f17efcb43e
@ -1,3 +1,9 @@
|
||||
2006-08-13 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
* sysdeps/powerpc/powerpc32/dl-trampoline.S (_dl_runtime_resolve):
|
||||
Don't clobber caller's LRSAVE.
|
||||
(_dl_prof_resolve): Likewise.
|
||||
|
||||
2006-08-14 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
[BZ #1996]
|
||||
|
@ -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]
|
||||
|
11
nptl/descr.h
11
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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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, ¶m) == -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, ¶m, sizeof (struct sched_param));
|
||||
pd->flags |= ATTR_FLAG_SCHED_SET;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
172
nptl/tpp.c
Normal file
172
nptl/tpp.c
Normal file
@ -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;
|
||||
}
|
@ -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"
|
||||
|
@ -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"
|
||||
|
45
nptl/tst-mutexpp1.c
Normal file
45
nptl/tst-mutexpp1.c
Normal file
@ -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"
|
334
nptl/tst-mutexpp10.c
Normal file
334
nptl/tst-mutexpp10.c
Normal file
@ -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"
|
45
nptl/tst-mutexpp6.c
Normal file
45
nptl/tst-mutexpp6.c
Normal file
@ -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"
|
94
nptl/tst-tpp.h
Normal file
94
nptl/tst-tpp.h
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -40,8 +40,9 @@ _dl_runtime_resolve:
|
||||
mflr r0
|
||||
# We also need to save some of the condition register fields
|
||||
stw r7,32(r1)
|
||||
stw r0,68(r1)
|
||||
cfi_offset (lr, 4)
|
||||
# Don't clobber the caller's LRSAVE, it is needed by _mcount.
|
||||
stw r0,48(r1)
|
||||
cfi_offset (lr, -16)
|
||||
stw r8,36(r1)
|
||||
mfcr r0
|
||||
stw r9,40(r1)
|
||||
@ -51,7 +52,7 @@ _dl_runtime_resolve:
|
||||
# 'fixup' returns the address we want to branch to.
|
||||
mtctr r3
|
||||
# Put the registers back...
|
||||
lwz r0,68(r1)
|
||||
lwz r0,48(r1)
|
||||
lwz r10,44(r1)
|
||||
lwz r9,40(r1)
|
||||
mtlr r0
|
||||
@ -128,8 +129,9 @@ _dl_prof_resolve:
|
||||
mflr r5
|
||||
# We also need to save some of the condition register fields.
|
||||
stw r7,32(r1)
|
||||
stw r5,324(r1)
|
||||
cfi_offset (lr, 4)
|
||||
# Don't clobber the caller's LRSAVE, it is needed by _mcount.
|
||||
stw r5,308(r1)
|
||||
cfi_offset (lr, -12)
|
||||
stw r8,36(r1)
|
||||
mfcr r0
|
||||
stw r9,40(r1)
|
||||
@ -154,7 +156,7 @@ _dl_prof_resolve:
|
||||
# 'fixup' returns the address we want to branch to.
|
||||
mtctr r3
|
||||
# Put the registers back...
|
||||
lwz r0,324(r1)
|
||||
lwz r0,308(r1)
|
||||
lwz r10,44(r1)
|
||||
lwz r9,40(r1)
|
||||
mtlr r0
|
||||
|
Loading…
Reference in New Issue
Block a user