• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/gnulib-tests/
1/* Test of thread-local storage in multithreaded situations.
2   Copyright (C) 2005 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_WIN32_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_WIN32_THREADS
33# define TEST_WIN32_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 "tls.h"
54
55#if ENABLE_DEBUGGING
56# define dbgprintf printf
57#else
58# define dbgprintf if (0) printf
59#endif
60
61#if TEST_POSIX_THREADS
62# include <pthread.h>
63# include <sched.h>
64typedef pthread_t gl_thread_t;
65static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
66{
67  pthread_t thread;
68  if (pthread_create (&thread, NULL, func, arg) != 0)
69    abort ();
70  return thread;
71}
72static inline void gl_thread_join (gl_thread_t thread)
73{
74  void *retval;
75  if (pthread_join (thread, &retval) != 0)
76    abort ();
77}
78static inline void gl_thread_yield (void)
79{
80  sched_yield ();
81}
82static inline void * gl_thread_self (void)
83{
84  return (void *) pthread_self ();
85}
86#endif
87#if TEST_PTH_THREADS
88# include <pth.h>
89typedef pth_t gl_thread_t;
90static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
91{
92  pth_t thread = pth_spawn (NULL, func, arg);
93  if (thread == NULL)
94    abort ();
95  return thread;
96}
97static inline void gl_thread_join (gl_thread_t thread)
98{
99  if (!pth_join (thread, NULL))
100    abort ();
101}
102static inline void gl_thread_yield (void)
103{
104  pth_yield (NULL);
105}
106static inline void * gl_thread_self (void)
107{
108  return pth_self ();
109}
110#endif
111#if TEST_SOLARIS_THREADS
112# include <thread.h>
113typedef thread_t gl_thread_t;
114static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
115{
116  thread_t thread;
117  if (thr_create (NULL, 0, func, arg, 0, &thread) != 0)
118    abort ();
119  return thread;
120}
121static inline void gl_thread_join (gl_thread_t thread)
122{
123  void *retval;
124  if (thr_join (thread, NULL, &retval) != 0)
125    abort ();
126}
127static inline void gl_thread_yield (void)
128{
129  thr_yield ();
130}
131static inline void * gl_thread_self (void)
132{
133  return (void *) thr_self ();
134}
135#endif
136#if TEST_WIN32_THREADS
137# include <windows.h>
138typedef HANDLE gl_thread_t;
139/* Use a wrapper function, instead of adding WINAPI through a cast.  */
140struct wrapper_args { void * (*func) (void *); void *arg; };
141static DWORD WINAPI wrapper_func (void *varg)
142{
143  struct wrapper_args *warg = (struct wrapper_args *)varg;
144  void * (*func) (void *) = warg->func;
145  void *arg = warg->arg;
146  free (warg);
147  func (arg);
148  return 0;
149}
150static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
151{
152  struct wrapper_args *warg =
153    (struct wrapper_args *) malloc (sizeof (struct wrapper_args));
154  if (warg == NULL)
155    abort ();
156  warg->func = func;
157  warg->arg = arg;
158  {
159    DWORD thread_id;
160    HANDLE thread =
161      CreateThread (NULL, 100000, wrapper_func, warg, 0, &thread_id);
162    if (thread == NULL)
163      abort ();
164    return thread;
165  }
166}
167static inline void gl_thread_join (gl_thread_t thread)
168{
169  if (WaitForSingleObject (thread, INFINITE) == WAIT_FAILED)
170    abort ();
171  if (!CloseHandle (thread))
172    abort ();
173}
174static inline void gl_thread_yield (void)
175{
176  Sleep (0);
177}
178static inline void * gl_thread_self (void)
179{
180  return (void *) GetCurrentThreadId ();
181}
182#endif
183#if EXPLICIT_YIELD
184# define yield() gl_thread_yield ()
185#else
186# define yield()
187#endif
188
189static inline void
190perhaps_yield (void)
191{
192  /* Call yield () only with a certain probability, otherwise with GNU Pth
193     the sequence of thread activations is too predictable.  */
194  if ((((unsigned int) rand () >> 3) % 4) == 0)
195    yield ();
196}
197
198#define KEYS_COUNT 4
199
200static gl_tls_key_t mykeys[KEYS_COUNT];
201
202static void *
203worker_thread (void *arg)
204{
205  unsigned int id = (unsigned int) (unsigned long) arg;
206  int i, j, repeat;
207  unsigned int values[KEYS_COUNT];
208
209  dbgprintf ("Worker %p started\n", gl_thread_self ());
210
211  /* Initialize the per-thread storage.  */
212  for (i = 0; i < KEYS_COUNT; i++)
213    {
214      values[i] = (((unsigned int) rand() >> 3) % 1000000) * THREAD_COUNT + id;
215      /* Hopefully no arithmetic overflow.  */
216      if ((values[i] % THREAD_COUNT) != id)
217	abort ();
218    }
219  perhaps_yield ();
220
221  /* Verify that the initial value is NULL.  */
222  dbgprintf ("Worker %p before initial verify\n", gl_thread_self ());
223  for (i = 0; i < KEYS_COUNT; i++)
224    if (gl_tls_get (mykeys[i]) != NULL)
225      abort ();
226  dbgprintf ("Worker %p after  initial verify\n", gl_thread_self ());
227  perhaps_yield ();
228
229  /* Initialize the per-thread storage.  */
230  dbgprintf ("Worker %p before first tls_set\n", gl_thread_self ());
231  for (i = 0; i < KEYS_COUNT; i++)
232    {
233      unsigned int *ptr = (unsigned int *) malloc (sizeof (unsigned int));
234      *ptr = values[i];
235      gl_tls_set (mykeys[i], ptr);
236    }
237  dbgprintf ("Worker %p after  first tls_set\n", gl_thread_self ());
238  perhaps_yield ();
239
240  /* Shuffle around the pointers.  */
241  for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
242    {
243      dbgprintf ("Worker %p doing value swapping\n", gl_thread_self ());
244      i = ((unsigned int) rand() >> 3) % KEYS_COUNT;
245      j = ((unsigned int) rand() >> 3) % KEYS_COUNT;
246      if (i != j)
247	{
248	  void *vi = gl_tls_get (mykeys[i]);
249	  void *vj = gl_tls_get (mykeys[j]);
250
251	  gl_tls_set (mykeys[i], vj);
252	  gl_tls_set (mykeys[j], vi);
253	}
254      perhaps_yield ();
255    }
256
257  /* Verify that all the values are from this thread.  */
258  dbgprintf ("Worker %p before final verify\n", gl_thread_self ());
259  for (i = 0; i < KEYS_COUNT; i++)
260    if ((*(unsigned int *) gl_tls_get (mykeys[i]) % THREAD_COUNT) != id)
261      abort ();
262  dbgprintf ("Worker %p after  final verify\n", gl_thread_self ());
263  perhaps_yield ();
264
265  dbgprintf ("Worker %p dying.\n", gl_thread_self ());
266  return NULL;
267}
268
269void
270test_tls (void)
271{
272  int pass, i;
273
274  for (pass = 0; pass < 2; pass++)
275    {
276      gl_thread_t threads[THREAD_COUNT];
277
278      if (pass == 0)
279	for (i = 0; i < KEYS_COUNT; i++)
280	  gl_tls_key_init (mykeys[i], free);
281      else
282	for (i = KEYS_COUNT - 1; i >= 0; i--)
283	  gl_tls_key_init (mykeys[i], free);
284
285      /* Spawn the threads.  */
286      for (i = 0; i < THREAD_COUNT; i++)
287	threads[i] = gl_thread_create (worker_thread, NULL);
288
289      /* Wait for the threads to terminate.  */
290      for (i = 0; i < THREAD_COUNT; i++)
291	gl_thread_join (threads[i]);
292
293      for (i = 0; i < KEYS_COUNT; i++)
294	gl_tls_key_destroy (mykeys[i]);
295    }
296}
297
298int
299main ()
300{
301#if TEST_PTH_THREADS
302  if (!pth_init ())
303    abort ();
304#endif
305
306  printf ("Starting test_tls ..."); fflush (stdout);
307  test_tls ();
308  printf (" OK\n"); fflush (stdout);
309
310  return 0;
311}
312
313#else
314
315/* No multithreading available.  */
316
317int
318main ()
319{
320  return 77;
321}
322
323#endif
324