nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* Test of locking in multithreaded situations.
2 Copyright (C) 2005, 2008-2016 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 Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
13  
14 You should have received a copy of the GNU Lesser 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 "lock.h"
75  
76 #if ENABLE_DEBUGGING
77 # define dbgprintf printf
78 #else
79 # define dbgprintf if (0) printf
80 #endif
81  
82 #if TEST_POSIX_THREADS
83 # include <pthread.h>
84 # ifndef __KLIBC__
85 # include <sched.h>
86 # else
87 # define sched_yield() pthread_yield()
88 # endif
89 typedef pthread_t gl_thread_t;
90 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
91 {
92 pthread_t thread;
93 if (pthread_create (&thread, NULL, func, arg) != 0)
94 abort ();
95 return thread;
96 }
97 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
98 {
99 if (pthread_join (thread, retvalp) != 0)
100 abort ();
101 }
102 static inline void gl_thread_yield (void)
103 {
104 sched_yield ();
105 }
106 static inline void * gl_thread_self_pointer (void)
107 {
108 # ifdef PTW32_VERSION
109 return pthread_self ().p;
110 # else
111 return (void *) pthread_self ();
112 # endif
113 }
114 #endif
115 #if TEST_PTH_THREADS
116 # include <pth.h>
117 typedef pth_t gl_thread_t;
118 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
119 {
120 pth_t thread = pth_spawn (NULL, func, arg);
121 if (thread == NULL)
122 abort ();
123 return thread;
124 }
125 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
126 {
127 if (!pth_join (thread, retvalp))
128 abort ();
129 }
130 static inline void gl_thread_yield (void)
131 {
132 pth_yield (NULL);
133 }
134 static inline void * gl_thread_self_pointer (void)
135 {
136 return pth_self ();
137 }
138 #endif
139 #if TEST_SOLARIS_THREADS
140 # include <thread.h>
141 typedef thread_t gl_thread_t;
142 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
143 {
144 thread_t thread;
145 if (thr_create (NULL, 0, func, arg, 0, &thread) != 0)
146 abort ();
147 return thread;
148 }
149 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
150 {
151 if (thr_join (thread, NULL, retvalp) != 0)
152 abort ();
153 }
154 static inline void gl_thread_yield (void)
155 {
156 thr_yield ();
157 }
158 static inline void * gl_thread_self_pointer (void)
159 {
160 return (void *) thr_self ();
161 }
162 #endif
163 #if TEST_WINDOWS_THREADS
164 # include <windows.h>
165 typedef HANDLE gl_thread_t;
166 /* Use a wrapper function, instead of adding WINAPI through a cast. */
167 struct wrapper_args { void * (*func) (void *); void *arg; };
168 static DWORD WINAPI wrapper_func (void *varg)
169 {
170 struct wrapper_args *warg = (struct wrapper_args *)varg;
171 void * (*func) (void *) = warg->func;
172 void *arg = warg->arg;
173 free (warg);
174 func (arg);
175 return 0;
176 }
177 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
178 {
179 struct wrapper_args *warg =
180 (struct wrapper_args *) malloc (sizeof (struct wrapper_args));
181 if (warg == NULL)
182 abort ();
183 warg->func = func;
184 warg->arg = arg;
185 {
186 DWORD thread_id;
187 HANDLE thread =
188 CreateThread (NULL, 100000, wrapper_func, warg, 0, &thread_id);
189 if (thread == NULL)
190 abort ();
191 return thread;
192 }
193 }
194 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
195 {
196 (void) retvalp;
197 if (WaitForSingleObject (thread, INFINITE) == WAIT_FAILED)
198 abort ();
199 if (!CloseHandle (thread))
200 abort ();
201 }
202 static inline void gl_thread_yield (void)
203 {
204 Sleep (0);
205 }
206 static inline void * gl_thread_self_pointer (void)
207 {
208 return (void *) GetCurrentThreadId ();
209 }
210 #endif
211 #if EXPLICIT_YIELD
212 # define yield() gl_thread_yield ()
213 #else
214 # define yield()
215 #endif
216  
217 #define ACCOUNT_COUNT 4
218  
219 static int account[ACCOUNT_COUNT];
220  
221 static int
222 random_account (void)
223 {
224 return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
225 }
226  
227 static void
228 check_accounts (void)
229 {
230 int i, sum;
231  
232 sum = 0;
233 for (i = 0; i < ACCOUNT_COUNT; i++)
234 sum += account[i];
235 if (sum != ACCOUNT_COUNT * 1000)
236 abort ();
237 }
238  
239  
240 /* ------------------- Test normal (non-recursive) locks ------------------- */
241  
242 /* Test normal locks by having several bank accounts and several threads
243 which shuffle around money between the accounts and another thread
244 checking that all the money is still there. */
245  
246 gl_lock_define_initialized(static, my_lock)
247  
248 static void *
249 lock_mutator_thread (void *arg)
250 {
251 int repeat;
252  
253 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
254 {
255 int i1, i2, value;
256  
257 dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
258 gl_lock_lock (my_lock);
259 dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
260  
261 i1 = random_account ();
262 i2 = random_account ();
263 value = ((unsigned int) rand () >> 3) % 10;
264 account[i1] += value;
265 account[i2] -= value;
266  
267 dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
268 gl_lock_unlock (my_lock);
269 dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
270  
271 dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
272 gl_lock_lock (my_lock);
273 check_accounts ();
274 gl_lock_unlock (my_lock);
275 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
276  
277 yield ();
278 }
279  
280 dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
281 return NULL;
282 }
283  
284 static volatile int lock_checker_done;
285  
286 static void *
287 lock_checker_thread (void *arg)
288 {
289 while (!lock_checker_done)
290 {
291 dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
292 gl_lock_lock (my_lock);
293 check_accounts ();
294 gl_lock_unlock (my_lock);
295 dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
296  
297 yield ();
298 }
299  
300 dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
301 return NULL;
302 }
303  
304 static void
305 test_lock (void)
306 {
307 int i;
308 gl_thread_t checkerthread;
309 gl_thread_t threads[THREAD_COUNT];
310  
311 /* Initialization. */
312 for (i = 0; i < ACCOUNT_COUNT; i++)
313 account[i] = 1000;
314 lock_checker_done = 0;
315  
316 /* Spawn the threads. */
317 checkerthread = gl_thread_create (lock_checker_thread, NULL);
318 for (i = 0; i < THREAD_COUNT; i++)
319 threads[i] = gl_thread_create (lock_mutator_thread, NULL);
320  
321 /* Wait for the threads to terminate. */
322 for (i = 0; i < THREAD_COUNT; i++)
323 gl_thread_join (threads[i], NULL);
324 lock_checker_done = 1;
325 gl_thread_join (checkerthread, NULL);
326 check_accounts ();
327 }
328  
329  
330 /* ----------------- Test read-write (non-recursive) locks ----------------- */
331  
332 /* Test read-write locks by having several bank accounts and several threads
333 which shuffle around money between the accounts and several other threads
334 that check that all the money is still there. */
335  
336 gl_rwlock_define_initialized(static, my_rwlock)
337  
338 static void *
339 rwlock_mutator_thread (void *arg)
340 {
341 int repeat;
342  
343 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
344 {
345 int i1, i2, value;
346  
347 dbgprintf ("Mutator %p before wrlock\n", gl_thread_self_pointer ());
348 gl_rwlock_wrlock (my_rwlock);
349 dbgprintf ("Mutator %p after wrlock\n", gl_thread_self_pointer ());
350  
351 i1 = random_account ();
352 i2 = random_account ();
353 value = ((unsigned int) rand () >> 3) % 10;
354 account[i1] += value;
355 account[i2] -= value;
356  
357 dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
358 gl_rwlock_unlock (my_rwlock);
359 dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
360  
361 yield ();
362 }
363  
364 dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
365 return NULL;
366 }
367  
368 static volatile int rwlock_checker_done;
369  
370 static void *
371 rwlock_checker_thread (void *arg)
372 {
373 while (!rwlock_checker_done)
374 {
375 dbgprintf ("Checker %p before check rdlock\n", gl_thread_self_pointer ());
376 gl_rwlock_rdlock (my_rwlock);
377 check_accounts ();
378 gl_rwlock_unlock (my_rwlock);
379 dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
380  
381 yield ();
382 }
383  
384 dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
385 return NULL;
386 }
387  
388 static void
389 test_rwlock (void)
390 {
391 int i;
392 gl_thread_t checkerthreads[THREAD_COUNT];
393 gl_thread_t threads[THREAD_COUNT];
394  
395 /* Initialization. */
396 for (i = 0; i < ACCOUNT_COUNT; i++)
397 account[i] = 1000;
398 rwlock_checker_done = 0;
399  
400 /* Spawn the threads. */
401 for (i = 0; i < THREAD_COUNT; i++)
402 checkerthreads[i] = gl_thread_create (rwlock_checker_thread, NULL);
403 for (i = 0; i < THREAD_COUNT; i++)
404 threads[i] = gl_thread_create (rwlock_mutator_thread, NULL);
405  
406 /* Wait for the threads to terminate. */
407 for (i = 0; i < THREAD_COUNT; i++)
408 gl_thread_join (threads[i], NULL);
409 rwlock_checker_done = 1;
410 for (i = 0; i < THREAD_COUNT; i++)
411 gl_thread_join (checkerthreads[i], NULL);
412 check_accounts ();
413 }
414  
415  
416 /* -------------------------- Test recursive locks -------------------------- */
417  
418 /* Test recursive locks by having several bank accounts and several threads
419 which shuffle around money between the accounts (recursively) and another
420 thread checking that all the money is still there. */
421  
422 gl_recursive_lock_define_initialized(static, my_reclock)
423  
424 static void
425 recshuffle (void)
426 {
427 int i1, i2, value;
428  
429 dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
430 gl_recursive_lock_lock (my_reclock);
431 dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
432  
433 i1 = random_account ();
434 i2 = random_account ();
435 value = ((unsigned int) rand () >> 3) % 10;
436 account[i1] += value;
437 account[i2] -= value;
438  
439 /* Recursive with probability 0.5. */
440 if (((unsigned int) rand () >> 3) % 2)
441 recshuffle ();
442  
443 dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
444 gl_recursive_lock_unlock (my_reclock);
445 dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
446 }
447  
448 static void *
449 reclock_mutator_thread (void *arg)
450 {
451 int repeat;
452  
453 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
454 {
455 recshuffle ();
456  
457 dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
458 gl_recursive_lock_lock (my_reclock);
459 check_accounts ();
460 gl_recursive_lock_unlock (my_reclock);
461 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
462  
463 yield ();
464 }
465  
466 dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
467 return NULL;
468 }
469  
470 static volatile int reclock_checker_done;
471  
472 static void *
473 reclock_checker_thread (void *arg)
474 {
475 while (!reclock_checker_done)
476 {
477 dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
478 gl_recursive_lock_lock (my_reclock);
479 check_accounts ();
480 gl_recursive_lock_unlock (my_reclock);
481 dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
482  
483 yield ();
484 }
485  
486 dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
487 return NULL;
488 }
489  
490 static void
491 test_recursive_lock (void)
492 {
493 int i;
494 gl_thread_t checkerthread;
495 gl_thread_t threads[THREAD_COUNT];
496  
497 /* Initialization. */
498 for (i = 0; i < ACCOUNT_COUNT; i++)
499 account[i] = 1000;
500 reclock_checker_done = 0;
501  
502 /* Spawn the threads. */
503 checkerthread = gl_thread_create (reclock_checker_thread, NULL);
504 for (i = 0; i < THREAD_COUNT; i++)
505 threads[i] = gl_thread_create (reclock_mutator_thread, NULL);
506  
507 /* Wait for the threads to terminate. */
508 for (i = 0; i < THREAD_COUNT; i++)
509 gl_thread_join (threads[i], NULL);
510 reclock_checker_done = 1;
511 gl_thread_join (checkerthread, NULL);
512 check_accounts ();
513 }
514  
515  
516 /* ------------------------ Test once-only execution ------------------------ */
517  
518 /* Test once-only execution by having several threads attempt to grab a
519 once-only task simultaneously (triggered by releasing a read-write lock). */
520  
521 gl_once_define(static, fresh_once)
522 static int ready[THREAD_COUNT];
523 static gl_lock_t ready_lock[THREAD_COUNT];
524 #if ENABLE_LOCKING
525 static gl_rwlock_t fire_signal[REPEAT_COUNT];
526 #else
527 static volatile int fire_signal_state;
528 #endif
529 static gl_once_t once_control;
530 static int performed;
531 gl_lock_define_initialized(static, performed_lock)
532  
533 static void
534 once_execute (void)
535 {
536 gl_lock_lock (performed_lock);
537 performed++;
538 gl_lock_unlock (performed_lock);
539 }
540  
541 static void *
542 once_contender_thread (void *arg)
543 {
544 int id = (int) (long) arg;
545 int repeat;
546  
547 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
548 {
549 /* Tell the main thread that we're ready. */
550 gl_lock_lock (ready_lock[id]);
551 ready[id] = 1;
552 gl_lock_unlock (ready_lock[id]);
553  
554 if (repeat == REPEAT_COUNT)
555 break;
556  
557 dbgprintf ("Contender %p waiting for signal for round %d\n",
558 gl_thread_self_pointer (), repeat);
559 #if ENABLE_LOCKING
560 /* Wait for the signal to go. */
561 gl_rwlock_rdlock (fire_signal[repeat]);
562 /* And don't hinder the others (if the scheduler is unfair). */
563 gl_rwlock_unlock (fire_signal[repeat]);
564 #else
565 /* Wait for the signal to go. */
566 while (fire_signal_state <= repeat)
567 yield ();
568 #endif
569 dbgprintf ("Contender %p got the signal for round %d\n",
570 gl_thread_self_pointer (), repeat);
571  
572 /* Contend for execution. */
573 gl_once (once_control, once_execute);
574 }
575  
576 return NULL;
577 }
578  
579 static void
580 test_once (void)
581 {
582 int i, repeat;
583 gl_thread_t threads[THREAD_COUNT];
584  
585 /* Initialize all variables. */
586 for (i = 0; i < THREAD_COUNT; i++)
587 {
588 ready[i] = 0;
589 gl_lock_init (ready_lock[i]);
590 }
591 #if ENABLE_LOCKING
592 for (i = 0; i < REPEAT_COUNT; i++)
593 gl_rwlock_init (fire_signal[i]);
594 #else
595 fire_signal_state = 0;
596 #endif
597  
598 /* Block all fire_signals. */
599 for (i = REPEAT_COUNT-1; i >= 0; i--)
600 gl_rwlock_wrlock (fire_signal[i]);
601  
602 /* Spawn the threads. */
603 for (i = 0; i < THREAD_COUNT; i++)
604 threads[i] = gl_thread_create (once_contender_thread, (void *) (long) i);
605  
606 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
607 {
608 /* Wait until every thread is ready. */
609 dbgprintf ("Main thread before synchronizing for round %d\n", repeat);
610 for (;;)
611 {
612 int ready_count = 0;
613 for (i = 0; i < THREAD_COUNT; i++)
614 {
615 gl_lock_lock (ready_lock[i]);
616 ready_count += ready[i];
617 gl_lock_unlock (ready_lock[i]);
618 }
619 if (ready_count == THREAD_COUNT)
620 break;
621 yield ();
622 }
623 dbgprintf ("Main thread after synchronizing for round %d\n", repeat);
624  
625 if (repeat > 0)
626 {
627 /* Check that exactly one thread executed the once_execute()
628 function. */
629 if (performed != 1)
630 abort ();
631 }
632  
633 if (repeat == REPEAT_COUNT)
634 break;
635  
636 /* Preparation for the next round: Initialize once_control. */
637 memcpy (&once_control, &fresh_once, sizeof (gl_once_t));
638  
639 /* Preparation for the next round: Reset the performed counter. */
640 performed = 0;
641  
642 /* Preparation for the next round: Reset the ready flags. */
643 for (i = 0; i < THREAD_COUNT; i++)
644 {
645 gl_lock_lock (ready_lock[i]);
646 ready[i] = 0;
647 gl_lock_unlock (ready_lock[i]);
648 }
649  
650 /* Signal all threads simultaneously. */
651 dbgprintf ("Main thread giving signal for round %d\n", repeat);
652 #if ENABLE_LOCKING
653 gl_rwlock_unlock (fire_signal[repeat]);
654 #else
655 fire_signal_state = repeat + 1;
656 #endif
657 }
658  
659 /* Wait for the threads to terminate. */
660 for (i = 0; i < THREAD_COUNT; i++)
661 gl_thread_join (threads[i], NULL);
662 }
663  
664  
665 /* -------------------------------------------------------------------------- */
666  
667 int
668 main ()
669 {
670 #if TEST_PTH_THREADS
671 if (!pth_init ())
672 abort ();
673 #endif
674  
675 #if DO_TEST_LOCK
676 printf ("Starting test_lock ..."); fflush (stdout);
677 test_lock ();
678 printf (" OK\n"); fflush (stdout);
679 #endif
680 #if DO_TEST_RWLOCK
681 printf ("Starting test_rwlock ..."); fflush (stdout);
682 test_rwlock ();
683 printf (" OK\n"); fflush (stdout);
684 #endif
685 #if DO_TEST_RECURSIVE_LOCK
686 printf ("Starting test_recursive_lock ..."); fflush (stdout);
687 test_recursive_lock ();
688 printf (" OK\n"); fflush (stdout);
689 #endif
690 #if DO_TEST_ONCE
691 printf ("Starting test_once ..."); fflush (stdout);
692 test_once ();
693 printf (" OK\n"); fflush (stdout);
694 #endif
695  
696 return 0;
697 }
698  
699 #else
700  
701 /* No multithreading available. */
702  
703 #include <stdio.h>
704  
705 int
706 main ()
707 {
708 fputs ("Skipping test: multithreading not enabled\n", stderr);
709 return 77;
710 }
711  
712 #endif