aboutsummaryrefslogtreecommitdiff
path: root/nptl/tst-once5.cc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2015-07-01 14:05:27 -0600
committerMartin Sebor <msebor@redhat.com>2015-07-01 14:05:27 -0600
commited225df3ad9cbac3c22ec3f0fbbed1f9c61d1c54 (patch)
tree175abf6476b8924e619c559993324efdb855e392 /nptl/tst-once5.cc
parent9081b7bcb11e74cd2d4363663ccd1bb641392719 (diff)
downloadglibc-ed225df3ad9cbac3c22ec3f0fbbed1f9c61d1c54.tar
glibc-ed225df3ad9cbac3c22ec3f0fbbed1f9c61d1c54.tar.gz
glibc-ed225df3ad9cbac3c22ec3f0fbbed1f9c61d1c54.tar.bz2
glibc-ed225df3ad9cbac3c22ec3f0fbbed1f9c61d1c54.zip
The C++ 2011 std::call_once function is specified to allow
the initialization routine to exit by throwing an exception. Such an execution, termed exceptional, requires call_once to propagate the exception to its caller. A program may contain any number of exceptional executions but only one returning execution (which, if it exists, must be the last execution with the same once flag). On POSIX systems such as Linux, std::call_once is implemented in terms of pthread_once. However, as discussed in libstdc++ bug 66146 - "call_once not C++11-compliant on ppc64le," GLIBC's pthread_once hangs when the initialization function exits by throwing an exception on at least arm and ppc64 (though apparently not on x86_64). This effectively prevents call_once from conforming to the C++ requirements since there doesn't appear to be a thread-safe way to work around this problem in libstdc++. This patch changes pthread_once to handle gracefully init functions that exit by throwing exceptions. It was successfully tested on ppc64, ppc64le, and x86_64. [BZ #18435] * nptl/Makefile: Add tst-once5.cc. * nptl/pthreadP.h (pthread_cleanup_push, pthread_cleanup_pop): Remove macro redefinitions. * nptl/tst-once5.cc: New test.
Diffstat (limited to 'nptl/tst-once5.cc')
-rw-r--r--nptl/tst-once5.cc80
1 files changed, 80 insertions, 0 deletions
diff --git a/nptl/tst-once5.cc b/nptl/tst-once5.cc
new file mode 100644
index 0000000000..60bc78a64a
--- /dev/null
+++ b/nptl/tst-once5.cc
@@ -0,0 +1,80 @@
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ 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 <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+// Exception type thrown from the pthread_once init routine.
+struct OnceException { };
+
+// Test iteration counter.
+static int niter;
+
+static void
+init_routine (void)
+{
+ if (niter < 2)
+ throw OnceException ();
+}
+
+// Verify that an exception thrown from the pthread_once init routine
+// is propagated to the pthread_once caller and that the function can
+// be subsequently invoked to attempt the initialization again.
+static int
+do_test (void)
+{
+ int result = 1;
+
+ // Repeat three times, having the init routine throw the first two
+ // times and succeed on the final attempt.
+ for (niter = 0; niter != 3; ++niter) {
+
+ try {
+ int rc = pthread_once (&once, init_routine);
+ if (rc)
+ fprintf (stderr, "pthread_once failed: %i (%s)\n",
+ rc, strerror (rc));
+
+ if (niter < 2)
+ fputs ("pthread_once unexpectedly returned without"
+ " throwing an exception", stderr);
+ }
+ catch (OnceException) {
+ if (1 < niter)
+ fputs ("pthread_once unexpectedly threw", stderr);
+ result = 0;
+ }
+ catch (...) {
+ fputs ("pthread_once threw an unknown exception", stderr);
+ }
+
+ // Abort the test on the first failure.
+ if (result)
+ break;
+ }
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"