c6d234
commit faf0e9c84119742dd9ebb79060faa22c52ae80a1
c6d234
Author: Florian Weimer <fweimer@redhat.com>
c6d234
Date:   Fri Jan 27 06:53:19 2017 +0100
c6d234
c6d234
    nptl: Add tst-robust-fork
c6d234
c6d234
Index: glibc-2.17-c758a686/nptl/Makefile
c6d234
===================================================================
c6d234
--- glibc-2.17-c758a686.orig/nptl/Makefile
c6d234
+++ glibc-2.17-c758a686/nptl/Makefile
c6d234
@@ -271,7 +271,7 @@ tests = tst-typesizes \
c6d234
 	tst-initializers1 $(patsubst %,tst-initializers1-%,c89 gnu89 c99 gnu99) \
c6d234
 	tst-mutex-errorcheck \
c6d234
 	tst-minstack-cancel tst-minstack-exit tst-minstack-throw \
c6d234
-	tst-thread-exit-clobber
c6d234
+	tst-thread-exit-clobber tst-robust-fork
c6d234
 xtests = tst-setuid1 tst-setuid1-static tst-mutexpp1 tst-mutexpp6 tst-mutexpp10
c6d234
 test-srcs = tst-oddstacklimit
c6d234
 
c6d234
Index: glibc-2.17-c758a686/nptl/tst-robust-fork.c
c6d234
===================================================================
c6d234
--- /dev/null
c6d234
+++ glibc-2.17-c758a686/nptl/tst-robust-fork.c
c6d234
@@ -0,0 +1,184 @@
c6d234
+/* Test the interaction of fork and robust mutexes.
c6d234
+   Copyright (C) 2017 Free Software Foundation, Inc.
c6d234
+   This file is part of the GNU C Library.
c6d234
+
c6d234
+   The GNU C Library is free software; you can redistribute it and/or
c6d234
+   modify it under the terms of the GNU Lesser General Public
c6d234
+   License as published by the Free Software Foundation; either
c6d234
+   version 2.1 of the License, or (at your option) any later version.
c6d234
+
c6d234
+   The GNU C Library is distributed in the hope that it will be useful,
c6d234
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
c6d234
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
c6d234
+   Lesser General Public License for more details.
c6d234
+
c6d234
+   You should have received a copy of the GNU Lesser General Public
c6d234
+   License along with the GNU C Library; if not, see
c6d234
+   <http://www.gnu.org/licenses/>.  */
c6d234
+
c6d234
+#include <errno.h>
c6d234
+#include <stdbool.h>
c6d234
+#include <stdio.h>
c6d234
+#include <support/check.h>
c6d234
+#include <support/test-driver.h>
c6d234
+#include <support/xthread.h>
c6d234
+#include <support/xunistd.h>
c6d234
+#include <sys/mman.h>
c6d234
+
c6d234
+/* Data shared between processes. */
c6d234
+struct shared
c6d234
+{
c6d234
+  pthread_mutex_t parent_mutex;
c6d234
+  pthread_mutex_t child_mutex;
c6d234
+};
c6d234
+
c6d234
+/* These flags control which mutex settings are enabled in the parent
c6d234
+   and child (separately).  */
c6d234
+enum mutex_bits
c6d234
+  {
c6d234
+    mutex_pshared = 1,
c6d234
+    mutex_robust = 2,
c6d234
+    mutex_pi = 4,
c6d234
+    mutex_check = 8,
c6d234
+
c6d234
+    /* All bits combined.  */
c6d234
+    mutex_all_bits = 15,
c6d234
+  };
c6d234
+
c6d234
+static void
c6d234
+mutex_init (pthread_mutex_t *mutex, int bits)
c6d234
+{
c6d234
+  pthread_mutexattr_t attr;
c6d234
+  xpthread_mutexattr_init (&attr);
c6d234
+  if (bits & mutex_pshared)
c6d234
+    xpthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED);
c6d234
+  if (bits & mutex_robust)
c6d234
+    xpthread_mutexattr_setrobust (&attr, PTHREAD_MUTEX_ROBUST);
c6d234
+  if (bits & mutex_pi)
c6d234
+    xpthread_mutexattr_setprotocol (&attr, PTHREAD_PRIO_INHERIT);
c6d234
+  if (bits & mutex_check)
c6d234
+    xpthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK);
c6d234
+  xpthread_mutex_init (mutex, &attr);
c6d234
+  xpthread_mutexattr_destroy (&attr);
c6d234
+}
c6d234
+
c6d234
+static void
c6d234
+one_test (int parent_bits, int child_bits, int nonshared_bits,
c6d234
+          bool lock_nonshared, bool lock_child)
c6d234
+{
c6d234
+
c6d234
+  struct shared *shared = xmmap (NULL, sizeof (*shared),
c6d234
+                                 PROT_READ | PROT_WRITE,
c6d234
+                                 MAP_ANONYMOUS | MAP_SHARED, -1);
c6d234
+  mutex_init (&shared->parent_mutex, parent_bits);
c6d234
+  mutex_init (&shared->child_mutex, child_bits);
c6d234
+
c6d234
+  /* Acquire the parent mutex in the parent.  */
c6d234
+  xpthread_mutex_lock (&shared->parent_mutex);
c6d234
+
c6d234
+  pthread_mutex_t nonshared_mutex;
c6d234
+  mutex_init (&nonshared_mutex, nonshared_bits);
c6d234
+  if (lock_nonshared)
c6d234
+    xpthread_mutex_lock (&nonshared_mutex);
c6d234
+
c6d234
+  pid_t pid = xfork ();
c6d234
+  if (pid == 0)
c6d234
+    {
c6d234
+      /* Child process.  */
c6d234
+      if (lock_child)
c6d234
+        xpthread_mutex_lock (&shared->child_mutex);
c6d234
+      else
c6d234
+        xmunmap (shared, sizeof (*shared));
c6d234
+      if (lock_nonshared)
c6d234
+        /* Reinitialize the non-shared mutex if it was locked in the
c6d234
+           parent.  */
c6d234
+        mutex_init (&nonshared_mutex, nonshared_bits);
c6d234
+      xpthread_mutex_lock (&nonshared_mutex);
c6d234
+      /* For robust mutexes, the _exit call will perform the unlock
c6d234
+         instead.  */
c6d234
+      if (lock_child && !(child_bits & mutex_robust))
c6d234
+        xpthread_mutex_unlock (&shared->child_mutex);
c6d234
+      _exit (0);
c6d234
+    }
c6d234
+  /* Parent process. */
c6d234
+  {
c6d234
+    int status;
c6d234
+    xwaitpid (pid, &status, 0);
c6d234
+    TEST_VERIFY (status == 0);
c6d234
+  }
c6d234
+
c6d234
+  if (parent_bits & mutex_check)
c6d234
+    /* Test for expected self-deadlock.  This is only possible to
c6d234
+       detect if the mutex is error-checking.  */
c6d234
+    TEST_VERIFY_EXIT (pthread_mutex_lock (&shared->parent_mutex) == EDEADLK);
c6d234
+
c6d234
+  pid = xfork ();
c6d234
+  if (pid == 0)
c6d234
+    {
c6d234
+      /* Child process.  We can perform some checks only if we are
c6d234
+         dealing with process-shared mutexes.  */
c6d234
+      if (parent_bits & mutex_pshared)
c6d234
+        /* It must not be possible to acquire the parent mutex.
c6d234
+
c6d234
+           NB: This check touches a mutex which has been acquired in
c6d234
+           the parent at fork time, so it might be deemed undefined
c6d234
+           behavior, pending the resolution of Austin Groups issue
c6d234
+           1112.  */
c6d234
+        TEST_VERIFY_EXIT (pthread_mutex_trylock (&shared->parent_mutex)
c6d234
+                          == EBUSY);
c6d234
+      if (lock_child && (child_bits & mutex_robust))
c6d234
+        {
c6d234
+          if (!(child_bits & mutex_pshared))
c6d234
+            /* No further tests possible.  */
c6d234
+            _exit (0);
c6d234
+          TEST_VERIFY_EXIT (pthread_mutex_lock (&shared->child_mutex)
c6d234
+                            == EOWNERDEAD);
c6d234
+          xpthread_mutex_consistent (&shared->child_mutex);
c6d234
+        }
c6d234
+      else
c6d234
+        /* We did not acquire the lock in the first child process, or
c6d234
+           we unlocked the mutex again because the mutex is not a
c6d234
+           robust mutex.  */
c6d234
+        xpthread_mutex_lock (&shared->child_mutex);
c6d234
+      xpthread_mutex_unlock (&shared->child_mutex);
c6d234
+      _exit (0);
c6d234
+    }
c6d234
+  /* Parent process. */
c6d234
+  {
c6d234
+    int status;
c6d234
+    xwaitpid (pid, &status, 0);
c6d234
+    TEST_VERIFY (status == 0);
c6d234
+  }
c6d234
+
c6d234
+  if (lock_nonshared)
c6d234
+    xpthread_mutex_unlock (&nonshared_mutex);
c6d234
+  xpthread_mutex_unlock (&shared->parent_mutex);
c6d234
+  xpthread_mutex_destroy (&shared->parent_mutex);
c6d234
+  xpthread_mutex_destroy (&shared->child_mutex);
c6d234
+  xpthread_mutex_destroy (&nonshared_mutex);
c6d234
+  xmunmap (shared, sizeof (*shared));
c6d234
+}
c6d234
+
c6d234
+static int
c6d234
+do_test (void)
c6d234
+{
c6d234
+  for (int parent_bits = 0; parent_bits <= mutex_all_bits; ++parent_bits)
c6d234
+    for (int child_bits = 0; child_bits <= mutex_all_bits; ++child_bits)
c6d234
+      for (int nonshared_bits = 0; nonshared_bits <= mutex_all_bits;
c6d234
+           ++nonshared_bits)
c6d234
+        for (int lock_nonshared = 0; lock_nonshared < 2; ++lock_nonshared)
c6d234
+          for (int lock_child = 0; lock_child < 2; ++lock_child)
c6d234
+            {
c6d234
+              if (test_verbose)
c6d234
+                printf ("info: parent_bits=0x%x child_bits=0x%x"
c6d234
+                        " nonshared_bits=0x%x%s%s\n",
c6d234
+                        parent_bits, child_bits, nonshared_bits,
c6d234
+                        lock_nonshared ? " lock_nonshared" : "",
c6d234
+                        lock_child ? " lock_child" : "");
c6d234
+              one_test (parent_bits, child_bits, nonshared_bits,
c6d234
+                        lock_nonshared, lock_child);
c6d234
+            }
c6d234
+  return 0;
c6d234
+}
c6d234
+
c6d234
+#include <support/test-driver.c>