(root)/
glibc-2.38/
elf/
tst-tls-manydynamic.c
       1  /* Test with many dynamic TLS variables.
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  /* This test intends to exercise dynamic TLS variable allocation.  It
      20     achieves this by combining dlopen (to avoid static TLS allocation
      21     after static TLS resizing), many DSOs with a large variable (to
      22     exceed the static TLS reserve), and an already-running thread (to
      23     force full dynamic TLS initialization).  */
      24  
      25  #include "tst-tls-manydynamic.h"
      26  
      27  #include <errno.h>
      28  #include <dlfcn.h>
      29  #include <pthread.h>
      30  #include <stdio.h>
      31  #include <stdlib.h>
      32  #include <string.h>
      33  
      34  static int do_test (void);
      35  #include <support/xthread.h>
      36  #include <support/test-driver.c>
      37  
      38  void *handles[COUNT];
      39  set_value_func set_value_funcs[COUNT];
      40  get_value_func get_value_funcs[COUNT];
      41  
      42  static void
      43  init_functions (void)
      44  {
      45    for (int i = 0; i < COUNT; ++i)
      46      {
      47        /* Open the module.  */
      48        {
      49          char soname[100];
      50          snprintf (soname, sizeof (soname), "tst-tls-manydynamic%02dmod.so", i);
      51          handles[i] = dlopen (soname, RTLD_LAZY);
      52          if (handles[i] == NULL)
      53            {
      54              printf ("error: dlopen failed: %s\n", dlerror ());
      55              exit (1);
      56            }
      57        }
      58  
      59        /* Obtain the setter function.  */
      60        {
      61          char fname[100];
      62          snprintf (fname, sizeof (fname), "set_value_%02d", i);
      63          void *func = dlsym (handles[i], fname);
      64          if (func == NULL)
      65            {
      66              printf ("error: dlsym: %s\n", dlerror ());
      67              exit (1);
      68            }
      69          set_value_funcs[i] = func;
      70        }
      71  
      72        /* Obtain the getter function.  */
      73        {
      74          char fname[100];
      75          snprintf (fname, sizeof (fname), "get_value_%02d", i);
      76          void *func = dlsym (handles[i], fname);
      77          if (func == NULL)
      78            {
      79              printf ("error: dlsym: %s\n", dlerror ());
      80              exit (1);
      81            }
      82          get_value_funcs[i] = func;
      83        }
      84      }
      85  }
      86  
      87  static pthread_barrier_t barrier;
      88  
      89  /* Running thread which forces real TLS initialization.  */
      90  static void *
      91  blocked_thread_func (void *closure)
      92  {
      93    xpthread_barrier_wait (&barrier);
      94  
      95    /* TLS test runs here in the main thread.  */
      96  
      97    xpthread_barrier_wait (&barrier);
      98    return NULL;
      99  }
     100  
     101  static int
     102  do_test (void)
     103  {
     104    {
     105      int ret = pthread_barrier_init (&barrier, NULL, 2);
     106      if (ret != 0)
     107        {
     108          errno = ret;
     109          printf ("error: pthread_barrier_init: %m\n");
     110          exit (1);
     111        }
     112    }
     113  
     114    pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL);
     115    xpthread_barrier_wait (&barrier);
     116  
     117    init_functions ();
     118  
     119    struct value values[COUNT];
     120    /* Initialize the TLS variables.  */
     121    for (int i = 0; i < COUNT; ++i)
     122      {
     123        for (int j = 0; j < PER_VALUE_COUNT; ++j)
     124          values[i].num[j] = rand ();
     125        set_value_funcs[i] (&values[i]);
     126      }
     127  
     128    /* Read back their values to check that they do not overlap.  */
     129    for (int i = 0; i < COUNT; ++i)
     130      {
     131        struct value actual;
     132        get_value_funcs[i] (&actual);
     133  
     134        for (int j = 0; j < PER_VALUE_COUNT; ++j)
     135          if (actual.num[j] != values[i].num[j])
     136          {
     137            printf ("error: mismatch at variable %d/%d: %d != %d\n",
     138                    i, j, actual.num[j], values[i].num[j]);
     139            exit (1);
     140          }
     141      }
     142  
     143    xpthread_barrier_wait (&barrier);
     144    xpthread_join (blocked_thread);
     145  
     146    /* Close the modules.  */
     147    for (int i = 0; i < COUNT; ++i)
     148      dlclose (handles[i]);
     149  
     150    return 0;
     151  }