|
|
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>
|