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