1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03: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:
Ulrich Drepper
2006-08-14 23:11:18 +00:00
parent 107b8a922a
commit f17efcb43e
25 changed files with 1249 additions and 43 deletions

View File

@ -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> 2006-08-14 Ulrich Drepper <drepper@redhat.com>
[BZ #1996] [BZ #1996]

View File

@ -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> 2006-08-12 Ulrich Drepper <drepper@redhat.com>
[BZ #2843] [BZ #2843]

View File

@ -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. */ /* Thread descriptor data structure. */
struct pthread struct pthread
{ {
@ -343,6 +351,9 @@ struct pthread
/* This is what the user specified and what we will report. */ /* This is what the user specified and what we will report. */
size_t reported_guardsize; size_t reported_guardsize;
/* Thread Priority Protection data. */
struct priority_protection_data *tpp;
/* Resolver state. */ /* Resolver state. */
struct __res_state res; struct __res_state res;

View File

@ -86,17 +86,31 @@ enum
= PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP, = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP,
PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP
= PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_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. */ /* Flags in mutex attr. */
#define PTHREAD_MUTEXATTR_PROTOCOL_SHIFT 28 #define PTHREAD_MUTEXATTR_PROTOCOL_SHIFT 28
#define PTHREAD_MUTEXATTR_PROTOCOL_MASK 0x30000000 #define PTHREAD_MUTEXATTR_PROTOCOL_MASK 0x30000000
#define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT 16 #define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT 12
#define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK 0x00ff0000 #define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK 0x00fff000
#define PTHREAD_MUTEXATTR_FLAG_ROBUST 0x40000000 #define PTHREAD_MUTEXATTR_FLAG_ROBUST 0x40000000
#define PTHREAD_MUTEXATTR_FLAG_PSHARED 0x80000000 #define PTHREAD_MUTEXATTR_FLAG_PSHARED 0x80000000
#define PTHREAD_MUTEXATTR_FLAG_BITS \ #define PTHREAD_MUTEXATTR_FLAG_BITS \
@ -151,6 +165,14 @@ extern unsigned int __nptl_nthreads attribute_hidden;
extern int __set_robust_list_avail attribute_hidden; extern int __set_robust_list_avail attribute_hidden;
#endif #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 /* The library can run in debugging mode where it performs a lot more
tests. */ tests. */
extern int __pthread_debug attribute_hidden; extern int __pthread_debug attribute_hidden;

View File

@ -206,6 +206,15 @@ __free_tcb (struct pthread *pd)
running thread is gone. */ running thread is gone. */
abort (); 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 /* Queue the stack memory block for reuse and exit the process. The
kernel will signal via writing to the address returned by kernel will signal via writing to the address returned by
QUEUE-STACK when the stack is available. */ QUEUE-STACK when the stack is available. */

View File

@ -18,6 +18,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */ 02111-1307 USA. */
#include <errno.h>
#include <pthreadP.h> #include <pthreadP.h>
@ -26,7 +27,11 @@ pthread_mutex_getprioceiling (mutex, prioceiling)
const pthread_mutex_t *mutex; const pthread_mutex_t *mutex;
int *prioceiling; 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; >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
return 0; return 0;

View File

@ -46,7 +46,6 @@ __pthread_mutex_init (mutex, mutexattr)
imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr; imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
/* Sanity checks. */ /* Sanity checks. */
// XXX For now we don't support priority protected mutexes.
switch (__builtin_expect (imutexattr->mutexkind switch (__builtin_expect (imutexattr->mutexkind
& PTHREAD_MUTEXATTR_PROTOCOL_MASK, & PTHREAD_MUTEXATTR_PROTOCOL_MASK,
PTHREAD_PRIO_NONE PTHREAD_PRIO_NONE
@ -72,7 +71,10 @@ __pthread_mutex_init (mutex, mutexattr)
break; break;
default: 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. */ /* Clear the whole variable. */
@ -100,15 +102,18 @@ __pthread_mutex_init (mutex, mutexattr)
case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
if (PTHREAD_MUTEX_PRIO_CEILING_MASK
== PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) int ceiling = (imutexattr->mutexkind
mutex->__data.__kind |= (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
& PTHREAD_MUTEXATTR_PRIO_CEILING_MASK); >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT;
else if (! ceiling)
mutex->__data.__kind |= ((imutexattr->mutexkind {
& PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) if (__sched_fifo_min_prio == -1)
>> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT) __init_sched_fifo_prio ();
<< PTHREAD_MUTEX_PRIO_CEILING_SHIFT; if (ceiling < __sched_fifo_min_prio)
ceiling = __sched_fifo_min_prio;
}
mutex->__data.__lock = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
break; break;
default: default:

View File

@ -335,6 +335,90 @@ __pthread_mutex_lock (mutex)
} }
break; 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: default:
/* Correct code cannot set any other type. */ /* Correct code cannot set any other type. */
return EINVAL; return EINVAL;

View File

@ -18,6 +18,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */ 02111-1307 USA. */
#include <stdbool.h>
#include <errno.h> #include <errno.h>
#include <pthreadP.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) if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
return EINVAL; 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; return EINVAL;
/* XXX This needs to lock with TID, but shouldn't obey priority protect /* Check whether we already hold the mutex. */
protocol. */ bool locked = false;
/* lll_xxx_mutex_lock (mutex->__data.__lock); */ 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) if (old_ceiling != NULL)
*old_ceiling = (mutex->__data.__kind & PTHREAD_MUTEX_PRIO_CEILING_MASK) *old_ceiling = oldprio;
>> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
int newkind = (mutex->__data.__kind & ~PTHREAD_MUTEX_PRIO_CEILING_MASK); int newlock = 0;
mutex->__data.__kind = newkind if (locked)
newlock = (mutex->__data.__lock & ~PTHREAD_MUTEX_PRIO_CEILING_MASK);
mutex->__data.__lock = newlock
| (prioceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT); | (prioceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT);
atomic_full_barrier ();
/* XXX This needs to unlock the above special kind of lock. */ lll_futex_wake (&mutex->__data.__lock, INT_MAX);
/* lll_xxx_mutex_unlock (mutex->__data.__lock); */
return 0; return 0;
} }

View File

@ -340,6 +340,119 @@ pthread_mutex_timedlock (mutex, abstime)
} }
break; 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: default:
/* Correct code cannot set any other type. */ /* Correct code cannot set any other type. */
return EINVAL; return EINVAL;

View File

@ -297,6 +297,79 @@ __pthread_mutex_trylock (mutex)
return 0; 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: default:
/* Correct code cannot set any other type. */ /* Correct code cannot set any other type. */
return EINVAL; return EINVAL;

View File

@ -202,6 +202,49 @@ __pthread_mutex_unlock_usercnt (mutex, decr)
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
break; 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: default:
/* Correct code cannot set any other type. */ /* Correct code cannot set any other type. */
return EINVAL; return EINVAL;

View File

@ -27,11 +27,22 @@ pthread_mutexattr_getprioceiling (attr, prioceiling)
int *prioceiling; int *prioceiling;
{ {
const struct pthread_mutexattr *iattr; const struct pthread_mutexattr *iattr;
int ceiling;
iattr = (const struct pthread_mutexattr *) attr; iattr = (const struct pthread_mutexattr *) attr;
*prioceiling = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) ceiling = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
>> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT); >> 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; return 0;
} }

View File

@ -27,7 +27,15 @@ pthread_mutexattr_setprioceiling (attr, prioceiling)
pthread_mutexattr_t *attr; pthread_mutexattr_t *attr;
int prioceiling; 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; return EINVAL;
struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr; struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr;

View File

@ -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. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@ -45,6 +45,19 @@ __pthread_setschedparam (threadid, policy, param)
lll_lock (pd->lock); 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. */ /* Try to set the scheduler information. */
if (__builtin_expect (__sched_setscheduler (pd->tid, policy, if (__builtin_expect (__sched_setscheduler (pd->tid, policy,
param) == -1, 0)) param) == -1, 0))
@ -54,7 +67,7 @@ __pthread_setschedparam (threadid, policy, param)
/* We succeeded changing the kernel information. Reflect this /* We succeeded changing the kernel information. Reflect this
change in the thread descriptor. */ change in the thread descriptor. */
pd->schedpolicy = policy; 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; pd->flags |= ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET;
} }

View File

@ -47,6 +47,11 @@ pthread_setschedprio (threadid, prio)
lll_lock (pd->lock); 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. */ /* Try to set the scheduler information. */
if (__builtin_expect (sched_setparam (pd->tid, &param) == -1, 0)) if (__builtin_expect (sched_setparam (pd->tid, &param) == -1, 0))
result = errno; result = errno;
@ -54,6 +59,7 @@ pthread_setschedprio (threadid, prio)
{ {
/* We succeeded changing the kernel information. Reflect this /* We succeeded changing the kernel information. Reflect this
change in the thread descriptor. */ change in the thread descriptor. */
param.sched_priority = prio;
memcpy (&pd->schedparam, &param, sizeof (struct sched_param)); memcpy (&pd->schedparam, &param, sizeof (struct sched_param));
pd->flags |= ATTR_FLAG_SCHED_SET; pd->flags |= ATTR_FLAG_SCHED_SET;
} }

View File

@ -82,6 +82,10 @@
/* We support priority inheritence. */ /* We support priority inheritence. */
#define _POSIX_THREAD_PRIO_INHERIT 200112L #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. */ /* We support POSIX.1b semaphores. */
#define _POSIX_SEMAPHORES 200112L #define _POSIX_SEMAPHORES 200112L
@ -174,7 +178,4 @@
/* Typed memory objects are not available. */ /* Typed memory objects are not available. */
#define _POSIX_TYPED_MEMORY_OBJECTS -1 #define _POSIX_TYPED_MEMORY_OBJECTS -1
/* No support for priority protection so far. */
#define _POSIX_THREAD_PRIO_PROTECT -1
#endif /* posix_opt.h */ #endif /* posix_opt.h */

172
nptl/tpp.c Normal file
View 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;
}

View File

@ -71,5 +71,7 @@ do_test (void)
return 0; return 0;
} }
#define TEST_FUNCTION do_test () #ifndef TEST_FUNCTION
# define TEST_FUNCTION do_test ()
#endif
#include "../test-skeleton.c" #include "../test-skeleton.c"

View File

@ -69,5 +69,7 @@ do_test (void)
} }
#define EXPECTED_SIGNAL SIGALRM #define EXPECTED_SIGNAL SIGALRM
#define TEST_FUNCTION do_test () #ifndef TEST_FUNCTION
# define TEST_FUNCTION do_test ()
#endif
#include "../test-skeleton.c" #include "../test-skeleton.c"

45
nptl/tst-mutexpp1.c Normal file
View 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
View 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
View 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
View 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);
}
}

View File

@ -40,8 +40,9 @@ _dl_runtime_resolve:
mflr r0 mflr r0
# We also need to save some of the condition register fields # We also need to save some of the condition register fields
stw r7,32(r1) stw r7,32(r1)
stw r0,68(r1) # Don't clobber the caller's LRSAVE, it is needed by _mcount.
cfi_offset (lr, 4) stw r0,48(r1)
cfi_offset (lr, -16)
stw r8,36(r1) stw r8,36(r1)
mfcr r0 mfcr r0
stw r9,40(r1) stw r9,40(r1)
@ -51,7 +52,7 @@ _dl_runtime_resolve:
# 'fixup' returns the address we want to branch to. # 'fixup' returns the address we want to branch to.
mtctr r3 mtctr r3
# Put the registers back... # Put the registers back...
lwz r0,68(r1) lwz r0,48(r1)
lwz r10,44(r1) lwz r10,44(r1)
lwz r9,40(r1) lwz r9,40(r1)
mtlr r0 mtlr r0
@ -128,8 +129,9 @@ _dl_prof_resolve:
mflr r5 mflr r5
# We also need to save some of the condition register fields. # We also need to save some of the condition register fields.
stw r7,32(r1) stw r7,32(r1)
stw r5,324(r1) # Don't clobber the caller's LRSAVE, it is needed by _mcount.
cfi_offset (lr, 4) stw r5,308(r1)
cfi_offset (lr, -12)
stw r8,36(r1) stw r8,36(r1)
mfcr r0 mfcr r0
stw r9,40(r1) stw r9,40(r1)
@ -154,7 +156,7 @@ _dl_prof_resolve:
# 'fixup' returns the address we want to branch to. # 'fixup' returns the address we want to branch to.
mtctr r3 mtctr r3
# Put the registers back... # Put the registers back...
lwz r0,324(r1) lwz r0,308(r1)
lwz r10,44(r1) lwz r10,44(r1)
lwz r9,40(r1) lwz r9,40(r1)
mtlr r0 mtlr r0