pty: Activate the signature wrapper of forkpty.
[gnulib.git] / tests / test-tls.c
1 /* Test of thread-local storage in multithreaded situations.
2    Copyright (C) 2005, 2008-2013 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 <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Bruno Haible <bruno@clisp.org>, 2005.  */
18
19 #include <config.h>
20
21 #if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WINDOWS_THREADS
22
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
35
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
39
40 /* Whether to print debugging messages.  */
41 #define ENABLE_DEBUGGING 0
42
43 /* Number of simultaneous threads.  */
44 #define THREAD_COUNT 16
45
46 /* Number of operations performed in each thread.  */
47 #define REPEAT_COUNT 50000
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 #include "glthread/tls.h"
54 #include "glthread/thread.h"
55 #include "glthread/yield.h"
56
57 #if ENABLE_DEBUGGING
58 # define dbgprintf printf
59 #else
60 # define dbgprintf if (0) printf
61 #endif
62
63 #if EXPLICIT_YIELD
64 # define yield() gl_thread_yield ()
65 #else
66 # define yield()
67 #endif
68
69 static void
70 perhaps_yield (void)
71 {
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 ();
76 }
77
78
79 /* ----------------------- Test thread-local storage ----------------------- */
80
81 #define KEYS_COUNT 4
82
83 static gl_tls_key_t mykeys[KEYS_COUNT];
84
85 static void *
86 worker_thread (void *arg)
87 {
88   unsigned int id = (unsigned int) (unsigned long) arg;
89   int i, j, repeat;
90   unsigned int values[KEYS_COUNT];
91
92   dbgprintf ("Worker %p started\n", gl_thread_self_pointer ());
93
94   /* Initialize the per-thread storage.  */
95   for (i = 0; i < KEYS_COUNT; i++)
96     {
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 ();
101     }
102   perhaps_yield ();
103
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 ();
111
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++)
115     {
116       unsigned int *ptr = (unsigned int *) malloc (sizeof (unsigned int));
117       *ptr = values[i];
118       gl_tls_set (mykeys[i], ptr);
119     }
120   dbgprintf ("Worker %p after  first tls_set\n", gl_thread_self_pointer ());
121   perhaps_yield ();
122
123   /* Shuffle around the pointers.  */
124   for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
125     {
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)
130         {
131           void *vi = gl_tls_get (mykeys[i]);
132           void *vj = gl_tls_get (mykeys[j]);
133
134           gl_tls_set (mykeys[i], vj);
135           gl_tls_set (mykeys[j], vi);
136         }
137       perhaps_yield ();
138     }
139
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 ();
147
148   dbgprintf ("Worker %p dying.\n", gl_thread_self_pointer ());
149   return NULL;
150 }
151
152 static void
153 test_tls (void)
154 {
155   int pass, i;
156
157   for (pass = 0; pass < 2; pass++)
158     {
159       gl_thread_t threads[THREAD_COUNT];
160
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);
167
168       /* Spawn the threads.  */
169       for (i = 0; i < THREAD_COUNT; i++)
170         threads[i] = gl_thread_create (worker_thread, NULL);
171
172       /* Wait for the threads to terminate.  */
173       for (i = 0; i < THREAD_COUNT; i++)
174         gl_thread_join (threads[i], NULL);
175
176       for (i = 0; i < KEYS_COUNT; i++)
177         gl_tls_key_destroy (mykeys[i]);
178     }
179 }
180
181
182 /* -------------------------------------------------------------------------- */
183
184 int
185 main ()
186 {
187 #if TEST_PTH_THREADS
188   if (!pth_init ())
189     abort ();
190 #endif
191
192   printf ("Starting test_tls ..."); fflush (stdout);
193   test_tls ();
194   printf (" OK\n"); fflush (stdout);
195
196   return 0;
197 }
198
199 #else
200
201 /* No multithreading available.  */
202
203 #include <stdio.h>
204
205 int
206 main ()
207 {
208   fputs ("Skipping test: multithreading not enabled\n", stderr);
209   return 77;
210 }
211
212 #endif