maint.mk: Update system header list for #include syntax checks.
[gnulib.git] / tests / test-random-mt.c
blob4e2f2d378e93bbdfc0893437f19ef1fb4310b4e0
1 /* Multithread-safety test for random().
2 Copyright (C) 2023-2024 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>, 2023. */
19 #include <config.h>
21 #if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
23 /* Whether to help the scheduler through explicit yield().
24 Uncomment this to see if the operating system has a fair scheduler. */
25 #define EXPLICIT_YIELD 1
27 /* Number of simultaneous threads. */
28 #define THREAD_COUNT 4
30 /* Number of random() invocations operations performed in each thread.
31 This value is chosen so that the unit test terminates quickly.
32 To reliably determine whether a random() implementation is multithread-safe,
33 set REPEAT_COUNT to 1000000 and run the test 100 times:
34 $ for i in `seq 100`; do ./test-random-mt; done
36 #define REPEAT_COUNT 100000
38 /* Specification. */
39 #include <stdlib.h>
41 #include <stdio.h>
43 #if EXPLICIT_YIELD
44 # include <sched.h>
45 #endif
47 #include "glthread/thread.h"
48 #include "xalloc.h"
50 #if EXPLICIT_YIELD
51 # define yield() sched_yield ()
52 #else
53 # define yield()
54 #endif
56 /* This test runs REPEAT_COUNT invocations of random() in each thread and stores
57 the result, then compares the first REPEAT_COUNT among these
58 THREAD_COUNT * REPEAT_COUNT
59 random numbers against a precomputed sequence with the same seed. */
61 static void *
62 random_invocator_thread (void *arg)
64 long *storage = (long *) arg;
65 int repeat;
67 for (repeat = 0; repeat < REPEAT_COUNT; repeat++)
69 storage[repeat] = random ();
70 yield ();
73 return NULL;
76 int
77 main ()
79 unsigned int seed = 19891109;
81 /* First, get the expected sequence of random() results. */
82 srandom (seed);
83 long *expected = XNMALLOC (REPEAT_COUNT, long);
85 int repeat;
86 for (repeat = 0; repeat < REPEAT_COUNT; repeat++)
87 expected[repeat] = random ();
90 /* Then, run REPEAT_COUNT invocations of random() each, in THREAD_COUNT
91 separate threads. */
92 gl_thread_t threads[THREAD_COUNT];
93 long *thread_results[THREAD_COUNT];
94 srandom (seed);
96 int i;
97 for (i = 0; i < THREAD_COUNT; i++)
98 thread_results[i] = XNMALLOC (REPEAT_COUNT, long);
99 for (i = 0; i < THREAD_COUNT; i++)
100 threads[i] =
101 gl_thread_create (random_invocator_thread, thread_results[i]);
104 /* Wait for the threads to terminate. */
106 int i;
107 for (i = 0; i < THREAD_COUNT; i++)
108 gl_thread_join (threads[i], NULL);
111 /* Finally, determine whether the threads produced the same sequence of
112 random() results. */
114 int expected_index;
115 int result_index[THREAD_COUNT];
116 int i;
118 for (i = 0; i < THREAD_COUNT; i++)
119 result_index[i] = 0;
121 for (expected_index = 0; expected_index < REPEAT_COUNT; expected_index++)
123 long expected_value = expected[expected_index];
125 for (i = 0; i < THREAD_COUNT; i++)
127 if (thread_results[i][result_index[i]] == expected_value)
129 result_index[i]++;
130 break;
133 if (i == THREAD_COUNT)
135 if (expected_index == 0)
137 /* This occurs on platforms like OpenBSD, where srandom() has no
138 effect and random() always return non-deterministic values.
139 Mark the test as SKIP. */
140 fprintf (stderr, "Skipping test: random() is non-deterministic.\n");
141 return 77;
143 else
145 fprintf (stderr, "Expected value #%d not found in multithreaded results.\n",
146 expected_index);
147 return 1;
153 return 0;
156 #else
158 /* No multithreading available. */
160 #include <stdio.h>
163 main ()
165 fputs ("Skipping test: multithreading not enabled\n", stderr);
166 return 77;
169 #endif