ce426f
commit a3e5b4feeb54cb92657ec2bc6d9be1fcef9e8575
ce426f
Author: Paul E. Murphy <murphyp@linux.vnet.ibm.com>
ce426f
Date:   Mon Jan 11 17:24:04 2016 -0500
ce426f
ce426f
    Fix race in tst-mqueue5
ce426f
    
ce426f
    The check is done on line 117 by a thread spawned
ce426f
    from do_child(), forked from do_test().  This test
ce426f
    generates a signal in the forked process.
ce426f
    
ce426f
    Either thread may handle the signal, and on ppc,
ce426f
    it happens to be done on do_child, on the thread
ce426f
    which is not doing the check on line 117.
ce426f
    
ce426f
    This exposes a race condition whereby the test
ce426f
    incorrectly fails as the signal is caught during
ce426f
    or after the check.
ce426f
    
ce426f
    This is mitigated by ensuring the signal is blocked
ce426f
    in the child thread while thread is running.
ce426f
ce426f
 2016-01-15  Martin Sebor  <msebor@redhat.com>
ce426f
 
ce426f
 	[BZ #19432]
ce426f
diff --git a/rt/tst-mqueue5.c b/rt/tst-mqueue5.c
ce426f
index aa74fa3..25042bc 100644
ce426f
--- a/rt/tst-mqueue5.c
ce426f
+++ b/rt/tst-mqueue5.c
ce426f
@@ -116,7 +116,7 @@ thr (void *arg)
ce426f
 
ce426f
   if (rtmin_cnt != 2)
ce426f
     {
ce426f
-      puts ("SIGRTMIN signal in child did not arrive");
ce426f
+      puts ("SIGRTMIN signal in thread did not arrive");
ce426f
       result = 1;
ce426f
     }
ce426f
   else if (rtmin_pid != getppid ()
ce426f
@@ -403,6 +403,16 @@ do_child (const char *name, pthread_barrier_t *b2, pthread_barrier_t *b3,
ce426f
       result = 1;
ce426f
     }
ce426f
 
ce426f
+  /* Ensure the thr thread gets the signal, not us.  */
ce426f
+  sigset_t set;
ce426f
+  sigemptyset (&set);
ce426f
+  sigaddset (&set, SIGRTMIN);
ce426f
+  if (pthread_sigmask (SIG_BLOCK, &set, NULL))
ce426f
+    {
ce426f
+      printf ("Failed to block SIGRTMIN in child: %m\n");
ce426f
+      result = 1;
ce426f
+    }
ce426f
+
ce426f
   (void) pthread_barrier_wait (b2);
ce426f
 
ce426f
   /* Parent calls mqsend (q), which should wake up mqrecv (q)
ce426f
@@ -514,7 +524,14 @@ do_child (const char *name, pthread_barrier_t *b2, pthread_barrier_t *b3,
ce426f
       result = 1;
ce426f
     }
ce426f
 
ce426f
- void *thr_ret;
ce426f
+  /* Reenable test signals before cleaning up the thread.  */
ce426f
+  if (pthread_sigmask (SIG_UNBLOCK, &set, NULL))
ce426f
+    {
ce426f
+      printf ("Failed to unblock SIGRTMIN in child: %m\n");
ce426f
+      result = 1;
ce426f
+    }
ce426f
+
ce426f
+  void *thr_ret;
ce426f
   ret = pthread_join (th, &thr_ret);
ce426f
   if (ret)
ce426f
     {