expl: Work around inaccurate implementation on NetBSD.
[gnulib.git] / tests / test-tls.c
blobb2066b3eccc20d3e5f9d42efb47cebe16ff2565e
1 /* Test of thread-local storage in multithreaded situations.
2 Copyright (C) 2005, 2008-2019 Free Software Foundation, Inc.
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.
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.
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/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2005. */
19 #include <config.h>
21 #if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WINDOWS_THREADS
23 #if USE_POSIX_THREADS
24 # define TEST_POSIX_THREADS 1
25 #endif
26 #if USE_SOLARIS_THREADS
27 # define TEST_SOLARIS_THREADS 1
28 #endif
29 #if USE_PTH_THREADS
30 # define TEST_PTH_THREADS 1
31 #endif
32 #if USE_WINDOWS_THREADS
33 # define TEST_WINDOWS_THREADS 1
34 #endif
36 /* Whether to help the scheduler through explicit yield().
37 Uncomment this to see if the operating system has a fair scheduler. */
38 #define EXPLICIT_YIELD 1
40 /* Whether to print debugging messages. */
41 #define ENABLE_DEBUGGING 0
43 /* Number of simultaneous threads. */
44 #define THREAD_COUNT 16
46 /* Number of operations performed in each thread. */
47 #define REPEAT_COUNT 50000
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
53 #include "glthread/tls.h"
54 #include "glthread/thread.h"
55 #include "glthread/yield.h"
57 #if ENABLE_DEBUGGING
58 # define dbgprintf printf
59 #else
60 # define dbgprintf if (0) printf
61 #endif
63 #if EXPLICIT_YIELD
64 # define yield() gl_thread_yield ()
65 #else
66 # define yield()
67 #endif
69 static void
70 perhaps_yield (void)
72 /* Call yield () only with a certain probability, otherwise with GNU Pth
73 the sequence of thread activations is too predictable. */
74 if ((((unsigned int) rand () >> 3) % 4) == 0)
75 yield ();
79 /* ----------------------- Test thread-local storage ----------------------- */
81 #define KEYS_COUNT 4
83 static gl_tls_key_t mykeys[KEYS_COUNT];
85 static void *
86 worker_thread (void *arg)
88 unsigned int id = (unsigned int) (unsigned long) arg;
89 int i, j, repeat;
90 unsigned int values[KEYS_COUNT];
92 dbgprintf ("Worker %p started\n", gl_thread_self_pointer ());
94 /* Initialize the per-thread storage. */
95 for (i = 0; i < KEYS_COUNT; i++)
97 values[i] = (((unsigned int) rand () >> 3) % 1000000) * THREAD_COUNT + id;
98 /* Hopefully no arithmetic overflow. */
99 if ((values[i] % THREAD_COUNT) != id)
100 abort ();
102 perhaps_yield ();
104 /* Verify that the initial value is NULL. */
105 dbgprintf ("Worker %p before initial verify\n", gl_thread_self_pointer ());
106 for (i = 0; i < KEYS_COUNT; i++)
107 if (gl_tls_get (mykeys[i]) != NULL)
108 abort ();
109 dbgprintf ("Worker %p after initial verify\n", gl_thread_self_pointer ());
110 perhaps_yield ();
112 /* Initialize the per-thread storage. */
113 dbgprintf ("Worker %p before first tls_set\n", gl_thread_self_pointer ());
114 for (i = 0; i < KEYS_COUNT; i++)
116 unsigned int *ptr = (unsigned int *) malloc (sizeof (unsigned int));
117 *ptr = values[i];
118 gl_tls_set (mykeys[i], ptr);
120 dbgprintf ("Worker %p after first tls_set\n", gl_thread_self_pointer ());
121 perhaps_yield ();
123 /* Shuffle around the pointers. */
124 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
126 dbgprintf ("Worker %p doing value swapping\n", gl_thread_self_pointer ());
127 i = ((unsigned int) rand () >> 3) % KEYS_COUNT;
128 j = ((unsigned int) rand () >> 3) % KEYS_COUNT;
129 if (i != j)
131 void *vi = gl_tls_get (mykeys[i]);
132 void *vj = gl_tls_get (mykeys[j]);
134 gl_tls_set (mykeys[i], vj);
135 gl_tls_set (mykeys[j], vi);
137 perhaps_yield ();
140 /* Verify that all the values are from this thread. */
141 dbgprintf ("Worker %p before final verify\n", gl_thread_self_pointer ());
142 for (i = 0; i < KEYS_COUNT; i++)
143 if ((*(unsigned int *) gl_tls_get (mykeys[i]) % THREAD_COUNT) != id)
144 abort ();
145 dbgprintf ("Worker %p after final verify\n", gl_thread_self_pointer ());
146 perhaps_yield ();
148 dbgprintf ("Worker %p dying.\n", gl_thread_self_pointer ());
149 return NULL;
152 static void
153 test_tls (void)
155 int pass, i;
157 for (pass = 0; pass < 2; pass++)
159 gl_thread_t threads[THREAD_COUNT];
161 if (pass == 0)
162 for (i = 0; i < KEYS_COUNT; i++)
163 gl_tls_key_init (mykeys[i], free);
164 else
165 for (i = KEYS_COUNT - 1; i >= 0; i--)
166 gl_tls_key_init (mykeys[i], free);
168 /* Spawn the threads. */
169 for (i = 0; i < THREAD_COUNT; i++)
170 threads[i] = gl_thread_create (worker_thread, NULL);
172 /* Wait for the threads to terminate. */
173 for (i = 0; i < THREAD_COUNT; i++)
174 gl_thread_join (threads[i], NULL);
176 for (i = 0; i < KEYS_COUNT; i++)
177 gl_tls_key_destroy (mykeys[i]);
182 /* -------------------------------------------------------------------------- */
185 main ()
187 #if TEST_PTH_THREADS
188 if (!pth_init ())
189 abort ();
190 #endif
192 printf ("Starting test_tls ..."); fflush (stdout);
193 test_tls ();
194 printf (" OK\n"); fflush (stdout);
196 return 0;
199 #else
201 /* No multithreading available. */
203 #include <stdio.h>
206 main ()
208 fputs ("Skipping test: multithreading not enabled\n", stderr);
209 return 77;
212 #endif