From 99e1dc0a688d6c25d3f422bc9f3fa29adb483339 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Tue, 6 Oct 2015 21:27:55 +0200 Subject: Add a test case for C++11 thread_local support This requires a C++ compiler with thread_local support, and a new configure check is needed. --- nptl/tst-thread_local1.cc | 199 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 nptl/tst-thread_local1.cc (limited to 'nptl/tst-thread_local1.cc') diff --git a/nptl/tst-thread_local1.cc b/nptl/tst-thread_local1.cc new file mode 100644 index 0000000000..133cc27ca8 --- /dev/null +++ b/nptl/tst-thread_local1.cc @@ -0,0 +1,199 @@ +/* Test basic thread_local support. + Copyright (C) 2015 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 + . */ + +#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" -- cgit 1.4.1