This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH 1/4] pi-condvars: add protocol support to pthread_condattr_t
- From: Darren Hart <dvhltc at us dot ibm dot com>
- To: libc-alpha at sources dot redhat dot com
- Cc: dvhltc at us dot ibm dot com, dino at in dot ibm dot com, drepper at gmail dot com, tglx at linutronix dot de, peterz at infradead dot org
- Date: Thu, 27 May 2010 16:14:47 -0700
- Subject: [PATCH 1/4] pi-condvars: add protocol support to pthread_condattr_t
- References: <1275002090-24343-1-git-send-email-dvhltc@us.ibm.com>
When using a PTHREAD_PRIO_INHERIT mutex with a condvar, the pthread_cond* calls
can still cause an unbounded priority inversion via the internal condvar lock.
The POSIX specification doesn't provide a mechanism to specify the protocol of
the condvar. We would like to do this at runtime, but unfortunately it is legal
to call pthread_cond_signal() or pthread_cond_broadcast() without first waiting
on the lock, so the mutex type may not be known the first time the condvar is
used. A new API, pthread_condattr_setprotocol_np() and
pthread_condattr_getprotocol_np() allow the user to create a
PTHREAD_PRIO_INHERIT condvar. This uses a PTHREAD_PRIO_INHERIT mutex for the
internal condvar lock, eliminating the potential for hitting an unbounded
priority inversion on that lock.
V3: Extricate the pi-condvars work from the C implementation of requeue-pi.
2010-05-21 Darren Hart <dvhltc@us.ibm.com>
* ../Versions.def: Define GLIBC_2.13
* Makefile (libpthread-routines): Add
pthread_condattr_getprotocol_np and pthread_condattr_setprotocol_np.
* Versions: Export pthread_condattr_getprotocol_np and
pthread_condattr_setprotocol_np.
* pthread_cond_broadcast.c: Use cond_lock and cond_unlock.
* pthread_cond_init.c: Set the condvar protocol from the condattr.
* pthread_cond_signal.c: Use cond_lock and cond_unlock.
* pthread_cond_timedwait.c: Use cond_lock and cond_unlock.
* pthread_cond_wait.c: Use cond_lock and cond_unlock.
FIXME: also defines lll_pi_(un)?lock - unused.
* pthread_condattr_getclock.c: Use new protocol shift values.
* pthread_condattr_getprotocol_np.c: New file.
* pthread_condattr_setclock.c: Use new protocol shift values.
* pthread_condattr_setprotocol_np.c: New file.
* sysdeps/pthread/pthread.h: Declare
pthread_condattr_getprotocol_np and pthread_condattr_setprotocol_np.
* sysdeps/unix/sysv/linux/internaltypes.h: Define bits, masks, and
shift for the pthread_condattr.value.
---
Versions.def | 1 +
nptl/Makefile | 1 +
nptl/Versions | 4 ++
nptl/pthread_cond_broadcast.c | 11 +++--
nptl/pthread_cond_init.c | 23 ++++++++-
nptl/pthread_cond_signal.c | 9 +++-
nptl/pthread_cond_timedwait.c | 16 ++++---
nptl/pthread_cond_wait.c | 61 ++++++++++++++++++++++----
nptl/pthread_condattr_getclock.c | 7 ++-
nptl/pthread_condattr_getprotocol_np.c | 34 ++++++++++++++
nptl/pthread_condattr_setclock.c | 6 +-
nptl/pthread_condattr_setprotocol_np.c | 39 ++++++++++++++++
nptl/sysdeps/pthread/cond-lock.h | 59 +++++++++++++++++++++++++
nptl/sysdeps/pthread/pthread.h | 12 +++++
nptl/sysdeps/unix/sysv/linux/internaltypes.h | 30 ++++++++++---
15 files changed, 276 insertions(+), 37 deletions(-)
create mode 100644 nptl/pthread_condattr_getprotocol_np.c
create mode 100644 nptl/pthread_condattr_setprotocol_np.c
create mode 100644 nptl/sysdeps/pthread/cond-lock.h
diff --git a/Versions.def b/Versions.def
index eab006b..26535b5 100644
--- a/Versions.def
+++ b/Versions.def
@@ -92,6 +92,7 @@ libpthread {
GLIBC_2.6
GLIBC_2.11
GLIBC_2.12
+ GLIBC_2.13
GLIBC_PRIVATE
}
libresolv {
diff --git a/nptl/Makefile b/nptl/Makefile
index 982db8e..6d1913e 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -75,6 +75,7 @@ libpthread-routines = nptl-init vars events version \
old_pthread_cond_signal old_pthread_cond_broadcast \
pthread_condattr_init pthread_condattr_destroy \
pthread_condattr_getpshared pthread_condattr_setpshared \
+ pthread_condattr_getprotocol_np pthread_condattr_setprotocol_np \
pthread_condattr_getclock pthread_condattr_setclock \
pthread_spin_init pthread_spin_destroy \
pthread_spin_lock pthread_spin_trylock \
diff --git a/nptl/Versions b/nptl/Versions
index f74941f..49a89e8 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -251,6 +251,10 @@ libpthread {
pthread_setname_np; pthread_getname_np;
};
+ GLIBC_2.13 {
+ pthread_condattr_getprotocol_np; pthread_condattr_setprotocol_np;
+ }
+
GLIBC_PRIVATE {
__pthread_initialize_minimal;
__pthread_clock_gettime; __pthread_clock_settime;
diff --git a/nptl/pthread_cond_broadcast.c b/nptl/pthread_cond_broadcast.c
index 22523c2..40611a5 100644
--- a/nptl/pthread_cond_broadcast.c
+++ b/nptl/pthread_cond_broadcast.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2003, 2004, 2006, 2007, 2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
@@ -27,6 +27,8 @@
#include <shlib-compat.h>
#include <kernel-features.h>
+#include "cond-lock.h"
+
int
__pthread_cond_broadcast (cond)
@@ -34,8 +36,9 @@ __pthread_cond_broadcast (cond)
{
int pshared = (cond->__data.__mutex == (void *) ~0l)
? LLL_SHARED : LLL_PRIVATE;
+
/* Make sure we are alone. */
- lll_lock (cond->__data.__lock, pshared);
+ cond_lock (cond, pshared);
/* Are there any waiters to be woken? */
if (cond->__data.__total_seq > cond->__data.__wakeup_seq)
@@ -49,7 +52,7 @@ __pthread_cond_broadcast (cond)
++cond->__data.__broadcast_seq;
/* We are done. */
- lll_unlock (cond->__data.__lock, pshared);
+ cond_unlock (cond, pshared);
/* Do not use requeue for pshared condvars. */
if (cond->__data.__mutex == (void *) ~0l)
@@ -82,7 +85,7 @@ __pthread_cond_broadcast (cond)
}
/* We are done. */
- lll_unlock (cond->__data.__lock, pshared);
+ cond_unlock (cond, pshared);
return 0;
}
diff --git a/nptl/pthread_cond_init.c b/nptl/pthread_cond_init.c
index 65c01b1..33bb6bb 100644
--- a/nptl/pthread_cond_init.c
+++ b/nptl/pthread_cond_init.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008
+/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2010
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -32,9 +32,26 @@ __pthread_cond_init (cond, cond_attr)
cond->__data.__lock = LLL_LOCK_INITIALIZER;
cond->__data.__futex = 0;
cond->__data.__nwaiters = (icond_attr != NULL
- ? ((icond_attr->value >> 1)
- & ((1 << COND_NWAITERS_SHIFT) - 1))
+ ? ((icond_attr->value >> CONDATTR_CLOCKID_SHIFT)
+ & ((1 << COND_PROTOCOL_SHIFT) - 1))
: CLOCK_REALTIME);
+ if (icond_attr != NULL)
+ {
+ switch (icond_attr->value & CONDATTR_PROTOCOL_MASK)
+ {
+ case PTHREAD_PRIO_INHERIT << CONDATTR_PROTOCOL_SHIFT:
+ cond->__data.__nwaiters |= COND_PRIO_INHERIT;
+ break;
+
+ case PTHREAD_PRIO_PROTECT << CONDATTR_PROTOCOL_SHIFT:
+ cond->__data.__nwaiters |= COND_PRIO_PROTECT;
+ break;
+
+ default:
+ break;
+ }
+ }
+
cond->__data.__total_seq = 0;
cond->__data.__wakeup_seq = 0;
cond->__data.__woken_seq = 0;
diff --git a/nptl/pthread_cond_signal.c b/nptl/pthread_cond_signal.c
index 023bbb5..114158c 100644
--- a/nptl/pthread_cond_signal.c
+++ b/nptl/pthread_cond_signal.c
@@ -27,6 +27,8 @@
#include <shlib-compat.h>
#include <kernel-features.h>
+#include "cond-lock.h"
+
int
__pthread_cond_signal (cond)
@@ -36,7 +38,7 @@ __pthread_cond_signal (cond)
? LLL_SHARED : LLL_PRIVATE;
/* Make sure we are alone. */
- lll_lock (cond->__data.__lock, pshared);
+ cond_lock(cond, pshared);
/* Are there any waiters to be woken? */
if (cond->__data.__total_seq > cond->__data.__wakeup_seq)
@@ -45,17 +47,20 @@ __pthread_cond_signal (cond)
++cond->__data.__wakeup_seq;
++cond->__data.__futex;
+#if 0
+ /* This is not needed for the x86_64 or i686 arches */
/* Wake one. */
if (! __builtin_expect (lll_futex_wake_unlock (&cond->__data.__futex, 1,
1, &cond->__data.__lock,
pshared), 0))
return 0;
+#endif
lll_futex_wake (&cond->__data.__futex, 1, pshared);
}
/* We are done. */
- lll_unlock (cond->__data.__lock, pshared);
+ cond_unlock(cond, pshared);
return 0;
}
diff --git a/nptl/pthread_cond_timedwait.c b/nptl/pthread_cond_timedwait.c
index 7278ec4..21e3afe 100644
--- a/nptl/pthread_cond_timedwait.c
+++ b/nptl/pthread_cond_timedwait.c
@@ -27,6 +27,8 @@
#include <shlib-compat.h>
+#include "cond-lock.h"
+
#ifndef HAVE_CLOCK_GETTIME_VSYSCALL
# undef INTERNAL_VSYSCALL
# define INTERNAL_VSYSCALL INTERNAL_SYSCALL
@@ -65,14 +67,14 @@ __pthread_cond_timedwait (cond, mutex, abstime)
int pshared = (cond->__data.__mutex == (void *) ~0l)
? LLL_SHARED : LLL_PRIVATE;
- /* Make sure we are along. */
- lll_lock (cond->__data.__lock, pshared);
+ /* Make sure we are alone. */
+ cond_lock(cond, pshared);
/* Now we can release the mutex. */
int err = __pthread_mutex_unlock_usercnt (mutex, 0);
if (err)
{
- lll_unlock (cond->__data.__lock, pshared);
+ cond_unlock(cond, pshared);
return err;
}
@@ -112,7 +114,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
int ret;
ret = INTERNAL_VSYSCALL (clock_gettime, err, 2,
(cond->__data.__nwaiters
- & ((1 << COND_NWAITERS_SHIFT) - 1)),
+ & ((1 << COND_PROTOCOL_SHIFT) - 1)),
&rt);
# ifndef __ASSUME_POSIX_TIMERS
if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (ret, err), 0))
@@ -158,7 +160,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
unsigned int futex_val = cond->__data.__futex;
/* Prepare to wait. Release the condvar futex. */
- lll_unlock (cond->__data.__lock, pshared);
+ cond_unlock(cond, pshared);
/* Enable asynchronous cancellation. Required by the standard. */
cbuffer.oldtype = __pthread_enable_asynccancel ();
@@ -171,7 +173,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
__pthread_disable_asynccancel (cbuffer.oldtype);
/* We are going to look at shared data again, so get the lock. */
- lll_lock (cond->__data.__lock, pshared);
+ cond_lock(cond, pshared);
/* If a broadcast happened, we are done. */
if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
@@ -211,7 +213,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
lll_futex_wake (&cond->__data.__nwaiters, 1, pshared);
/* We are done with the condvar. */
- lll_unlock (cond->__data.__lock, pshared);
+ cond_unlock(cond, pshared);
/* The cancellation handling is back to normal, remove the handler. */
__pthread_cleanup_pop (&buffer, 0);
diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
index 670fba5..43893b7 100644
--- a/nptl/pthread_cond_wait.c
+++ b/nptl/pthread_cond_wait.c
@@ -17,15 +17,19 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <assert.h>
#include <endian.h>
#include <errno.h>
#include <sysdep.h>
#include <lowlevellock.h>
+#include <not-cancel.h>
#include <pthread.h>
#include <pthreadP.h>
#include <shlib-compat.h>
+#include "cond-lock.h"
+
struct _condvar_cleanup_buffer
{
@@ -38,16 +42,55 @@ struct _condvar_cleanup_buffer
void
__attribute__ ((visibility ("hidden")))
+lll_pi_lock(int *futexp, int private)
+{
+ pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
+ int newval = id;
+ int ret;
+
+ newval |= FUTEX_WAITERS;
+ ret = atomic_compare_and_exchange_val_acq (futexp, newval, 0);
+
+ if (ret != 0)
+ {
+ /* The mutex is locked. The kernel will now take care of
+ everything. */
+ INTERNAL_SYSCALL_DECL (__err);
+ int e = INTERNAL_SYSCALL (futex, __err, 4, futexp,
+ __lll_private_flag (FUTEX_LOCK_PI, private),
+ 1, 0);
+ }
+}
+
+
+void
+__attribute__ ((visibility ("hidden")))
+lll_pi_unlock(int *futexp, int private)
+{
+
+ if ((*futexp & FUTEX_WAITERS) != 0
+ || atomic_compare_and_exchange_bool_acq (futexp, 0,
+ THREAD_GETMEM (THREAD_SELF,
+ tid)))
+ {
+ INTERNAL_SYSCALL_DECL (__err);
+ INTERNAL_SYSCALL (futex, __err, 2, futexp,
+ __lll_private_flag (FUTEX_UNLOCK_PI, private));
+ }
+}
+
+
+void
+__attribute__ ((visibility ("hidden")))
__condvar_cleanup (void *arg)
{
struct _condvar_cleanup_buffer *cbuffer =
(struct _condvar_cleanup_buffer *) arg;
unsigned int destroying;
- int pshared = (cbuffer->cond->__data.__mutex == (void *) ~0l)
- ? LLL_SHARED : LLL_PRIVATE;
+ int pshared = (cbuffer->mutex == (void *) ~0l) ? LLL_SHARED : LLL_PRIVATE;
/* We are going to modify shared data. */
- lll_lock (cbuffer->cond->__data.__lock, pshared);
+ cond_lock(cbuffer->cond, pshared);
if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq)
{
@@ -78,7 +121,7 @@ __condvar_cleanup (void *arg)
}
/* We are done. */
- lll_unlock (cbuffer->cond->__data.__lock, pshared);
+ cond_unlock(cbuffer->cond, pshared);
/* Wake everybody to make sure no condvar signal gets lost. */
if (! destroying)
@@ -102,13 +145,13 @@ __pthread_cond_wait (cond, mutex)
? LLL_SHARED : LLL_PRIVATE;
/* Make sure we are along. */
- lll_lock (cond->__data.__lock, pshared);
+ cond_lock(cond, pshared);
/* Now we can release the mutex. */
err = __pthread_mutex_unlock_usercnt (mutex, 0);
if (__builtin_expect (err, 0))
{
- lll_unlock (cond->__data.__lock, pshared);
+ cond_unlock(cond, pshared);
return err;
}
@@ -144,7 +187,7 @@ __pthread_cond_wait (cond, mutex)
unsigned int futex_val = cond->__data.__futex;
/* Prepare to wait. Release the condvar futex. */
- lll_unlock (cond->__data.__lock, pshared);
+ cond_unlock(cond, pshared);
/* Enable asynchronous cancellation. Required by the standard. */
cbuffer.oldtype = __pthread_enable_asynccancel ();
@@ -156,7 +199,7 @@ __pthread_cond_wait (cond, mutex)
__pthread_disable_asynccancel (cbuffer.oldtype);
/* We are going to look at shared data again, so get the lock. */
- lll_lock (cond->__data.__lock, pshared);
+ cond_lock(cond, pshared);
/* If a broadcast happened, we are done. */
if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
@@ -182,7 +225,7 @@ __pthread_cond_wait (cond, mutex)
lll_futex_wake (&cond->__data.__nwaiters, 1, pshared);
/* We are done with the condvar. */
- lll_unlock (cond->__data.__lock, pshared);
+ cond_unlock(cond, pshared);
/* The cancellation handling is back to normal, remove the handler. */
__pthread_cleanup_pop (&buffer, 0);
diff --git a/nptl/pthread_condattr_getclock.c b/nptl/pthread_condattr_getclock.c
index 3eedeb1..9f034b3 100644
--- a/nptl/pthread_condattr_getclock.c
+++ b/nptl/pthread_condattr_getclock.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2003,2004,2007,2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -25,7 +25,8 @@ pthread_condattr_getclock (attr, clock_id)
const pthread_condattr_t *attr;
clockid_t *clock_id;
{
- *clock_id = (((((const struct pthread_condattr *) attr)->value) >> 1)
- & ((1 << COND_NWAITERS_SHIFT) - 1));
+ *clock_id = (((((const struct pthread_condattr *) attr)->value)
+ >> CONDATTR_CLOCKID_SHIFT)
+ & ((1 << COND_PROTOCOL_SHIFT) - 1));
return 0;
}
diff --git a/nptl/pthread_condattr_getprotocol_np.c b/nptl/pthread_condattr_getprotocol_np.c
new file mode 100644
index 0000000..18e099d
--- /dev/null
+++ b/nptl/pthread_condattr_getprotocol_np.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Dinakar Guniguntala <dino@in.ibm.com>.
+
+ 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 "pthreadP.h"
+
+
+int
+pthread_condattr_getprotocol_np (attr, protocol)
+ const pthread_condattr_t *attr;
+ int *protocol;
+{
+ *protocol = ((const struct pthread_condattr *) attr)->value;
+
+ *protocol = ((*protocol & CONDATTR_PROTOCOL_MASK)
+ >> CONDATTR_PROTOCOL_SHIFT);
+
+ return 0;
+}
diff --git a/nptl/pthread_condattr_setclock.c b/nptl/pthread_condattr_setclock.c
index 5c54f76..97e9595 100644
--- a/nptl/pthread_condattr_setclock.c
+++ b/nptl/pthread_condattr_setclock.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
+/* Copyright (C) 2003,2004,2007,2008,2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -62,11 +62,11 @@ pthread_condattr_setclock (attr, clock_id)
return EINVAL;
/* Make sure the value fits in the bits we reserved. */
- assert (clock_id < (1 << COND_NWAITERS_SHIFT));
+ assert (clock_id < (1 << COND_PROTOCOL_SHIFT));
int *valuep = &((struct pthread_condattr *) attr)->value;
- *valuep = ((*valuep & ~(((1 << COND_NWAITERS_SHIFT) - 1) << 1))
+ *valuep = ((*valuep & ~(((1 << COND_PROTOCOL_SHIFT) - 1) << 1))
| (clock_id << 1));
return 0;
diff --git a/nptl/pthread_condattr_setprotocol_np.c b/nptl/pthread_condattr_setprotocol_np.c
new file mode 100644
index 0000000..250a196
--- /dev/null
+++ b/nptl/pthread_condattr_setprotocol_np.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Dinakar Guniguntala <dino@in.ibm.com>.
+
+ 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 <pthreadP.h>
+
+int
+pthread_condattr_setprotocol_np (attr, protocol)
+ pthread_condattr_t *attr;
+ int protocol;
+{
+ if (protocol != PTHREAD_PRIO_NONE
+ && protocol != PTHREAD_PRIO_INHERIT
+ && __builtin_expect (protocol != PTHREAD_PRIO_PROTECT, 0))
+ return EINVAL;
+
+ int *valuep = &((struct pthread_condattr *) attr)->value;
+
+ *valuep = ((*valuep & ~CONDATTR_PROTOCOL_MASK)
+ | (protocol << CONDATTR_PROTOCOL_SHIFT));
+
+ return 0;
+}
diff --git a/nptl/sysdeps/pthread/cond-lock.h b/nptl/sysdeps/pthread/cond-lock.h
new file mode 100644
index 0000000..9031a00
--- /dev/null
+++ b/nptl/sysdeps/pthread/cond-lock.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Dinakar Guniguntala <dino@in.ibm.com>.
+
+ 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. */
+
+#ifndef _COND_LOCK_H
+#define _COND_LOCK_H 1
+
+
+extern void lll_pi_lock (int *futex, int pshared)
+ __attribute__ ((visibility ("hidden")));
+extern void lll_pi_unlock (int *futex, int pshared)
+ __attribute__ ((visibility ("hidden")));
+
+static inline void cond_lock(pthread_cond_t *cond,
+ int pshared);
+
+static inline void cond_unlock(pthread_cond_t *cond,
+ int pshared);
+
+static inline void cond_lock(cond, pshared)
+ pthread_cond_t *cond;
+ int pshared;
+{
+ if (pshared == LLL_PRIVATE
+ && ((cond->__data.__nwaiters & COND_PROTOCOL_MASK)
+ == COND_PRIO_INHERIT))
+ lll_pi_lock (&cond->__data.__lock, pshared);
+ else
+ lll_lock (cond->__data.__lock, pshared);
+}
+
+static inline void cond_unlock(cond, pshared)
+ pthread_cond_t *cond;
+ int pshared;
+{
+ if (pshared == LLL_PRIVATE
+ && ((cond->__data.__nwaiters & COND_PROTOCOL_MASK)
+ == COND_PRIO_INHERIT))
+ lll_pi_unlock (&cond->__data.__lock, pshared);
+ else
+ lll_unlock (cond->__data.__lock, pshared);
+}
+
+#endif
diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h
index 44cf9f0..ef5e093 100644
--- a/nptl/sysdeps/pthread/pthread.h
+++ b/nptl/sysdeps/pthread/pthread.h
@@ -1006,6 +1006,18 @@ extern int pthread_condattr_getpshared (__const pthread_condattr_t *
extern int pthread_condattr_setpshared (pthread_condattr_t *__attr,
int __pshared) __THROW __nonnull ((1));
+/* Get the protocol flag of the condition variable attribute ATTR. */
+extern int pthread_condattr_getprotocol_np (__const pthread_condattr_t *
+ __restrict __attr,
+ int *__restrict __protocol)
+ __THROW __nonnull ((1, 2));
+
+/* Set the cond protocol attribute in ATTR to protocol (one of
+ PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT or PTHREAD_PRIO_PROTECT). */
+extern int pthread_condattr_setprotocol_np (pthread_condattr_t *__attr,
+ int __protocol)
+ __THROW __nonnull ((1));
+
#ifdef __USE_XOPEN2K
/* Get the clock selected for the conditon variable attribute ATTR. */
extern int pthread_condattr_getclock (__const pthread_condattr_t *
diff --git a/nptl/sysdeps/unix/sysv/linux/internaltypes.h b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
index add20b6..876ca79 100644
--- a/nptl/sysdeps/unix/sysv/linux/internaltypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
@@ -67,20 +67,38 @@ struct pthread_condattr
{
/* Combination of values:
- Bit 0 : flag whether coditional variable will be shareable between
+ Bit 0 : flag whether conditional variable will be shareable between
processes.
- Bit 1-7: clock ID. */
+ Bit 1-7: clock ID.
+ Bit 8-9: protocol. One of PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT
+ or PTHREAD_PRIO_PROTECT. */
int value;
};
+#define CONDATTR_PSHARED_MASK 0x00000001
+#define CONDATTR_CLOCKID_MASK 0x000000FE
+#define CONDATTR_CLOCKID_SHIFT 1
+#define CONDATTR_PROTOCOL_MASK 0x00000300
+#define CONDATTR_PROTOCOL_SHIFT 8
+
+
+enum {
+ COND_PRIO_INHERIT = 2,
+ COND_PRIO_PROTECT
+};
+
+
/* The __NWAITERS field is used as a counter and to house the number
- of bits for other purposes. COND_CLOCK_BITS is the number
- of bits needed to represent the ID of the clock. COND_NWAITERS_SHIFT
+ of bits for other purposes. COND_CLOCK_MASK defines the bits used
+ to represent the ID of the clock. COND_PROTOCOL_MASK defines the
+ bits used to represent cond protocol attrbutes. COND_NWAITERS_SHIFT
is the number of bits reserved for other purposes like the clock. */
-#define COND_CLOCK_BITS 1
-#define COND_NWAITERS_SHIFT 1
+#define COND_CLOCK_MASK 0x00000001
+#define COND_PROTOCOL_SHIFT 1
+#define COND_PROTOCOL_MASK 0x00000006
+#define COND_NWAITERS_SHIFT 3
/* Read-write lock variable attribute data structure. */
--
1.7.0.4