root/maint/gnulib/tests/test-thread_local.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. perhaps_yield
  2. worker_thread
  3. test_thread_local
  4. main
  5. main

   1 /* Test of thread-local storage in multithreaded situations.
   2    Copyright (C) 2005, 2008-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 3 of the License, or
   7    (at your option) any later version.
   8 
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Bruno Haible <bruno@clisp.org>, 2005.  */
  18 
  19 #include <config.h>
  20 
  21 #include <threads.h>
  22 
  23 #ifdef thread_local
  24 
  25 /* Whether to help the scheduler through explicit thrd_yield().
  26    Uncomment this to see if the operating system has a fair scheduler.  */
  27 #define EXPLICIT_YIELD 1
  28 
  29 /* Whether to print debugging messages.  */
  30 #define ENABLE_DEBUGGING 0
  31 
  32 /* Number of simultaneous threads.  */
  33 #define THREAD_COUNT 16
  34 
  35 /* Number of operations performed in each thread.  */
  36 #define REPEAT_COUNT 50000
  37 
  38 #include <stdint.h>
  39 #include <stdio.h>
  40 #include <stdlib.h>
  41 
  42 #if HAVE_DECL_ALARM
  43 # include <signal.h>
  44 # include <unistd.h>
  45 #endif
  46 
  47 #include "macros.h"
  48 
  49 #if ENABLE_DEBUGGING
  50 # define dbgprintf printf
  51 #else
  52 # define dbgprintf if (0) printf
  53 #endif
  54 
  55 #if EXPLICIT_YIELD
  56 # define yield() thrd_yield ()
  57 #else
  58 # define yield()
  59 #endif
  60 
  61 /* Returns a reference to the current thread as a pointer, for debugging.  */
  62 #if defined __MVS__
  63   /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field.
  64      The first three bytes of this field appear to uniquely identify a
  65      pthread_t, though not necessarily representing a pointer.  */
  66 # define thrd_current_pointer() (*((void **) thrd_current ().__))
  67 #elif defined __sun
  68   /* On Solaris, thrd_t is merely an 'unsigned int'.  */
  69 # define thrd_current_pointer() ((void *) (uintptr_t) thrd_current ())
  70 #else
  71 # define thrd_current_pointer() ((void *) thrd_current ())
  72 #endif
  73 
  74 static void
  75 perhaps_yield (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77   /* Call yield () only with a certain probability, otherwise the
  78      sequence of thread activations may be too predictable.  */
  79   if ((((unsigned int) rand () >> 3) % 4) == 0)
  80     yield ();
  81 }
  82 
  83 
  84 /* ----------------------- Test thread-local storage ----------------------- */
  85 
  86 #define KEYS_COUNT 4
  87 static unsigned int thread_local value0;
  88 static unsigned int thread_local value1;
  89 static unsigned int thread_local value2;
  90 static unsigned int thread_local value3;
  91 
  92 static int
  93 worker_thread (void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  94 {
  95   unsigned int id = (unsigned int) (uintptr_t) arg;
  96   int i, j, repeat;
  97   unsigned int *values[KEYS_COUNT] = { &value0, &value1, &value2, &value3 };
  98 
  99   dbgprintf ("Worker %p started\n", thrd_current_pointer ());
 100 
 101   /* Initialize the per-thread storage.  */
 102   dbgprintf ("Worker %p before first assignment\n", thrd_current_pointer ());
 103   for (i = 0; i < KEYS_COUNT; i++)
 104     {
 105       *values[i] = (((unsigned int) rand () >> 3) % 1000000) * THREAD_COUNT + id;
 106       /* Hopefully no arithmetic overflow.  */
 107       if ((*values[i] % THREAD_COUNT) != id)
 108         abort ();
 109     }
 110   dbgprintf ("Worker %p after  first assignment\n", thrd_current_pointer ());
 111   perhaps_yield ();
 112 
 113   /* Shuffle around the pointers.  */
 114   for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
 115     {
 116       dbgprintf ("Worker %p doing value swapping\n", thrd_current_pointer ());
 117       i = ((unsigned int) rand () >> 3) % KEYS_COUNT;
 118       j = ((unsigned int) rand () >> 3) % KEYS_COUNT;
 119       if (i != j)
 120         {
 121           unsigned int vi = *values[i];
 122           unsigned int vj = *values[j];
 123 
 124           *values[i] = vj;
 125           *values[j] = vi;
 126         }
 127       perhaps_yield ();
 128     }
 129 
 130   /* Verify that all the values are from this thread.  */
 131   dbgprintf ("Worker %p before final verify\n", thrd_current_pointer ());
 132   for (i = 0; i < KEYS_COUNT; i++)
 133     if ((*values[i] % THREAD_COUNT) != id)
 134       abort ();
 135   dbgprintf ("Worker %p after  final verify\n", thrd_current_pointer ());
 136   perhaps_yield ();
 137 
 138   dbgprintf ("Worker %p dying.\n", thrd_current_pointer ());
 139   return 0;
 140 }
 141 
 142 static void
 143 test_thread_local (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 144 {
 145   int pass, i;
 146 
 147   for (pass = 0; pass < 2; pass++)
 148     {
 149       thrd_t threads[THREAD_COUNT];
 150 
 151       /* Spawn the threads.  */
 152       for (i = 0; i < THREAD_COUNT; i++)
 153         ASSERT (thrd_create (&threads[i], worker_thread, (void *) (uintptr_t) i)
 154                 == thrd_success);
 155 
 156       /* Wait for the threads to terminate.  */
 157       for (i = 0; i < THREAD_COUNT; i++)
 158         ASSERT (thrd_join (threads[i], NULL) == thrd_success);
 159     }
 160 }
 161 
 162 
 163 /* -------------------------------------------------------------------------- */
 164 
 165 int
 166 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168 #if HAVE_DECL_ALARM
 169   /* Declare failure if test takes too long, by using default abort
 170      caused by SIGALRM.  */
 171   int alarm_value = 600;
 172   signal (SIGALRM, SIG_DFL);
 173   alarm (alarm_value);
 174 #endif
 175 
 176   printf ("Starting test_thread_local ..."); fflush (stdout);
 177   test_thread_local ();
 178   printf (" OK\n"); fflush (stdout);
 179 
 180   return 0;
 181 }
 182 
 183 #else
 184 
 185 /* No thread-local storage support available in the compiler and linker.  */
 186 
 187 #include <stdio.h>
 188 
 189 int
 190 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 191 {
 192   fputs ("Skipping test: thread_local not supported\n", stderr);
 193   return 77;
 194 }
 195 
 196 #endif

/* [previous][next][first][last][top][bottom][index][help] */