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]

[PATCH 4/4] pi-condvars: tst-condpi2.c, detect priority inversion


The test framework will abort the test after 2 seconds and stop a make check
run. I had originally thought to detect the inversion and gracefully exit. I'm
not sure which approach is preferred, so this patch adds the detection
separately and can be safely discarded if not desired.

V3: Whitespace cleanup.

2010-05-21:  Darren Hart  <dvhltc@us.ibm.com>
	* tst-condpi2.c: Add unbounded priority inversion detection rather
	than relying on the built-in timeout facility.
---
 nptl/tst-condpi2.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/nptl/tst-condpi2.c b/nptl/tst-condpi2.c
index 2b6c7ef..29921f8 100644
--- a/nptl/tst-condpi2.c
+++ b/nptl/tst-condpi2.c
@@ -40,7 +40,31 @@ static pthread_mutex_t race_mut;
 static pthread_cond_t sig1, sig2, sig3;
 static pthread_mutex_t m1, m2, m3;
 
+static pthread_barrier_t bar;
+
 static volatile unsigned int done = 0;
+static unsigned int test_result = 0;
+
+static void *
+watchdog_tf (void *p)
+{
+  int err;
+
+  err = pthread_barrier_wait (&bar);
+  if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+    error (EXIT_FAILURE, err, "watchdog_tf: barrier wait failed");
+
+  /* Allow time for high_tf to set done=1 indicating a successful run.  If
+     it is hung waiting on race_var, we set done=2 indicating failure.  med_tf
+     will detect the 2 and indicate a failure in test_result.  */
+  usleep (1000);
+  if (done != 1)
+    {
+      usleep (500000);
+      done = 2;
+    }
+  return NULL;
+}
 
 static void *
 low_tf (void *p)
@@ -147,6 +171,28 @@ med_tf (void *p)
   while (!done)
           /* Busy wait to block low threads.  */;
 
+  /* If watchdog_tf has set done to 2 before high_tf has set it to 1,
+     then the test has failed.  */
+  if (done == 2)
+    {
+      puts ("med_tf: unbounded priority inversion detected.");
+
+      /* low_tf and high_tf are now waiting on race_var, having missed
+         the broadcast issued in do_test(). Wake them up now and exit
+         gracefully.  */
+      err = pthread_mutex_lock (&race_mut);
+      if (err != 0)
+        error (EXIT_FAILURE, err, "med_tf: failed to lock race_mut");
+      err = pthread_cond_broadcast (&race_var);
+      if (err != 0)
+        error (EXIT_FAILURE, err, "med_tf: broadcast to race_var failed");
+      err = pthread_mutex_unlock (&race_mut);
+      if (err != 0)
+        error (EXIT_FAILURE, err, "med_tf: failed to unlock race_mut");
+
+      test_result = 1;
+    }
+
   puts ("med_tf: done spinning");
 
   return NULL;
@@ -158,6 +204,7 @@ do_test (void)
   pthread_t low_thread;
   pthread_t med_thread;
   pthread_t high_thread;
+  pthread_t watchdog_thread;
   struct sched_param param;
   pthread_attr_t attr;
   pthread_mutexattr_t m_attr;
@@ -167,7 +214,10 @@ do_test (void)
   int err;
 
 
-  /* Initialize mutexes and condvars.  */
+  /* Initialize barrier, mutexes, and condvars.  */
+  err = pthread_barrier_init (&bar, NULL, 2);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: failed to init barrier");
 
   err = pthread_attr_init (&attr);
   if (err != 0)
@@ -231,6 +281,10 @@ do_test (void)
   if (err != 0)
     error (EXIT_FAILURE, err, "parent: failed to set CPU affinity");
 
+  err = pthread_create (&watchdog_thread, &attr, watchdog_tf, (void*)NULL);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "parent: failed to create watchdog_tf");
+
   param.sched_priority = LOW_PRIO;
   err = pthread_attr_setschedparam (&attr, &param);
   if (err != 0)
@@ -265,11 +319,18 @@ do_test (void)
      PTHREAD_PRIO_INHERIT, low_tf will not have released the race_var cond_lock
      and neither thread will have waited on race_var.  */
   usleep (1000);
+
+  err = pthread_barrier_wait (&bar);
+  if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+    error (EXIT_FAILURE, err, "parent: barrier wait failed");
   err = pthread_cond_broadcast (&race_var);
   if (err != 0)
     error (EXIT_FAILURE, err, "parent: failed to broadcast condition");
 
   /* Wait for threads to complete.  */
+  err = pthread_join (watchdog_thread, (void**) NULL);
+  if (err != 0)
+    error (EXIT_FAILURE, err, "join of watchdog_tf failed");
   err = pthread_join (low_thread, (void**) NULL);
   if (err != 0)
     error (EXIT_FAILURE, err, "join of low_tf failed");
@@ -282,7 +343,7 @@ do_test (void)
 
   puts ("done");
 
-  return 0;
+  return test_result;
 }
 
 
-- 
1.7.0.4


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