Blame nptl/tst-thread_local1.cc

Packit 6c4009
/* Test basic thread_local support.
Packit 6c4009
   Copyright (C) 2015-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <pthread.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
#include <functional>
Packit 6c4009
#include <string>
Packit 6c4009
#include <thread>
Packit 6c4009
Packit 6c4009
struct counter
Packit 6c4009
{
Packit 6c4009
  int constructed {};
Packit 6c4009
  int destructed {};
Packit 6c4009
Packit 6c4009
  void reset ();
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
counter::reset ()
Packit 6c4009
{
Packit 6c4009
  constructed = 0;
Packit 6c4009
  destructed = 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static std::string
Packit 6c4009
to_string (const counter &c)
Packit 6c4009
{
Packit 6c4009
  char buf[128];
Packit 6c4009
  snprintf (buf, sizeof (buf), "%d/%d",
Packit 6c4009
            c.constructed, c.destructed);
Packit 6c4009
  return buf;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
template <counter *Counter>
Packit 6c4009
struct counting
Packit 6c4009
{
Packit 6c4009
  counting () __attribute__ ((noinline, noclone));
Packit 6c4009
  ~counting () __attribute__ ((noinline, noclone));
Packit 6c4009
  void operation () __attribute__ ((noinline, noclone));
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
template<counter *Counter>
Packit 6c4009
__attribute__ ((noinline, noclone))
Packit 6c4009
counting<Counter>::counting ()
Packit 6c4009
{
Packit 6c4009
  ++Counter->constructed;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
template<counter *Counter>
Packit 6c4009
__attribute__ ((noinline, noclone))
Packit 6c4009
counting<Counter>::~counting ()
Packit 6c4009
{
Packit 6c4009
  ++Counter->destructed;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
template<counter *Counter>
Packit 6c4009
void __attribute__ ((noinline, noclone))
Packit 6c4009
counting<Counter>::operation ()
Packit 6c4009
{
Packit 6c4009
  // Optimization barrier.
Packit 6c4009
  asm ("");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static counter counter_static;
Packit 6c4009
static counter counter_anonymous_namespace;
Packit 6c4009
static counter counter_extern;
Packit 6c4009
static counter counter_function_local;
Packit 6c4009
static bool errors (false);
Packit 6c4009
Packit 6c4009
static std::string
Packit 6c4009
all_counters ()
Packit 6c4009
{
Packit 6c4009
  return to_string (counter_static)
Packit 6c4009
    + ' ' + to_string (counter_anonymous_namespace)
Packit 6c4009
    + ' ' + to_string (counter_extern)
Packit 6c4009
    + ' ' + to_string (counter_function_local);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
check_counters (const char *name, const char *expected)
Packit 6c4009
{
Packit 6c4009
  std::string actual{all_counters ()};
Packit 6c4009
  if (actual != expected)
Packit 6c4009
    {
Packit 6c4009
      printf ("error: %s: (%s) != (%s)\n",
Packit 6c4009
              name, actual.c_str (), expected);
Packit 6c4009
      errors = true;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
reset_all ()
Packit 6c4009
{
Packit 6c4009
  counter_static.reset ();
Packit 6c4009
  counter_anonymous_namespace.reset ();
Packit 6c4009
  counter_extern.reset ();
Packit 6c4009
  counter_function_local.reset ();
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static thread_local counting<&counter_static> counting_static;
Packit 6c4009
namespace {
Packit 6c4009
  thread_local counting<&counter_anonymous_namespace>
Packit 6c4009
    counting_anonymous_namespace;
Packit 6c4009
}
Packit 6c4009
extern thread_local counting<&counter_extern> counting_extern;
Packit 6c4009
thread_local counting<&counter_extern> counting_extern;
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
thread_without_access (void *)
Packit 6c4009
{
Packit 6c4009
  return nullptr;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
thread_with_access (void *)
Packit 6c4009
{
Packit 6c4009
  thread_local counting<&counter_function_local> counting_function_local;
Packit 6c4009
  counting_function_local.operation ();
Packit 6c4009
  check_counters ("early in thread_with_access", "0/0 0/0 0/0 1/0");
Packit 6c4009
  counting_static.operation ();
Packit 6c4009
  counting_anonymous_namespace.operation ();
Packit 6c4009
  counting_extern.operation ();
Packit 6c4009
  check_counters ("in thread_with_access", "1/0 1/0 1/0 1/0");
Packit 6c4009
  return nullptr;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  std::function<void (void *(void *))> do_pthread =
Packit 6c4009
    [](void *(func) (void *))
Packit 6c4009
    {
Packit 6c4009
      pthread_t thr;
Packit 6c4009
      int ret = pthread_create (&thr, nullptr, func, nullptr);
Packit 6c4009
      if (ret != 0)
Packit 6c4009
        {
Packit 6c4009
          errno = ret;
Packit 6c4009
          printf ("error: pthread_create: %m\n");
Packit 6c4009
          errors = true;
Packit 6c4009
          return;
Packit 6c4009
        }
Packit 6c4009
      ret = pthread_join (thr, nullptr);
Packit 6c4009
      if (ret != 0)
Packit 6c4009
        {
Packit 6c4009
          errno = ret;
Packit 6c4009
          printf ("error: pthread_join: %m\n");
Packit 6c4009
          errors = true;
Packit 6c4009
          return;
Packit 6c4009
        }
Packit 6c4009
    };
Packit 6c4009
  std::function<void (void *(void *))> do_std_thread =
Packit 6c4009
    [](void *(func) (void *))
Packit 6c4009
    {
Packit 6c4009
      std::thread thr{[func] {func (nullptr);}};
Packit 6c4009
      thr.join ();
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  std::array<std::pair<const char *, std::function<void (void *(void *))>>, 2>
Packit 6c4009
    do_thread_X
Packit 6c4009
      {{
Packit 6c4009
        {"pthread_create", do_pthread},
Packit 6c4009
        {"std::thread", do_std_thread},
Packit 6c4009
      }};
Packit 6c4009
Packit 6c4009
  for (auto do_thread : do_thread_X)
Packit 6c4009
    {
Packit 6c4009
      printf ("info: testing %s\n", do_thread.first);
Packit 6c4009
      check_counters ("initial", "0/0 0/0 0/0 0/0");
Packit 6c4009
      do_thread.second (thread_without_access);
Packit 6c4009
      check_counters ("after thread_without_access", "0/0 0/0 0/0 0/0");
Packit 6c4009
      reset_all ();
Packit 6c4009
      do_thread.second (thread_with_access);
Packit 6c4009
      check_counters ("after thread_with_access", "1/1 1/1 1/1 1/1");
Packit 6c4009
      reset_all ();
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return errors;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"