djdelorie / rpms / glibc

Forked from rpms/glibc 3 years ago
Clone
bcf3103
commit 99e1dc0a688d6c25d3f422bc9f3fa29adb483339
bcf3103
Author: Florian Weimer <fweimer@redhat.com>
bcf3103
Date:   Tue Oct 6 21:27:55 2015 +0200
bcf3103
bcf3103
    Add a test case for C++11 thread_local support
bcf3103
    
bcf3103
    This requires a C++ compiler with thread_local support, and a new
bcf3103
    configure check is needed.
bcf3103
bcf3103
Index: b/config.make.in
bcf3103
===================================================================
bcf3103
--- a/config.make.in
bcf3103
+++ b/config.make.in
bcf3103
@@ -66,6 +66,7 @@ bind-now = @bindnow@
bcf3103
 have-hash-style = @libc_cv_hashstyle@
bcf3103
 use-default-link = @use_default_link@
bcf3103
 output-format = @libc_cv_output_format@
bcf3103
+have-cxx-thread_local = @libc_cv_cxx_thread_local@
bcf3103
 
bcf3103
 static-libgcc = @libc_cv_gcc_static_libgcc@
bcf3103
 
bcf3103
Index: b/configure
bcf3103
===================================================================
bcf3103
--- a/configure
bcf3103
+++ b/configure
bcf3103
@@ -613,6 +613,7 @@ use_nscd
bcf3103
 libc_cv_gcc_unwind_find_fde
bcf3103
 libc_extra_cppflags
bcf3103
 libc_extra_cflags
bcf3103
+libc_cv_cxx_thread_local
bcf3103
 CPPUNDEFS
bcf3103
 sizeof_long_double
bcf3103
 have_selinux
bcf3103
@@ -7047,6 +7048,61 @@ if test $libc_cv_builtin_trap = yes; the
bcf3103
 
bcf3103
 fi
bcf3103
 
bcf3103
+ac_ext=cpp
bcf3103
+ac_cpp='$CXXCPP $CPPFLAGS'
bcf3103
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
bcf3103
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
bcf3103
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
bcf3103
+
bcf3103
+
bcf3103
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler supports thread_local" >&5
bcf3103
+$as_echo_n "checking whether the C++ compiler supports thread_local... " >&6; }
bcf3103
+if ${libc_cv_cxx_thread_local+:} false; then :
bcf3103
+  $as_echo_n "(cached) " >&6
bcf3103
+else
bcf3103
+
bcf3103
+old_CXXFLAGS="$CXXFLAGS"
bcf3103
+CXXFLAGS="$CXXFLAGS -std=gnu++11"
bcf3103
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
bcf3103
+/* end confdefs.h.  */
bcf3103
+
bcf3103
+#include <thread>
bcf3103
+
bcf3103
+// Compiler support.
bcf3103
+struct S
bcf3103
+{
bcf3103
+  S ();
bcf3103
+  ~S ();
bcf3103
+};
bcf3103
+thread_local S s;
bcf3103
+S * get () { return &s; }
bcf3103
+
bcf3103
+// libstdc++ support.
bcf3103
+#ifndef _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL
bcf3103
+#error __cxa_thread_atexit_impl not supported
bcf3103
+#endif
bcf3103
+
bcf3103
+_ACEOF
bcf3103
+if ac_fn_cxx_try_compile "$LINENO"; then :
bcf3103
+  libc_cv_cxx_thread_local=yes
bcf3103
+else
bcf3103
+  libc_cv_cxx_thread_local=no
bcf3103
+fi
bcf3103
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
bcf3103
+CXXFLAGS="$old_CXXFLAGS"
bcf3103
+
bcf3103
+fi
bcf3103
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cxx_thread_local" >&5
bcf3103
+$as_echo "$libc_cv_cxx_thread_local" >&6; }
bcf3103
+
bcf3103
+
bcf3103
+ac_ext=c
bcf3103
+ac_cpp='$CPP $CPPFLAGS'
bcf3103
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
bcf3103
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
bcf3103
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
bcf3103
+
bcf3103
+
bcf3103
 ### End of automated tests.
bcf3103
 ### Now run sysdeps configure fragments.
bcf3103
 
bcf3103
Index: b/configure.ac
bcf3103
===================================================================
bcf3103
--- a/configure.ac
bcf3103
+++ b/configure.ac
bcf3103
@@ -1925,6 +1925,39 @@ if test $libc_cv_builtin_trap = yes; the
bcf3103
   AC_DEFINE([HAVE_BUILTIN_TRAP])
bcf3103
 fi
bcf3103
 
bcf3103
+dnl C++ feature tests.
bcf3103
+AC_LANG_PUSH([C++])
bcf3103
+
bcf3103
+AC_CACHE_CHECK([whether the C++ compiler supports thread_local],
bcf3103
+	       libc_cv_cxx_thread_local, [
bcf3103
+old_CXXFLAGS="$CXXFLAGS"
bcf3103
+CXXFLAGS="$CXXFLAGS -std=gnu++11"
bcf3103
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([
bcf3103
+#include <thread>
bcf3103
+
bcf3103
+// Compiler support.
bcf3103
+struct S
bcf3103
+{
bcf3103
+  S ();
bcf3103
+  ~S ();
bcf3103
+};
bcf3103
+thread_local S s;
bcf3103
+S * get () { return &s; }
bcf3103
+
bcf3103
+// libstdc++ support.
bcf3103
+#ifndef _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL
bcf3103
+#error __cxa_thread_atexit_impl not supported
bcf3103
+#endif
bcf3103
+])],
bcf3103
+	       [libc_cv_cxx_thread_local=yes],
bcf3103
+	       [libc_cv_cxx_thread_local=no])
bcf3103
+CXXFLAGS="$old_CXXFLAGS"
bcf3103
+])
bcf3103
+AC_SUBST(libc_cv_cxx_thread_local)
bcf3103
+
bcf3103
+AC_LANG_POP([C++])
bcf3103
+dnl End of C++ feature tests.
bcf3103
+
bcf3103
 ### End of automated tests.
bcf3103
 ### Now run sysdeps configure fragments.
bcf3103
 
bcf3103
Index: b/nptl/Makefile
bcf3103
===================================================================
bcf3103
--- a/nptl/Makefile
bcf3103
+++ b/nptl/Makefile
bcf3103
@@ -205,6 +205,8 @@ CFLAGS-send.c = -fexceptions -fasynchron
bcf3103
 
bcf3103
 CFLAGS-pt-system.c = -fexceptions
bcf3103
 
bcf3103
+CFLAGS-tst-thread_local1.o = -std=gnu++11
bcf3103
+LDLIBS-tst-thread_local1 = -lstdc++
bcf3103
 
bcf3103
 tests = tst-typesizes \
bcf3103
 	tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
bcf3103
@@ -274,7 +276,8 @@ tests = tst-typesizes \
bcf3103
 	tst-getpid1 tst-getpid2 tst-getpid3 \
bcf3103
 	tst-setuid3 \
bcf3103
 	tst-initializers1 $(addprefix tst-initializers1-,c89 gnu89 c99 gnu99) \
bcf3103
-	tst-bad-schedattr
bcf3103
+	tst-bad-schedattr \
bcf3103
+	tst-thread_local1
bcf3103
 xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \
bcf3103
 	tst-mutexpp1 tst-mutexpp6 tst-mutexpp10
bcf3103
 test-srcs = tst-oddstacklimit
bcf3103
@@ -385,6 +388,11 @@ tests-special += $(objpfx)tst-tls6.out $
bcf3103
 endif
bcf3103
 endif
bcf3103
 
bcf3103
+# These tests require a C++ compiler and runtime with thread_local support.
bcf3103
+ifneq ($(have-cxx-thread_local),yes)
bcf3103
+tests-unsupported += tst-thread_local1
bcf3103
+endif
bcf3103
+
bcf3103
 include ../Rules
bcf3103
 
bcf3103
 ifeq (yes,$(build-shared))
bcf3103
Index: b/nptl/tst-thread_local1.cc
bcf3103
===================================================================
bcf3103
--- /dev/null
bcf3103
+++ b/nptl/tst-thread_local1.cc
bcf3103
@@ -0,0 +1,199 @@
bcf3103
+/* Test basic thread_local support.
bcf3103
+   Copyright (C) 2015 Free Software Foundation, Inc.
bcf3103
+   This file is part of the GNU C Library.
bcf3103
+
bcf3103
+   The GNU C Library is free software; you can redistribute it and/or
bcf3103
+   modify it under the terms of the GNU Lesser General Public
bcf3103
+   License as published by the Free Software Foundation; either
bcf3103
+   version 2.1 of the License, or (at your option) any later version.
bcf3103
+
bcf3103
+   The GNU C Library is distributed in the hope that it will be useful,
bcf3103
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
bcf3103
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
bcf3103
+   Lesser General Public License for more details.
bcf3103
+
bcf3103
+   You should have received a copy of the GNU Lesser General Public
bcf3103
+   License along with the GNU C Library; if not, see
bcf3103
+   <http://www.gnu.org/licenses/>.  */
bcf3103
+
bcf3103
+#include <errno.h>
bcf3103
+#include <pthread.h>
bcf3103
+#include <stdio.h>
bcf3103
+#include <string.h>
bcf3103
+
bcf3103
+#include <functional>
bcf3103
+#include <string>
bcf3103
+#include <thread>
bcf3103
+
bcf3103
+struct counter
bcf3103
+{
bcf3103
+  int constructed {};
bcf3103
+  int destructed {};
bcf3103
+
bcf3103
+  void reset ();
bcf3103
+};
bcf3103
+
bcf3103
+void
bcf3103
+counter::reset ()
bcf3103
+{
bcf3103
+  constructed = 0;
bcf3103
+  destructed = 0;
bcf3103
+}
bcf3103
+
bcf3103
+static std::string
bcf3103
+to_string (const counter &c)
bcf3103
+{
bcf3103
+  char buf[128];
bcf3103
+  snprintf (buf, sizeof (buf), "%d/%d",
bcf3103
+            c.constructed, c.destructed);
bcf3103
+  return buf;
bcf3103
+}
bcf3103
+
bcf3103
+template <counter *Counter>
bcf3103
+struct counting
bcf3103
+{
bcf3103
+  counting () __attribute__ ((noinline, noclone));
bcf3103
+  ~counting () __attribute__ ((noinline, noclone));
bcf3103
+  void operation () __attribute__ ((noinline, noclone));
bcf3103
+};
bcf3103
+
bcf3103
+template<counter *Counter>
bcf3103
+__attribute__ ((noinline, noclone))
bcf3103
+counting<Counter>::counting ()
bcf3103
+{
bcf3103
+  ++Counter->constructed;
bcf3103
+}
bcf3103
+
bcf3103
+template<counter *Counter>
bcf3103
+__attribute__ ((noinline, noclone))
bcf3103
+counting<Counter>::~counting ()
bcf3103
+{
bcf3103
+  ++Counter->destructed;
bcf3103
+}
bcf3103
+
bcf3103
+template<counter *Counter>
bcf3103
+void __attribute__ ((noinline, noclone))
bcf3103
+counting<Counter>::operation ()
bcf3103
+{
bcf3103
+  // Optimization barrier.
bcf3103
+  asm ("");
bcf3103
+}
bcf3103
+
bcf3103
+static counter counter_static;
bcf3103
+static counter counter_anonymous_namespace;
bcf3103
+static counter counter_extern;
bcf3103
+static counter counter_function_local;
bcf3103
+static bool errors (false);
bcf3103
+
bcf3103
+static std::string
bcf3103
+all_counters ()
bcf3103
+{
bcf3103
+  return to_string (counter_static)
bcf3103
+    + ' ' + to_string (counter_anonymous_namespace)
bcf3103
+    + ' ' + to_string (counter_extern)
bcf3103
+    + ' ' + to_string (counter_function_local);
bcf3103
+}
bcf3103
+
bcf3103
+static void
bcf3103
+check_counters (const char *name, const char *expected)
bcf3103
+{
bcf3103
+  std::string actual{all_counters ()};
bcf3103
+  if (actual != expected)
bcf3103
+    {
bcf3103
+      printf ("error: %s: (%s) != (%s)\n",
bcf3103
+              name, actual.c_str (), expected);
bcf3103
+      errors = true;
bcf3103
+    }
bcf3103
+}
bcf3103
+
bcf3103
+static void
bcf3103
+reset_all ()
bcf3103
+{
bcf3103
+  counter_static.reset ();
bcf3103
+  counter_anonymous_namespace.reset ();
bcf3103
+  counter_extern.reset ();
bcf3103
+  counter_function_local.reset ();
bcf3103
+}
bcf3103
+
bcf3103
+static thread_local counting<&counter_static> counting_static;
bcf3103
+namespace {
bcf3103
+  thread_local counting<&counter_anonymous_namespace>
bcf3103
+    counting_anonymous_namespace;
bcf3103
+}
bcf3103
+extern thread_local counting<&counter_extern> counting_extern;
bcf3103
+thread_local counting<&counter_extern> counting_extern;
bcf3103
+
bcf3103
+static void *
bcf3103
+thread_without_access (void *)
bcf3103
+{
bcf3103
+  return nullptr;
bcf3103
+}
bcf3103
+
bcf3103
+static void *
bcf3103
+thread_with_access (void *)
bcf3103
+{
bcf3103
+  thread_local counting<&counter_function_local> counting_function_local;
bcf3103
+  counting_function_local.operation ();
bcf3103
+  check_counters ("early in thread_with_access", "0/0 0/0 0/0 1/0");
bcf3103
+  counting_static.operation ();
bcf3103
+  counting_anonymous_namespace.operation ();
bcf3103
+  counting_extern.operation ();
bcf3103
+  check_counters ("in thread_with_access", "1/0 1/0 1/0 1/0");
bcf3103
+  return nullptr;
bcf3103
+}
bcf3103
+
bcf3103
+static int
bcf3103
+do_test (void)
bcf3103
+{
bcf3103
+  std::function<void (void *(void *))> do_pthread =
bcf3103
+    [](void *(func) (void *))
bcf3103
+    {
bcf3103
+      pthread_t thr;
bcf3103
+      int ret = pthread_create (&thr, nullptr, func, nullptr);
bcf3103
+      if (ret != 0)
bcf3103
+        {
bcf3103
+          errno = ret;
bcf3103
+          printf ("error: pthread_create: %m\n");
bcf3103
+          errors = true;
bcf3103
+          return;
bcf3103
+        }
bcf3103
+      ret = pthread_join (thr, nullptr);
bcf3103
+      if (ret != 0)
bcf3103
+        {
bcf3103
+          errno = ret;
bcf3103
+          printf ("error: pthread_join: %m\n");
bcf3103
+          errors = true;
bcf3103
+          return;
bcf3103
+        }
bcf3103
+    };
bcf3103
+  std::function<void (void *(void *))> do_std_thread =
bcf3103
+    [](void *(func) (void *))
bcf3103
+    {
bcf3103
+      std::thread thr{[func] {func (nullptr);}};
bcf3103
+      thr.join ();
bcf3103
+    };
bcf3103
+
bcf3103
+  std::array<std::pair<const char *, std::function<void (void *(void *))>>, 2>
bcf3103
+    do_thread_X
bcf3103
+      {{
bcf3103
+        {"pthread_create", do_pthread},
bcf3103
+        {"std::thread", do_std_thread},
bcf3103
+      }};
bcf3103
+
bcf3103
+  for (auto do_thread : do_thread_X)
bcf3103
+    {
bcf3103
+      printf ("info: testing %s\n", do_thread.first);
bcf3103
+      check_counters ("initial", "0/0 0/0 0/0 0/0");
bcf3103
+      do_thread.second (thread_without_access);
bcf3103
+      check_counters ("after thread_without_access", "0/0 0/0 0/0 0/0");
bcf3103
+      reset_all ();
bcf3103
+      do_thread.second (thread_with_access);
bcf3103
+      check_counters ("after thread_with_access", "1/1 1/1 1/1 1/1");
bcf3103
+      reset_all ();
bcf3103
+    }
bcf3103
+
bcf3103
+  return errors;
bcf3103
+}
bcf3103
+
bcf3103
+#define TEST_FUNCTION do_test ()
bcf3103
+#include "../test-skeleton.c"