1 /* Test of once-only execution in multithreaded situations.
2 Copyright (C) 2005, 2008-2020 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. */
21 #if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
23 /* Whether to enable locking.
24 Uncomment this to get a test program without locking, to verify that
26 #define ENABLE_LOCKING 1
28 /* Whether to help the scheduler through explicit sched_yield().
29 Uncomment this to see if the operating system has a fair scheduler. */
30 #define EXPLICIT_YIELD 1
32 /* Whether to print debugging messages. */
33 #define ENABLE_DEBUGGING 0
35 /* Number of simultaneous threads. */
36 #define THREAD_COUNT 10
38 /* Number of operations performed in each thread.
39 This is quite high, because with a smaller count, say 5000, we often get
40 an "OK" result even without ENABLE_LOCKING (on Linux/x86). */
41 #define REPEAT_COUNT 50000
61 # define dbgprintf printf
63 # define dbgprintf if (0) printf
67 # define yield() sched_yield ()
72 /* Returns a reference to the current thread as a pointer, for debugging. */
74 /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field.
75 The first three bytes of this field appear to uniquely identify a
76 pthread_t, though not necessarily representing a pointer. */
77 # define pthread_self_pointer() (*((void **) pthread_self ().__))
79 # define pthread_self_pointer() ((void *) (uintptr_t) pthread_self ())
83 /* ------------------------ Test once-only execution ------------------------ */
85 /* Test once-only execution by having several threads attempt to grab a
86 once-only task simultaneously (triggered by releasing a read-write lock). */
88 static pthread_once_t fresh_once
= PTHREAD_ONCE_INIT
;
89 static int ready
[THREAD_COUNT
];
90 static pthread_mutex_t ready_lock
[THREAD_COUNT
];
92 static pthread_rwlock_t fire_signal
[REPEAT_COUNT
];
94 static volatile int fire_signal_state
;
96 static pthread_once_t once_control
;
98 static pthread_mutex_t performed_lock
;
103 ASSERT (pthread_mutex_lock (&performed_lock
) == 0);
105 ASSERT (pthread_mutex_unlock (&performed_lock
) == 0);
109 once_contender_thread (void *arg
)
111 int id
= (int) (intptr_t) arg
;
114 for (repeat
= 0; repeat
<= REPEAT_COUNT
; repeat
++)
116 /* Tell the main thread that we're ready. */
117 ASSERT (pthread_mutex_lock (&ready_lock
[id
]) == 0);
119 ASSERT (pthread_mutex_unlock (&ready_lock
[id
]) == 0);
121 if (repeat
== REPEAT_COUNT
)
124 dbgprintf ("Contender %p waiting for signal for round %d\n",
125 pthread_self_pointer (), repeat
);
127 /* Wait for the signal to go. */
128 ASSERT (pthread_rwlock_rdlock (&fire_signal
[repeat
]) == 0);
129 /* And don't hinder the others (if the scheduler is unfair). */
130 ASSERT (pthread_rwlock_unlock (&fire_signal
[repeat
]) == 0);
132 /* Wait for the signal to go. */
133 while (fire_signal_state
<= repeat
)
136 dbgprintf ("Contender %p got the signal for round %d\n",
137 pthread_self_pointer (), repeat
);
139 /* Contend for execution. */
140 ASSERT (pthread_once (&once_control
, once_execute
) == 0);
150 pthread_t threads
[THREAD_COUNT
];
152 /* Initialize all variables. */
153 for (i
= 0; i
< THREAD_COUNT
; i
++)
155 pthread_mutexattr_t attr
;
158 ASSERT (pthread_mutexattr_init (&attr
) == 0);
159 ASSERT (pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_NORMAL
) == 0);
160 ASSERT (pthread_mutex_init (&ready_lock
[i
], &attr
) == 0);
161 ASSERT (pthread_mutexattr_destroy (&attr
) == 0);
164 for (i
= 0; i
< REPEAT_COUNT
; i
++)
165 ASSERT (pthread_rwlock_init (&fire_signal
[i
], NULL
) == 0);
167 fire_signal_state
= 0;
171 /* Block all fire_signals. */
172 for (i
= REPEAT_COUNT
-1; i
>= 0; i
--)
173 ASSERT (pthread_rwlock_wrlock (&fire_signal
[i
]) == 0);
176 /* Spawn the threads. */
177 for (i
= 0; i
< THREAD_COUNT
; i
++)
178 ASSERT (pthread_create (&threads
[i
], NULL
,
179 once_contender_thread
, (void *) (intptr_t) i
)
182 for (repeat
= 0; repeat
<= REPEAT_COUNT
; repeat
++)
184 /* Wait until every thread is ready. */
185 dbgprintf ("Main thread before synchronizing for round %d\n", repeat
);
189 for (i
= 0; i
< THREAD_COUNT
; i
++)
191 ASSERT (pthread_mutex_lock (&ready_lock
[i
]) == 0);
192 ready_count
+= ready
[i
];
193 ASSERT (pthread_mutex_unlock (&ready_lock
[i
]) == 0);
195 if (ready_count
== THREAD_COUNT
)
199 dbgprintf ("Main thread after synchronizing for round %d\n", repeat
);
203 /* Check that exactly one thread executed the once_execute()
209 if (repeat
== REPEAT_COUNT
)
212 /* Preparation for the next round: Initialize once_control. */
213 memcpy (&once_control
, &fresh_once
, sizeof (pthread_once_t
));
215 /* Preparation for the next round: Reset the performed counter. */
218 /* Preparation for the next round: Reset the ready flags. */
219 for (i
= 0; i
< THREAD_COUNT
; i
++)
221 ASSERT (pthread_mutex_lock (&ready_lock
[i
]) == 0);
223 ASSERT (pthread_mutex_unlock (&ready_lock
[i
]) == 0);
226 /* Signal all threads simultaneously. */
227 dbgprintf ("Main thread giving signal for round %d\n", repeat
);
229 ASSERT (pthread_rwlock_unlock (&fire_signal
[repeat
]) == 0);
231 fire_signal_state
= repeat
+ 1;
235 /* Wait for the threads to terminate. */
236 for (i
= 0; i
< THREAD_COUNT
; i
++)
237 ASSERT (pthread_join (threads
[i
], NULL
) == 0);
241 /* -------------------------------------------------------------------------- */
247 /* Declare failure if test takes too long, by using default abort
248 caused by SIGALRM. */
249 int alarm_value
= 600;
250 signal (SIGALRM
, SIG_DFL
);
255 pthread_mutexattr_t attr
;
257 ASSERT (pthread_mutexattr_init (&attr
) == 0);
258 ASSERT (pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_NORMAL
) == 0);
259 ASSERT (pthread_mutex_init (&performed_lock
, &attr
) == 0);
260 ASSERT (pthread_mutexattr_destroy (&attr
) == 0);
263 printf ("Starting test_once ..."); fflush (stdout
);
265 printf (" OK\n"); fflush (stdout
);
272 /* No multithreading available. */
279 fputs ("Skipping test: multithreading not enabled\n", stderr
);