Branch data Line data Source code
1 : : /* Test of locking in multithreaded situations.
2 : : Copyright (C) 2005, 2008-2012 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 enable locking.
37 : : Uncomment this to get a test program without locking, to verify that
38 : : it crashes. */
39 : : #define ENABLE_LOCKING 1
40 : :
41 : : /* Which tests to perform.
42 : : Uncomment some of these, to verify that all tests crash if no locking
43 : : is enabled. */
44 : : #define DO_TEST_LOCK 1
45 : : #define DO_TEST_RWLOCK 1
46 : : #define DO_TEST_RECURSIVE_LOCK 1
47 : : #define DO_TEST_ONCE 1
48 : :
49 : : /* Whether to help the scheduler through explicit yield().
50 : : Uncomment this to see if the operating system has a fair scheduler. */
51 : : #define EXPLICIT_YIELD 1
52 : :
53 : : /* Whether to print debugging messages. */
54 : : #define ENABLE_DEBUGGING 0
55 : :
56 : : /* Number of simultaneous threads. */
57 : : #define THREAD_COUNT 10
58 : :
59 : : /* Number of operations performed in each thread.
60 : : This is quite high, because with a smaller count, say 5000, we often get
61 : : an "OK" result even without ENABLE_LOCKING (on Linux/x86). */
62 : : #define REPEAT_COUNT 50000
63 : :
64 : : #include <stdio.h>
65 : : #include <stdlib.h>
66 : : #include <string.h>
67 : :
68 : : #if !ENABLE_LOCKING
69 : : # undef USE_POSIX_THREADS
70 : : # undef USE_SOLARIS_THREADS
71 : : # undef USE_PTH_THREADS
72 : : # undef USE_WINDOWS_THREADS
73 : : #endif
74 : : #include "glthread/lock.h"
75 : :
76 : : #if !ENABLE_LOCKING
77 : : # if TEST_POSIX_THREADS
78 : : # define USE_POSIX_THREADS 1
79 : : # endif
80 : : # if TEST_SOLARIS_THREADS
81 : : # define USE_SOLARIS_THREADS 1
82 : : # endif
83 : : # if TEST_PTH_THREADS
84 : : # define USE_PTH_THREADS 1
85 : : # endif
86 : : # if TEST_WINDOWS_THREADS
87 : : # define USE_WINDOWS_THREADS 1
88 : : # endif
89 : : #endif
90 : :
91 : : #include "glthread/thread.h"
92 : : #include "glthread/yield.h"
93 : :
94 : : #if ENABLE_DEBUGGING
95 : : # define dbgprintf printf
96 : : #else
97 : : # define dbgprintf if (0) printf
98 : : #endif
99 : :
100 : : #if EXPLICIT_YIELD
101 : : # define yield() gl_thread_yield ()
102 : : #else
103 : : # define yield()
104 : : #endif
105 : :
106 : : #define ACCOUNT_COUNT 4
107 : :
108 : : static int account[ACCOUNT_COUNT];
109 : :
110 : : static int
111 : 4002468 : random_account (void)
112 : : {
113 : 4002468 : return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
114 : : }
115 : :
116 : : static void
117 : 1836139 : check_accounts (void)
118 : : {
119 : : int i, sum;
120 : :
121 : 1836139 : sum = 0;
122 [ + + ]: 9172243 : for (i = 0; i < ACCOUNT_COUNT; i++)
123 : 7336104 : sum += account[i];
124 [ - + ]: 1836139 : if (sum != ACCOUNT_COUNT * 1000)
125 : 0 : abort ();
126 : 1836139 : }
127 : :
128 : :
129 : : /* ------------------- Test normal (non-recursive) locks ------------------- */
130 : :
131 : : /* Test normal locks by having several bank accounts and several threads
132 : : which shuffle around money between the accounts and another thread
133 : : checking that all the money is still there. */
134 : :
135 : : gl_lock_define_initialized(static, my_lock)
136 : :
137 : : static void *
138 : 3567 : lock_mutator_thread (void *arg)
139 : : {
140 : : int repeat;
141 : :
142 [ + + ]: 493930 : for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
143 : : {
144 : : int i1, i2, value;
145 : :
146 : : dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
147 [ + + ][ - + ]: 493920 : gl_lock_lock (my_lock);
148 : : dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
149 : :
150 : 501585 : i1 = random_account ();
151 : 500000 : i2 = random_account ();
152 : 500000 : value = ((unsigned int) rand () >> 3) % 10;
153 : 500000 : account[i1] += value;
154 : 500000 : account[i2] -= value;
155 : :
156 : : dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
157 [ + - ][ - + ]: 500000 : gl_lock_unlock (my_lock);
158 : : dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
159 : :
160 : : dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
161 [ + ][ - + ]: 496288 : gl_lock_lock (my_lock);
162 : 498798 : check_accounts ();
163 [ + - ][ - + ]: 500000 : gl_lock_unlock (my_lock);
164 : : dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
165 : :
166 : 494312 : yield ();
167 : : }
168 : :
169 : : dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
170 : 10 : return NULL;
171 : : }
172 : :
173 : : static volatile int lock_checker_done;
174 : :
175 : : static void *
176 : 1 : lock_checker_thread (void *arg)
177 : : {
178 [ + + ]: 74800 : while (!lock_checker_done)
179 : : {
180 : : dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
181 [ + - ][ - + ]: 74799 : gl_lock_lock (my_lock);
182 : 74799 : check_accounts ();
183 [ + - ][ - + ]: 74799 : gl_lock_unlock (my_lock);
184 : : dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
185 : :
186 : 74799 : yield ();
187 : : }
188 : :
189 : : dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
190 : 1 : return NULL;
191 : : }
192 : :
193 : : static void
194 : 1 : test_lock (void)
195 : : {
196 : : int i;
197 : : gl_thread_t checkerthread;
198 : : gl_thread_t threads[THREAD_COUNT];
199 : :
200 : : /* Initialization. */
201 [ + + ]: 5 : for (i = 0; i < ACCOUNT_COUNT; i++)
202 : 4 : account[i] = 1000;
203 : 1 : lock_checker_done = 0;
204 : :
205 : : /* Spawn the threads. */
206 : 1 : checkerthread = gl_thread_create (lock_checker_thread, NULL);
207 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
208 : 10 : threads[i] = gl_thread_create (lock_mutator_thread, NULL);
209 : :
210 : : /* Wait for the threads to terminate. */
211 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
212 [ + - ][ - + ]: 10 : gl_thread_join (threads[i], NULL);
213 : 1 : lock_checker_done = 1;
214 [ + - ][ - + ]: 1 : gl_thread_join (checkerthread, NULL);
215 : 1 : check_accounts ();
216 : 1 : }
217 : :
218 : :
219 : : /* ----------------- Test read-write (non-recursive) locks ----------------- */
220 : :
221 : : /* Test read-write locks by having several bank accounts and several threads
222 : : which shuffle around money between the accounts and several other threads
223 : : that check that all the money is still there. */
224 : :
225 : : gl_rwlock_define_initialized(static, my_rwlock)
226 : :
227 : : static void *
228 : 2470 : rwlock_mutator_thread (void *arg)
229 : : {
230 : : int repeat;
231 : :
232 [ + + ]: 495490 : for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
233 : : {
234 : : int i1, i2, value;
235 : :
236 : : dbgprintf ("Mutator %p before wrlock\n", gl_thread_self_pointer ());
237 [ + + ][ - + ]: 495480 : gl_rwlock_wrlock (my_rwlock);
238 : : dbgprintf ("Mutator %p after wrlock\n", gl_thread_self_pointer ());
239 : :
240 : 500781 : i1 = random_account ();
241 : 500000 : i2 = random_account ();
242 : 500000 : value = ((unsigned int) rand () >> 3) % 10;
243 : 500000 : account[i1] += value;
244 : 500000 : account[i2] -= value;
245 : :
246 : : dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
247 [ + - ][ - + ]: 500000 : gl_rwlock_unlock (my_rwlock);
248 : : dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
249 : :
250 : 493943 : yield ();
251 : : }
252 : :
253 : : dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
254 : 10 : return NULL;
255 : : }
256 : :
257 : : static volatile int rwlock_checker_done;
258 : :
259 : : static void *
260 : 10 : rwlock_checker_thread (void *arg)
261 : : {
262 [ + + ]: 654829 : while (!rwlock_checker_done)
263 : : {
264 : : dbgprintf ("Checker %p before check rdlock\n", gl_thread_self_pointer ());
265 [ + + ][ - + ]: 654819 : gl_rwlock_rdlock (my_rwlock);
266 : 673533 : check_accounts ();
267 [ + ][ - + ]: 670272 : gl_rwlock_unlock (my_rwlock);
268 : : dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
269 : :
270 : 664113 : yield ();
271 : : }
272 : :
273 : : dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
274 : 10 : return NULL;
275 : : }
276 : :
277 : : static void
278 : 1 : test_rwlock (void)
279 : : {
280 : : int i;
281 : : gl_thread_t checkerthreads[THREAD_COUNT];
282 : : gl_thread_t threads[THREAD_COUNT];
283 : :
284 : : /* Initialization. */
285 [ + + ]: 5 : for (i = 0; i < ACCOUNT_COUNT; i++)
286 : 4 : account[i] = 1000;
287 : 1 : rwlock_checker_done = 0;
288 : :
289 : : /* Spawn the threads. */
290 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
291 : 10 : checkerthreads[i] = gl_thread_create (rwlock_checker_thread, NULL);
292 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
293 : 10 : threads[i] = gl_thread_create (rwlock_mutator_thread, NULL);
294 : :
295 : : /* Wait for the threads to terminate. */
296 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
297 [ + - ][ - + ]: 10 : gl_thread_join (threads[i], NULL);
298 : 1 : rwlock_checker_done = 1;
299 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
300 [ + - ][ - + ]: 10 : gl_thread_join (checkerthreads[i], NULL);
301 : 1 : check_accounts ();
302 : 1 : }
303 : :
304 : :
305 : : /* -------------------------- Test recursive locks -------------------------- */
306 : :
307 : : /* Test recursive locks by having several bank accounts and several threads
308 : : which shuffle around money between the accounts (recursively) and another
309 : : thread checking that all the money is still there. */
310 : :
311 : : gl_recursive_lock_define_initialized(static, my_reclock)
312 : :
313 : : static void
314 : 995316 : recshuffle (void)
315 : : {
316 : : int i1, i2, value;
317 : :
318 : : dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
319 [ + ][ - + ]: 995316 : gl_recursive_lock_lock (my_reclock);
320 : : dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
321 : :
322 : 1000923 : i1 = random_account ();
323 : 1001234 : i2 = random_account ();
324 : 1001234 : value = ((unsigned int) rand () >> 3) % 10;
325 : 1001234 : account[i1] += value;
326 : 1001234 : account[i2] -= value;
327 : :
328 : : /* Recursive with probability 0.5. */
329 [ + + ]: 1001234 : if (((unsigned int) rand () >> 3) % 2)
330 : 501234 : recshuffle ();
331 : :
332 : : dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
333 [ + - ][ - + ]: 1001234 : gl_recursive_lock_unlock (my_reclock);
334 : : dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
335 : 996446 : }
336 : :
337 : : static void *
338 : 2746 : reclock_mutator_thread (void *arg)
339 : : {
340 : : int repeat;
341 : :
342 [ + + ]: 495584 : for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
343 : : {
344 : 495574 : recshuffle ();
345 : :
346 : : dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
347 [ + ][ - + ]: 496105 : gl_recursive_lock_lock (my_reclock);
348 : 498832 : check_accounts ();
349 [ + - ][ - + ]: 500000 : gl_recursive_lock_unlock (my_reclock);
350 : : dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
351 : :
352 : 491087 : yield ();
353 : : }
354 : :
355 : : dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
356 : 10 : return NULL;
357 : : }
358 : :
359 : : static volatile int reclock_checker_done;
360 : :
361 : : static void *
362 : 1 : reclock_checker_thread (void *arg)
363 : : {
364 [ + + ]: 90082 : while (!reclock_checker_done)
365 : : {
366 : : dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
367 [ + - ][ - + ]: 90081 : gl_recursive_lock_lock (my_reclock);
368 : 90081 : check_accounts ();
369 [ + - ][ - + ]: 90081 : gl_recursive_lock_unlock (my_reclock);
370 : : dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
371 : :
372 : 90081 : yield ();
373 : : }
374 : :
375 : : dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
376 : 1 : return NULL;
377 : : }
378 : :
379 : : static void
380 : 1 : test_recursive_lock (void)
381 : : {
382 : : int i;
383 : : gl_thread_t checkerthread;
384 : : gl_thread_t threads[THREAD_COUNT];
385 : :
386 : : /* Initialization. */
387 [ + + ]: 5 : for (i = 0; i < ACCOUNT_COUNT; i++)
388 : 4 : account[i] = 1000;
389 : 1 : reclock_checker_done = 0;
390 : :
391 : : /* Spawn the threads. */
392 : 1 : checkerthread = gl_thread_create (reclock_checker_thread, NULL);
393 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
394 : 10 : threads[i] = gl_thread_create (reclock_mutator_thread, NULL);
395 : :
396 : : /* Wait for the threads to terminate. */
397 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
398 [ + - ][ - + ]: 10 : gl_thread_join (threads[i], NULL);
399 : 1 : reclock_checker_done = 1;
400 [ + - ][ - + ]: 1 : gl_thread_join (checkerthread, NULL);
401 : 1 : check_accounts ();
402 : 1 : }
403 : :
404 : :
405 : : /* ------------------------ Test once-only execution ------------------------ */
406 : :
407 : : /* Test once-only execution by having several threads attempt to grab a
408 : : once-only task simultaneously (triggered by releasing a read-write lock). */
409 : :
410 : : gl_once_define(static, fresh_once)
411 : : static int ready[THREAD_COUNT];
412 : : static gl_lock_t ready_lock[THREAD_COUNT];
413 : : #if ENABLE_LOCKING
414 : : static gl_rwlock_t fire_signal[REPEAT_COUNT];
415 : : #else
416 : : static volatile int fire_signal_state;
417 : : #endif
418 : : static gl_once_t once_control;
419 : : static int performed;
420 : : gl_lock_define_initialized(static, performed_lock)
421 : :
422 : : static void
423 : 50000 : once_execute (void)
424 : : {
425 [ + - ][ - + ]: 50000 : gl_lock_lock (performed_lock);
426 : 50000 : performed++;
427 [ + - ][ - + ]: 50000 : gl_lock_unlock (performed_lock);
428 : 50000 : }
429 : :
430 : : static void *
431 : 10 : once_contender_thread (void *arg)
432 : : {
433 : 10 : int id = (int) (long) arg;
434 : : int repeat;
435 : :
436 [ + ]: 494047 : for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
437 : : {
438 : : /* Tell the main thread that we're ready. */
439 [ + ][ - + ]: 496281 : gl_lock_lock (ready_lock[id]);
440 : 489539 : ready[id] = 1;
441 [ + + ][ - + ]: 489539 : gl_lock_unlock (ready_lock[id]);
442 : :
443 [ + + ]: 498725 : if (repeat == REPEAT_COUNT)
444 : 10 : break;
445 : :
446 : : dbgprintf ("Contender %p waiting for signal for round %d\n",
447 : : gl_thread_self_pointer (), repeat);
448 : : #if ENABLE_LOCKING
449 : : /* Wait for the signal to go. */
450 [ + + ][ - + ]: 498715 : gl_rwlock_rdlock (fire_signal[repeat]);
451 : : /* And don't hinder the others (if the scheduler is unfair). */
452 [ + + ][ - + ]: 499597 : gl_rwlock_unlock (fire_signal[repeat]);
453 : : #else
454 : : /* Wait for the signal to go. */
455 : : while (fire_signal_state <= repeat)
456 : : yield ();
457 : : #endif
458 : : dbgprintf ("Contender %p got the signal for round %d\n",
459 : : gl_thread_self_pointer (), repeat);
460 : :
461 : : /* Contend for execution. */
462 [ + - ][ # # ]: 495686 : gl_once (once_control, once_execute);
[ - + ]
463 : : }
464 : :
465 : 0 : return NULL;
466 : : }
467 : :
468 : : static void
469 : 1 : test_once (void)
470 : : {
471 : : int i, repeat;
472 : : gl_thread_t threads[THREAD_COUNT];
473 : :
474 : : /* Initialize all variables. */
475 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
476 : : {
477 : 10 : ready[i] = 0;
478 [ + - ][ - + ]: 10 : gl_lock_init (ready_lock[i]);
479 : : }
480 : : #if ENABLE_LOCKING
481 [ + + ]: 50001 : for (i = 0; i < REPEAT_COUNT; i++)
482 [ + - ][ - + ]: 50000 : gl_rwlock_init (fire_signal[i]);
483 : : #else
484 : : fire_signal_state = 0;
485 : : #endif
486 : :
487 : : /* Block all fire_signals. */
488 [ + + ]: 50001 : for (i = REPEAT_COUNT-1; i >= 0; i--)
489 [ + - ][ - + ]: 50000 : gl_rwlock_wrlock (fire_signal[i]);
490 : :
491 : : /* Spawn the threads. */
492 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
493 : 10 : threads[i] = gl_thread_create (once_contender_thread, (void *) (long) i);
494 : :
495 [ + - ]: 50001 : for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
496 : : {
497 : : /* Wait until every thread is ready. */
498 : : dbgprintf ("Main thread before synchronizing for round %d\n", repeat);
499 : : for (;;)
500 : : {
501 : 327337 : int ready_count = 0;
502 [ + + ]: 3600707 : for (i = 0; i < THREAD_COUNT; i++)
503 : : {
504 [ + - ][ - + ]: 3273370 : gl_lock_lock (ready_lock[i]);
505 : 3273370 : ready_count += ready[i];
506 [ + - ][ - + ]: 3273370 : gl_lock_unlock (ready_lock[i]);
507 : : }
508 [ + + ]: 327337 : if (ready_count == THREAD_COUNT)
509 : 50001 : break;
510 : 277336 : yield ();
511 : 277336 : }
512 : : dbgprintf ("Main thread after synchronizing for round %d\n", repeat);
513 : :
514 [ + + ]: 50001 : if (repeat > 0)
515 : : {
516 : : /* Check that exactly one thread executed the once_execute()
517 : : function. */
518 [ - + ]: 50000 : if (performed != 1)
519 : 0 : abort ();
520 : : }
521 : :
522 [ + + ]: 50001 : if (repeat == REPEAT_COUNT)
523 : 1 : break;
524 : :
525 : : /* Preparation for the next round: Initialize once_control. */
526 : 50000 : memcpy (&once_control, &fresh_once, sizeof (gl_once_t));
527 : :
528 : : /* Preparation for the next round: Reset the performed counter. */
529 : 50000 : performed = 0;
530 : :
531 : : /* Preparation for the next round: Reset the ready flags. */
532 [ + + ]: 550000 : for (i = 0; i < THREAD_COUNT; i++)
533 : : {
534 [ + - ][ - + ]: 500000 : gl_lock_lock (ready_lock[i]);
535 : 500000 : ready[i] = 0;
536 [ + - ][ - + ]: 500000 : gl_lock_unlock (ready_lock[i]);
537 : : }
538 : :
539 : : /* Signal all threads simultaneously. */
540 : : dbgprintf ("Main thread giving signal for round %d\n", repeat);
541 : : #if ENABLE_LOCKING
542 [ + - ][ - + ]: 50000 : gl_rwlock_unlock (fire_signal[repeat]);
543 : : #else
544 : : fire_signal_state = repeat + 1;
545 : : #endif
546 : : }
547 : :
548 : : /* Wait for the threads to terminate. */
549 [ + + ]: 11 : for (i = 0; i < THREAD_COUNT; i++)
550 [ + - ][ - + ]: 10 : gl_thread_join (threads[i], NULL);
551 : 1 : }
552 : :
553 : :
554 : : /* -------------------------------------------------------------------------- */
555 : :
556 : : int
557 : 1 : main ()
558 : : {
559 : : #if TEST_PTH_THREADS
560 : : if (!pth_init ())
561 : : abort ();
562 : : #endif
563 : :
564 : : #if DO_TEST_LOCK
565 : 1 : printf ("Starting test_lock ..."); fflush (stdout);
566 : 1 : test_lock ();
567 : 1 : printf (" OK\n"); fflush (stdout);
568 : : #endif
569 : : #if DO_TEST_RWLOCK
570 : 1 : printf ("Starting test_rwlock ..."); fflush (stdout);
571 : 1 : test_rwlock ();
572 : 1 : printf (" OK\n"); fflush (stdout);
573 : : #endif
574 : : #if DO_TEST_RECURSIVE_LOCK
575 : 1 : printf ("Starting test_recursive_lock ..."); fflush (stdout);
576 : 1 : test_recursive_lock ();
577 : 1 : printf (" OK\n"); fflush (stdout);
578 : : #endif
579 : : #if DO_TEST_ONCE
580 : 1 : printf ("Starting test_once ..."); fflush (stdout);
581 : 1 : test_once ();
582 : 1 : printf (" OK\n"); fflush (stdout);
583 : : #endif
584 : :
585 : 1 : return 0;
586 : : }
587 : :
588 : : #else
589 : :
590 : : /* No multithreading available. */
591 : :
592 : : #include <stdio.h>
593 : :
594 : : int
595 : : main ()
596 : : {
597 : : fputs ("Skipping test: multithreading not enabled\n", stderr);
598 : : return 77;
599 : : }
600 : :
601 : : #endif
|