From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4472 invoked by alias); 14 Aug 2006 11:28:40 -0000 Received: (qmail 4413 invoked by uid 22791); 14 Aug 2006 11:28:39 -0000 X-Spam-Check-By: sourceware.org Received: from sunsite.ms.mff.cuni.cz (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 14 Aug 2006 12:28:29 +0100 Received: from sunsite.mff.cuni.cz (sunsite.mff.cuni.cz [127.0.0.1]) by sunsite.mff.cuni.cz (8.13.1/8.13.1) with ESMTP id k7EBS7p7013956; Mon, 14 Aug 2006 13:28:07 +0200 Received: (from jj@localhost) by sunsite.mff.cuni.cz (8.13.1/8.13.1/Submit) id k7EBS78v013955; Mon, 14 Aug 2006 13:28:07 +0200 Date: Mon, 14 Aug 2006 11:28:00 -0000 From: Jakub Jelinek To: Ulrich Drepper Cc: Glibc hackers Subject: [PATCH] PTHREAD_PRIO_PROTECT support Message-ID: <20060814112806.GH4556@sunsite.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.1i Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2006-08/txt/msg00018.txt.bz2 Hi! This patch implements PTHREAD_PRIO_PROTECT support in NPTL, though only for non-robust mutexes, on the other side it requires no additional kernel support. 2006-08-14 Jakub Jelinek * 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 test. * tst-mutexpp6.c: New test. * tst-mutexpp10.c: New test. * tst-mutex1.c (TEST_FUNCTION): Don't redefine if already defined. * tst-mutex6.c (TEST_FUNCTION): Likewise. --- libc/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h 2006-08-14 12:35:16.000000000 +0200 @@ -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 */ --- libc/nptl/tpp.c.jj 2006-08-10 14:07:26.000000000 +0200 +++ libc/nptl/tpp.c 2006-08-14 13:19:50.000000000 +0200 @@ -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 , 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 +#include +#include +#include +#include +#include + + +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; +} --- libc/nptl/pthread_setschedparam.c.jj 2004-02-27 13:51:58.000000000 +0100 +++ libc/nptl/pthread_setschedparam.c 2006-08-14 11:59:10.000000000 +0200 @@ -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 , 2002. @@ -45,6 +45,19 @@ __pthread_setschedparam (threadid, polic 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, polic /* 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; } --- libc/nptl/pthread_mutexattr_setprioceiling.c.jj 2006-02-28 10:36:05.000000000 +0100 +++ libc/nptl/pthread_mutexattr_setprioceiling.c 2006-08-14 12:30:57.000000000 +0200 @@ -27,7 +27,15 @@ pthread_mutexattr_setprioceiling (attr, 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; --- libc/nptl/pthread_mutex_init.c.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/pthread_mutex_init.c 2006-08-10 16:25:59.000000000 +0200 @@ -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: --- libc/nptl/pthread_create.c.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/pthread_create.c 2006-08-14 12:11:43.000000000 +0200 @@ -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. */ --- libc/nptl/descr.h.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/descr.h 2006-08-14 11:36:19.000000000 +0200 @@ -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; --- libc/nptl/pthreadP.h.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/pthreadP.h 2006-08-14 12:29:07.000000000 +0200 @@ -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 attr 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; --- libc/nptl/pthread_mutex_trylock.c.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/pthread_mutex_trylock.c 2006-08-14 12:04:35.000000000 +0200 @@ -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; --- libc/nptl/pthread_mutex_timedlock.c.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/pthread_mutex_timedlock.c 2006-08-14 12:05:16.000000000 +0200 @@ -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; --- libc/nptl/pthread_mutex_unlock.c.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/pthread_mutex_unlock.c 2006-08-10 16:04:36.000000000 +0200 @@ -202,6 +202,49 @@ __pthread_mutex_unlock_usercnt (mutex, d 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; --- libc/nptl/pthread_mutexattr_getprioceiling.c.jj 2006-02-28 10:36:05.000000000 +0100 +++ libc/nptl/pthread_mutexattr_getprioceiling.c 2006-08-10 16:04:36.000000000 +0200 @@ -27,11 +27,22 @@ pthread_mutexattr_getprioceiling (attr, 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; } --- libc/nptl/pthread_mutex_getprioceiling.c.jj 2006-02-28 10:36:05.000000000 +0100 +++ libc/nptl/pthread_mutex_getprioceiling.c 2006-08-10 16:04:36.000000000 +0200 @@ -26,7 +26,11 @@ pthread_mutex_getprioceiling (mutex, pri 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; --- libc/nptl/pthread_setschedprio.c.jj 2004-11-24 23:52:48.000000000 +0100 +++ libc/nptl/pthread_setschedprio.c 2006-08-14 11:59:43.000000000 +0200 @@ -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; } --- libc/nptl/pthread_mutex_setprioceiling.c.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/pthread_mutex_setprioceiling.c 2006-08-14 12:30:15.000000000 +0200 @@ -18,6 +18,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include #include #include @@ -33,23 +34,83 @@ pthread_mutex_setprioceiling (mutex, pri 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; } --- libc/nptl/Makefile.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/Makefile 2006-08-11 15:33:52.000000000 +0200 @@ -122,7 +122,7 @@ libpthread-routines = init vars events v pthread_mutexattr_getprotocol \ pthread_mutexattr_setprotocol \ pthread_mutexattr_getprioceiling \ - pthread_mutexattr_setprioceiling \ + pthread_mutexattr_setprioceiling tpp \ pthread_mutex_getprioceiling pthread_mutex_setprioceiling # pthread_setuid pthread_seteuid pthread_setreuid \ # pthread_setresuid \ @@ -258,7 +258,7 @@ tests = tst-typesizes \ tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \ tst-getpid1 tst-getpid2 tst-getpid3 \ tst-initializers1 $(patsubst %,tst-initializers1-%,c89 gnu89 c99 gnu99) -xtests = tst-setuid1 tst-setuid1-static +xtests = tst-setuid1 tst-setuid1-static tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 # Files which must not be linked with libpthread. tests-nolibpthread = tst-unload --- libc/nptl/pthread_mutex_lock.c.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/pthread_mutex_lock.c 2006-08-14 12:03:49.000000000 +0200 @@ -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; --- libc/nptl/tst-mutexpp10.c.jj 2006-08-11 13:03:22.000000000 +0200 +++ libc/nptl/tst-mutexpp10.c 2006-08-11 15:12:06.000000000 +0200 @@ -0,0 +1,334 @@ +/* Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 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 +#include +#include +#include +#include +#include +#include +#include + +#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" --- libc/nptl/tst-mutex1.c.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/tst-mutex1.c 2006-08-11 15:12:50.000000000 +0200 @@ -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" --- libc/nptl/tst-mutex6.c.jj 2006-08-03 19:36:24.000000000 +0200 +++ libc/nptl/tst-mutex6.c 2006-08-11 15:14:52.000000000 +0200 @@ -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" --- libc/nptl/tst-tpp.h.jj 2006-08-11 15:10:14.000000000 +0200 +++ libc/nptl/tst-tpp.h 2006-08-14 13:08:34.000000000 +0200 @@ -0,0 +1,94 @@ +/* Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 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 +#include +#include +#include +#include +#include +#include +#include + +/* 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); + } +} --- libc/nptl/tst-mutexpp1.c.jj 2006-08-11 15:15:13.000000000 +0200 +++ libc/nptl/tst-mutexpp1.c 2006-08-11 15:26:08.000000000 +0200 @@ -0,0 +1,45 @@ +#include +#include +#include + +#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" --- libc/nptl/tst-mutexpp6.c.jj 2006-08-11 15:15:13.000000000 +0200 +++ libc/nptl/tst-mutexpp6.c 2006-08-11 15:25:53.000000000 +0200 @@ -0,0 +1,45 @@ +#include +#include +#include + +#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" Jakub