This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 1/4] pi-condvars: add protocol support to pthread_condattr_t


On 05/27/2010 04:14 PM, Darren Hart wrote:
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.

As Ulrich has expressed concern with the impact of this patch on the non PI code paths, I wrote a condvar_perf testcase:


http://sourceware.org/bugzilla/attachment.cgi?id=4821&action=view

And ran it with and without these patches. In both cases I removed the pthread_cond*.S files in order to eliminate the custom asm as a variable. The test measures how long it takes to perform 10,000 unlocked cond_wait/signal pairs 10,000 times. This produces a population size of 10,000 from which the following statistics are generated. The units are in cycles/second.

Two runs WITHOUT the patch applied:

Scheduling: SCHED_OTHER 0
Iterations: 10000
Population: 10000
Min: 192429.812500
Max: 509735.937500
Avg: 318937.718750
Var: 7093996032.000000
Std: 84225.863201

Scheduling: SCHED_OTHER 0
Iterations: 10000
Population: 10000
Min: 125557.156250
Max: 441930.343750
Avg: 356763.937500
Var: 1766417280.000000
Std: 42028.767291


Two runs WITH the patch applied:


Scheduling: SCHED_OTHER 0
Iterations: 10000
Population: 10000
Min: 189591.437500
Max: 399584.437500
Avg: 293040.406250
Var: 6691464704.000000
Std: 81801.373485

Scheduling: SCHED_OTHER 0
Iterations: 10000
Population: 10000
Min: 201971.250000
Max: 374644.093750
Avg: 296880.343750
Var: 2308329472.000000
Std: 48045.077500


There is a considerable amount of variation in all the test runs. The lowest average does occur with the patch applied at 293,040. The highest occurs without the patch at 356,763. The StdDev varies from 42,028 to 84,225. The difference between the min and max scores is about a StdDev.


This is more of a difference than I expected to see, and is much more than what I saw with my previous measurements. I ran the test case differently this time, using the glibc testrun.sh script after integrating the performance test into the nptl/Makefile. It's possible my previous numbers resulted from a faulty test setup.

I will continue to experiment with the testcase as I'd like to see less variation between runs of the same glibc build.

Thoughts and suggestions regarding this approach are appreciated.

Thanks,

Darren Hart


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. */


--
Darren Hart
IBM Linux Technology Center
Real-Time Linux Team


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]