Blame elf/tst-tls-manydynamic.c

Packit 6c4009
/* Test with many dynamic TLS variables.
Packit 6c4009
   Copyright (C) 2016-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
/* This test intends to exercise dynamic TLS variable allocation.  It
Packit 6c4009
   achieves this by combining dlopen (to avoid static TLS allocation
Packit 6c4009
   after static TLS resizing), many DSOs with a large variable (to
Packit 6c4009
   exceed the static TLS reserve), and an already-running thread (to
Packit 6c4009
   force full dynamic TLS initialization).  */
Packit 6c4009
Packit 6c4009
#include "tst-tls-manydynamic.h"
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <pthread.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
static int do_test (void);
Packit 6c4009
#include <support/xthread.h>
Packit 6c4009
#include <support/test-driver.c>
Packit 6c4009
Packit 6c4009
void *handles[COUNT];
Packit 6c4009
set_value_func set_value_funcs[COUNT];
Packit 6c4009
get_value_func get_value_funcs[COUNT];
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
init_functions (void)
Packit 6c4009
{
Packit 6c4009
  for (int i = 0; i < COUNT; ++i)
Packit 6c4009
    {
Packit 6c4009
      /* Open the module.  */
Packit 6c4009
      {
Packit 6c4009
        char soname[100];
Packit 6c4009
        snprintf (soname, sizeof (soname), "tst-tls-manydynamic%02dmod.so", i);
Packit 6c4009
        handles[i] = dlopen (soname, RTLD_LAZY);
Packit 6c4009
        if (handles[i] == NULL)
Packit 6c4009
          {
Packit 6c4009
            printf ("error: dlopen failed: %s\n", dlerror ());
Packit 6c4009
            exit (1);
Packit 6c4009
          }
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
      /* Obtain the setter function.  */
Packit 6c4009
      {
Packit 6c4009
        char fname[100];
Packit 6c4009
        snprintf (fname, sizeof (fname), "set_value_%02d", i);
Packit 6c4009
        void *func = dlsym (handles[i], fname);
Packit 6c4009
        if (func == NULL)
Packit 6c4009
          {
Packit 6c4009
            printf ("error: dlsym: %s\n", dlerror ());
Packit 6c4009
            exit (1);
Packit 6c4009
          }
Packit 6c4009
        set_value_funcs[i] = func;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
      /* Obtain the getter function.  */
Packit 6c4009
      {
Packit 6c4009
        char fname[100];
Packit 6c4009
        snprintf (fname, sizeof (fname), "get_value_%02d", i);
Packit 6c4009
        void *func = dlsym (handles[i], fname);
Packit 6c4009
        if (func == NULL)
Packit 6c4009
          {
Packit 6c4009
            printf ("error: dlsym: %s\n", dlerror ());
Packit 6c4009
            exit (1);
Packit 6c4009
          }
Packit 6c4009
        get_value_funcs[i] = func;
Packit 6c4009
      }
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static pthread_barrier_t barrier;
Packit 6c4009
Packit 6c4009
/* Running thread which forces real TLS initialization.  */
Packit 6c4009
static void *
Packit 6c4009
blocked_thread_func (void *closure)
Packit 6c4009
{
Packit 6c4009
  xpthread_barrier_wait (&barrier);
Packit 6c4009
Packit 6c4009
  /* TLS test runs here in the main thread.  */
Packit 6c4009
Packit 6c4009
  xpthread_barrier_wait (&barrier);
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  {
Packit 6c4009
    int ret = pthread_barrier_init (&barrier, NULL, 2);
Packit 6c4009
    if (ret != 0)
Packit 6c4009
      {
Packit 6c4009
        errno = ret;
Packit 6c4009
        printf ("error: pthread_barrier_init: %m\n");
Packit 6c4009
        exit (1);
Packit 6c4009
      }
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL);
Packit 6c4009
  xpthread_barrier_wait (&barrier);
Packit 6c4009
Packit 6c4009
  init_functions ();
Packit 6c4009
Packit 6c4009
  struct value values[COUNT];
Packit 6c4009
  /* Initialze the TLS variables.  */
Packit 6c4009
  for (int i = 0; i < COUNT; ++i)
Packit 6c4009
    {
Packit 6c4009
      for (int j = 0; j < PER_VALUE_COUNT; ++j)
Packit 6c4009
        values[i].num[j] = rand ();
Packit 6c4009
      set_value_funcs[i] (&values[i]);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Read back their values to check that they do not overlap.  */
Packit 6c4009
  for (int i = 0; i < COUNT; ++i)
Packit 6c4009
    {
Packit 6c4009
      struct value actual;
Packit 6c4009
      get_value_funcs[i] (&actual);
Packit 6c4009
Packit 6c4009
      for (int j = 0; j < PER_VALUE_COUNT; ++j)
Packit 6c4009
        if (actual.num[j] != values[i].num[j])
Packit 6c4009
        {
Packit 6c4009
          printf ("error: mismatch at variable %d/%d: %d != %d\n",
Packit 6c4009
                  i, j, actual.num[j], values[i].num[j]);
Packit 6c4009
          exit (1);
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  xpthread_barrier_wait (&barrier);
Packit 6c4009
  xpthread_join (blocked_thread);
Packit 6c4009
Packit 6c4009
  /* Close the modules.  */
Packit 6c4009
  for (int i = 0; i < COUNT; ++i)
Packit 6c4009
    dlclose (handles[i]);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}