Hash :
7b089321
Author :
Date :
2025-01-01T09:24:36
maint: run 'make update-copyright'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
/* Multithread-safety test for random().
Copyright (C) 2023-2025 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
#include <config.h>
#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
/* Whether to help the scheduler through explicit yield().
Uncomment this to see if the operating system has a fair scheduler. */
#define EXPLICIT_YIELD 1
/* Number of simultaneous threads. */
#define THREAD_COUNT 4
/* Number of random() invocations operations performed in each thread.
This value is chosen so that the unit test terminates quickly.
To reliably determine whether a random() implementation is multithread-safe,
set REPEAT_COUNT to 1000000 and run the test 100 times:
$ for i in `seq 100`; do ./test-random-mt; done
*/
#define REPEAT_COUNT 100000
/* Specification. */
#include <stdlib.h>
#include <stdio.h>
#if EXPLICIT_YIELD
# include <sched.h>
#endif
#include "glthread/thread.h"
#include "xalloc.h"
#if EXPLICIT_YIELD
# define yield() sched_yield ()
#else
# define yield()
#endif
/* This test runs REPEAT_COUNT invocations of random() in each thread and stores
the result, then compares the first REPEAT_COUNT among these
THREAD_COUNT * REPEAT_COUNT
random numbers against a precomputed sequence with the same seed. */
static void *
random_invocator_thread (void *arg)
{
long *storage = (long *) arg;
int repeat;
for (repeat = 0; repeat < REPEAT_COUNT; repeat++)
{
storage[repeat] = random ();
yield ();
}
return NULL;
}
int
main ()
{
unsigned int seed = 19891109;
/* First, get the expected sequence of random() results. */
srandom (seed);
long *expected = XNMALLOC (REPEAT_COUNT, long);
{
int repeat;
for (repeat = 0; repeat < REPEAT_COUNT; repeat++)
expected[repeat] = random ();
}
/* Then, run REPEAT_COUNT invocations of random() each, in THREAD_COUNT
separate threads. */
gl_thread_t threads[THREAD_COUNT];
long *thread_results[THREAD_COUNT];
srandom (seed);
{
int i;
for (i = 0; i < THREAD_COUNT; i++)
thread_results[i] = XNMALLOC (REPEAT_COUNT, long);
for (i = 0; i < THREAD_COUNT; i++)
threads[i] =
gl_thread_create (random_invocator_thread, thread_results[i]);
}
/* Wait for the threads to terminate. */
{
int i;
for (i = 0; i < THREAD_COUNT; i++)
gl_thread_join (threads[i], NULL);
}
/* Finally, determine whether the threads produced the same sequence of
random() results. */
{
int expected_index;
int result_index[THREAD_COUNT];
int i;
for (i = 0; i < THREAD_COUNT; i++)
result_index[i] = 0;
for (expected_index = 0; expected_index < REPEAT_COUNT; expected_index++)
{
long expected_value = expected[expected_index];
for (i = 0; i < THREAD_COUNT; i++)
{
if (thread_results[i][result_index[i]] == expected_value)
{
result_index[i]++;
break;
}
}
if (i == THREAD_COUNT)
{
if (expected_index == 0)
{
/* This occurs on platforms like OpenBSD, where srandom() has no
effect and random() always return non-deterministic values.
Mark the test as SKIP. */
fprintf (stderr, "Skipping test: random() is non-deterministic.\n");
return 77;
}
else
{
fprintf (stderr, "Expected value #%d not found in multithreaded results.\n",
expected_index);
return 1;
}
}
}
}
return 0;
}
#else
/* No multithreading available. */
#include <stdio.h>
int
main ()
{
fputs ("Skipping test: multithreading not enabled\n", stderr);
return 77;
}
#endif