From patchwork Mon Oct 5 15:50:40 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 526386 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 8A70314029C for ; Tue, 6 Oct 2015 02:50:53 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b=wCPQLlku; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:to:from:subject:message-id:date:mime-version :content-type; q=dns; s=default; b=vNZFy5Yh/n1jMAo+BxdNz7ZoZGSgl 70eCKfqiHdVza+Ovy9POew4iPO/H4YzI0rgsFl57McQ97auWdqrQJOEt9eTFRcg7 E69s5sIWeaw71PtlL1P46sYwCOJ1NBE+jdZHYW0G5EP4vv9UQWKD/Q/81d/FG4CJ /Q5BFXt2+fwAEE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:to:from:subject:message-id:date:mime-version :content-type; s=default; bh=qOk2SQGxhGZ9CDuR+Dg3Xo6+v6Q=; b=wCP QLlkuydYy8/yY+32F5c7KXAK4yRXLvgmCzk/2kC3rFtK1hgaf2dR1NOwHwv3USIi JvLUwvfa4kKckUriJ5WwtW0VsnCLn/Rp1HGC3fXDbMxWG+i/oP4FqkBYODYn8NdM yhvi5M1MrFKNQprJiRjIkJi8bhxUuGiJ648Su4cI= Received: (qmail 11673 invoked by alias); 5 Oct 2015 15:50:47 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 11663 invoked by uid 89); 5 Oct 2015 15:50:46 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.6 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, T_RP_MATCHES_RCVD, URIBL_BLACK autolearn=no version=3.3.2 X-HELO: mx1.redhat.com To: GNU C Library From: Florian Weimer Subject: [PATCH] Add test case for C++11 thread_local support X-Enigmail-Draft-Status: N1110 Message-ID: <56129C50.3020008@redhat.com> Date: Mon, 5 Oct 2015 17:50:40 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.2.0 MIME-Version: 1.0 We did not have a test case which tests the thread_local support functionality with the C++ compiler. I tested this on Fedora 22 (x86_64), Red Hat Enterprise Linux 7 (ppc64), and Debian wheezy (x86_64, after commenting out AVX512 support in the dynamic linker). The latter correctly marks the test case as UNSUPPORTED. Florian From b2d51b5b9152d841f3476d7d5588ce302dad1853 Mon Sep 17 00:00:00 2001 Message-Id: From: Florian Weimer Date: Mon, 5 Oct 2015 17:48:12 +0200 Subject: [PATCH] Add a test case for C++11 thread_local support To: libc-alpha@sourceware.org This requires a C++ compiler with thread_local support, and a new configure check is needed. --- ChangeLog | 12 +++ config.make.in | 1 + configure | 47 +++++++++++ configure.ac | 25 ++++++ nptl/Makefile | 9 ++- nptl/tst-thread_local1.cc | 200 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 nptl/tst-thread_local1.cc diff --git a/ChangeLog b/ChangeLog index 0bfe2bb..804a2a1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2015-10-05 Florian Weimer + + * configure.ac (libc_cv_cxx_thread_local): Define. + * configure: Regenerate. + * config.make.in (have-cxx-thread_local): Define. + * nptl/Makefile (CFLAGS-tst-thread_local1.o): + (LDLIBS-tst-thread_local1): Define. + (tests): Add tst-thread_local1. + [have-cxx-thread_local != yes] (tests-unsupported): Add + tst-thread_local1. + * nptl/tst-thread_local1.cc: New file. + 2015-10-03 Paul Pluzhnikov * sysdeps/x86_64/fpu/libm-test-ulps: Regenerated. diff --git a/config.make.in b/config.make.in index bea371d..839d86f 100644 --- a/config.make.in +++ b/config.make.in @@ -68,6 +68,7 @@ bind-now = @bindnow@ have-hash-style = @libc_cv_hashstyle@ use-default-link = @use_default_link@ output-format = @libc_cv_output_format@ +have-cxx-thread_local = @libc_cv_cxx_thread_local@ static-libgcc = @libc_cv_gcc_static_libgcc@ diff --git a/configure b/configure index fe402ea..0d19d05 100755 --- a/configure +++ b/configure @@ -614,6 +614,7 @@ use_nscd libc_cv_gcc_unwind_find_fde libc_extra_cppflags libc_extra_cflags +libc_cv_cxx_thread_local CPPUNDEFS sizeof_long_double have_selinux @@ -7215,6 +7216,52 @@ if test $libc_cv_builtin_trap = yes; then fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler supports thread_local" >&5 +$as_echo_n "checking whether the C++ compiler supports thread_local... " >&6; } +if ${libc_cv_cxx_thread_local+:} false; then : + $as_echo_n "(cached) " >&6 +else + +old_CXX="$CXX" +CXX="$CXX -std=gnu++11" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +struct S { + S(); + ~S(); +}; +thread_local S s; +S * get() { return &s; } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + libc_cv_cxx_thread_local=yes +else + libc_cv_cxx_thread_local=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CXX="$old_CXX" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cxx_thread_local" >&5 +$as_echo "$libc_cv_cxx_thread_local" >&6; } + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + ### End of automated tests. ### Now run sysdeps configure fragments. diff --git a/configure.ac b/configure.ac index 95d700e..68e6777 100644 --- a/configure.ac +++ b/configure.ac @@ -1982,6 +1982,31 @@ if test $libc_cv_builtin_trap = yes; then AC_DEFINE([HAVE_BUILTIN_TRAP]) fi +dnl C++ feature tests. +AC_LANG_PUSH([C++]) + +AC_CACHE_CHECK([whether the C++ compiler supports thread_local], + libc_cv_cxx_thread_local, [ +old_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS -std=gnu++11" +AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +struct S +{ + S (); + ~S (); +}; +thread_local S s; +S * get () { return &s; } +])], + [libc_cv_cxx_thread_local=yes], + [libc_cv_cxx_thread_local=no]) +CXXFLAGS="$old_CXXFLAGS" +]) +AC_SUBST(libc_cv_cxx_thread_local) + +AC_LANG_POP([C++]) +dnl End of C++ feature tests. + ### End of automated tests. ### Now run sysdeps configure fragments. diff --git a/nptl/Makefile b/nptl/Makefile index aaca0a4..b27bef1 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -212,6 +212,8 @@ CFLAGS-recvfrom.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-pt-system.c = -fexceptions LDLIBS-tst-once5 = -lstdc++ +CFLAGS-tst-thread_local1.o = -std=gnu++11 +LDLIBS-tst-thread_local1 = -lstdc++ tests = tst-typesizes \ tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ @@ -283,7 +285,8 @@ tests = tst-typesizes \ tst-getpid3 \ tst-setuid3 \ tst-initializers1 $(addprefix tst-initializers1-,c89 gnu89 c99 gnu99) \ - tst-bad-schedattr + tst-bad-schedattr \ + tst-thread_local1 xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \ tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 test-srcs = tst-oddstacklimit @@ -403,6 +406,10 @@ ifeq (,$(CXX)) # These tests require a C++ compiler and runtime. tests-unsupported += tst-cancel24 tst-cancel24-static tst-once5 endif +# These tests require a C++ compiler with thread_local support. +ifneq ($(have-cxx-thread_local),yes) +tests-unsupported += tst-thread_local1 +endif include ../Rules diff --git a/nptl/tst-thread_local1.cc b/nptl/tst-thread_local1.cc new file mode 100644 index 0000000..65d374b --- /dev/null +++ b/nptl/tst-thread_local1.cc @@ -0,0 +1,200 @@ +/* Test basic thread_local support. + Copyright (C) 2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 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 + . */ + +#include +#include +#include +#include + +#include +#include +#include + +struct counter +{ + int constructed {}; + int destructed {}; + + void reset (); +}; + +void +counter::reset () +{ + constructed = 0; + destructed = 0; +} + +static std::string +to_string (const counter &c) +{ + char buf[128]; + snprintf (buf, sizeof (buf), "%d/%d", + c.constructed, c.destructed); + return buf; +} + +template +struct counting +{ + counting () __attribute__ ((noinline, noclone)); + ~counting () __attribute__ ((noinline, noclone)); + void operation () __attribute__ ((noinline, noclone)); +}; + +template +__attribute__ ((noinline, noclone)) +counting::counting () +{ + ++Counter->constructed; +} + +template +__attribute__ ((noinline, noclone)) +counting::~counting () +{ + ++Counter->destructed; +} + +template +void __attribute__ ((noinline, noclone)) +counting::operation () +{ + // Optimization barrier. + asm (""); +} + +static counter counter_static; +static counter counter_anonymous_namespace; +static counter counter_extern; +static counter counter_function_local; +static bool errors (false); + +static std::string +all_counters () +{ + return to_string (counter_static) + + ' ' + to_string (counter_anonymous_namespace) + + ' ' + to_string (counter_extern) + + ' ' + to_string (counter_function_local); +} + +static void +check_counters (const char *name, const char *expected) +{ + std::string actual{all_counters ()}; + if (actual != expected) + { + printf ("error: %s: (%s) != (%s)\n", + name, actual.c_str (), expected); + errors = true; + } +} + +static void +reset_all () +{ + counter_static.reset (); + counter_anonymous_namespace.reset (); + counter_extern.reset (); + counter_function_local.reset (); +} + +static thread_local counting<&counter_static> counting_static; +namespace { + thread_local counting<&counter_anonymous_namespace> + counting_anonymous_namespace; +} +extern thread_local counting<&counter_extern> counting_extern; +thread_local counting<&counter_extern> counting_extern; + +static void * +thread_without_access (void *) +{ + return nullptr; +} + +static void * +thread_with_access (void *) +{ + thread_local counting<&counter_function_local> counting_function_local; + counting_function_local.operation (); + check_counters ("early in thread_with_access", "0/0 0/0 0/0 1/0"); + counting_static.operation (); + counting_anonymous_namespace.operation (); + counting_extern.operation (); + check_counters ("in thread_with_access", "1/0 1/0 1/0 1/0"); + return nullptr; +} + +static int +do_test (void) +{ + std::function do_pthread = + [](void *(func) (void *)) + { + pthread_t thr; + int ret = pthread_create (&thr, nullptr, func, nullptr); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_create: %m\n"); + errors = true; + return; + } + ret = pthread_join (thr, nullptr); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_join: %m\n"); + errors = true; + return; + } + }; + std::function do_std_thread = + [](void *(func) (void *)) + { + std::thread thr{[func] {func (nullptr);}}; + thr.join (); + }; + + std::array>, 2> + do_thread_X + {{ + {"pthread_create", do_pthread}, + {"std::thread", do_std_thread}, + }}; + + for (auto do_thread : do_thread_X) + { + printf ("info: testing %s\n", do_thread.first); + check_counters ("initial", "0/0 0/0 0/0 0/0"); + do_thread.second (thread_without_access); + check_counters ("after thread_without_access", "0/0 0/0 0/0 0/0"); + reset_all (); + do_thread.second (thread_with_access); + check_counters ("after thread_with_access", "1/1 1/1 1/1 1/1"); + reset_all (); + } + + return errors; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" -- 2.4.3