"Fossies" - the Fresh Open Source Software Archive

Member "gnuastro-0.8/bootstrapped/tests/test-lock.c" (28 Dec 2018, 19951 Bytes) of package /linux/privat/gnuastro-0.8.tar.lz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "test-lock.c": 0.5_vs_0.6.

    1 /* Test of locking in multithreaded situations.
    2    Copyright (C) 2005, 2008-2018 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 <https://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 use 'volatile' on some variables that communicate information
   54    between threads.  If set to 0, a semaphore or a lock is used to protect
   55    these variables.  If set to 1, 'volatile' is used; this is theoretically
   56    equivalent but can lead to much slower execution (e.g. 30x slower total
   57    run time on a 40-core machine), because 'volatile' does not imply any
   58    synchronization/communication between different CPUs.  */
   59 #define USE_VOLATILE 0
   60 
   61 #if USE_POSIX_THREADS && HAVE_SEMAPHORE_H
   62 /* Whether to use a semaphore to communicate information between threads.
   63    If set to 0, a lock is used. If set to 1, a semaphore is used.
   64    Uncomment this to reduce the dependencies of this test.  */
   65 # define USE_SEMAPHORE 1
   66 /* Mac OS X provides only named semaphores (sem_open); its facility for
   67    unnamed semaphores (sem_init) does not work.  */
   68 # if defined __APPLE__ && defined __MACH__
   69 #  define USE_NAMED_SEMAPHORE 1
   70 # else
   71 #  define USE_UNNAMED_SEMAPHORE 1
   72 # endif
   73 #endif
   74 
   75 /* Whether to print debugging messages.  */
   76 #define ENABLE_DEBUGGING 0
   77 
   78 /* Number of simultaneous threads.  */
   79 #define THREAD_COUNT 10
   80 
   81 /* Number of operations performed in each thread.
   82    This is quite high, because with a smaller count, say 5000, we often get
   83    an "OK" result even without ENABLE_LOCKING (on Linux/x86).  */
   84 #define REPEAT_COUNT 50000
   85 
   86 #include <stdio.h>
   87 #include <stdlib.h>
   88 #include <string.h>
   89 
   90 #if !ENABLE_LOCKING
   91 # undef USE_POSIX_THREADS
   92 # undef USE_SOLARIS_THREADS
   93 # undef USE_PTH_THREADS
   94 # undef USE_WINDOWS_THREADS
   95 #endif
   96 #include "glthread/lock.h"
   97 
   98 #if !ENABLE_LOCKING
   99 # if TEST_POSIX_THREADS
  100 #  define USE_POSIX_THREADS 1
  101 # endif
  102 # if TEST_SOLARIS_THREADS
  103 #  define USE_SOLARIS_THREADS 1
  104 # endif
  105 # if TEST_PTH_THREADS
  106 #  define USE_PTH_THREADS 1
  107 # endif
  108 # if TEST_WINDOWS_THREADS
  109 #  define USE_WINDOWS_THREADS 1
  110 # endif
  111 #endif
  112 
  113 #include "glthread/thread.h"
  114 #include "glthread/yield.h"
  115 #if USE_SEMAPHORE
  116 # include <errno.h>
  117 # include <fcntl.h>
  118 # include <semaphore.h>
  119 # include <unistd.h>
  120 #endif
  121 
  122 #if ENABLE_DEBUGGING
  123 # define dbgprintf printf
  124 #else
  125 # define dbgprintf if (0) printf
  126 #endif
  127 
  128 #if EXPLICIT_YIELD
  129 # define yield() gl_thread_yield ()
  130 #else
  131 # define yield()
  132 #endif
  133 
  134 #if USE_VOLATILE
  135 struct atomic_int {
  136   volatile int value;
  137 };
  138 static void
  139 init_atomic_int (struct atomic_int *ai)
  140 {
  141 }
  142 static int
  143 get_atomic_int_value (struct atomic_int *ai)
  144 {
  145   return ai->value;
  146 }
  147 static void
  148 set_atomic_int_value (struct atomic_int *ai, int new_value)
  149 {
  150   ai->value = new_value;
  151 }
  152 #elif USE_SEMAPHORE
  153 /* This atomic_int implementation can only support the values 0 and 1.
  154    It is initially 0 and can be set to 1 only once.  */
  155 # if USE_UNNAMED_SEMAPHORE
  156 struct atomic_int {
  157   sem_t semaphore;
  158 };
  159 #define atomic_int_semaphore(ai) (&(ai)->semaphore)
  160 static void
  161 init_atomic_int (struct atomic_int *ai)
  162 {
  163   sem_init (&ai->semaphore, 0, 0);
  164 }
  165 # endif
  166 # if USE_NAMED_SEMAPHORE
  167 struct atomic_int {
  168   sem_t *semaphore;
  169 };
  170 #define atomic_int_semaphore(ai) ((ai)->semaphore)
  171 static void
  172 init_atomic_int (struct atomic_int *ai)
  173 {
  174   sem_t *s;
  175   unsigned int count;
  176   for (count = 0; ; count++)
  177     {
  178       char name[80];
  179       /* Use getpid() in the name, so that different processes running at the
  180          same time will not interfere.  Use ai in the name, so that different
  181          atomic_int in the same process will not interfere.  Use a count in
  182          the name, so that even in the (unlikely) case that a semaphore with
  183          the specified name already exists, we can try a different name.  */
  184       sprintf (name, "test-lock-%lu-%p-%u",
  185                (unsigned long) getpid (), ai, count);
  186       s = sem_open (name, O_CREAT | O_EXCL, 0600, 0);
  187       if (s == SEM_FAILED)
  188         {
  189           if (errno == EEXIST)
  190             /* Retry with a different name.  */
  191             continue;
  192           else
  193             {
  194               perror ("sem_open failed");
  195               abort ();
  196             }
  197         }
  198       else
  199         {
  200           /* Try not to leave a semaphore hanging around on the file system
  201              eternally, if we can avoid it.  */
  202           sem_unlink (name);
  203           break;
  204         }
  205     }
  206   ai->semaphore = s;
  207 }
  208 # endif
  209 static int
  210 get_atomic_int_value (struct atomic_int *ai)
  211 {
  212   if (sem_trywait (atomic_int_semaphore (ai)) == 0)
  213     {
  214       if (sem_post (atomic_int_semaphore (ai)))
  215         abort ();
  216       return 1;
  217     }
  218   else if (errno == EAGAIN)
  219     return 0;
  220   else
  221     abort ();
  222 }
  223 static void
  224 set_atomic_int_value (struct atomic_int *ai, int new_value)
  225 {
  226   if (new_value == 0)
  227     /* It's already initialized with 0.  */
  228     return;
  229   /* To set the value 1: */
  230   if (sem_post (atomic_int_semaphore (ai)))
  231     abort ();
  232 }
  233 #else
  234 struct atomic_int {
  235   gl_lock_define (, lock)
  236   int value;
  237 };
  238 static void
  239 init_atomic_int (struct atomic_int *ai)
  240 {
  241   gl_lock_init (ai->lock);
  242 }
  243 static int
  244 get_atomic_int_value (struct atomic_int *ai)
  245 {
  246   gl_lock_lock (ai->lock);
  247   int ret = ai->value;
  248   gl_lock_unlock (ai->lock);
  249   return ret;
  250 }
  251 static void
  252 set_atomic_int_value (struct atomic_int *ai, int new_value)
  253 {
  254   gl_lock_lock (ai->lock);
  255   ai->value = new_value;
  256   gl_lock_unlock (ai->lock);
  257 }
  258 #endif
  259 
  260 #define ACCOUNT_COUNT 4
  261 
  262 static int account[ACCOUNT_COUNT];
  263 
  264 static int
  265 random_account (void)
  266 {
  267   return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
  268 }
  269 
  270 static void
  271 check_accounts (void)
  272 {
  273   int i, sum;
  274 
  275   sum = 0;
  276   for (i = 0; i < ACCOUNT_COUNT; i++)
  277     sum += account[i];
  278   if (sum != ACCOUNT_COUNT * 1000)
  279     abort ();
  280 }
  281 
  282 
  283 /* ------------------- Test normal (non-recursive) locks ------------------- */
  284 
  285 /* Test normal locks by having several bank accounts and several threads
  286    which shuffle around money between the accounts and another thread
  287    checking that all the money is still there.  */
  288 
  289 gl_lock_define_initialized(static, my_lock)
  290 
  291 static void *
  292 lock_mutator_thread (void *arg)
  293 {
  294   int repeat;
  295 
  296   for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
  297     {
  298       int i1, i2, value;
  299 
  300       dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
  301       gl_lock_lock (my_lock);
  302       dbgprintf ("Mutator %p after  lock\n", gl_thread_self_pointer ());
  303 
  304       i1 = random_account ();
  305       i2 = random_account ();
  306       value = ((unsigned int) rand () >> 3) % 10;
  307       account[i1] += value;
  308       account[i2] -= value;
  309 
  310       dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
  311       gl_lock_unlock (my_lock);
  312       dbgprintf ("Mutator %p after  unlock\n", gl_thread_self_pointer ());
  313 
  314       dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
  315       gl_lock_lock (my_lock);
  316       check_accounts ();
  317       gl_lock_unlock (my_lock);
  318       dbgprintf ("Mutator %p after  check unlock\n", gl_thread_self_pointer ());
  319 
  320       yield ();
  321     }
  322 
  323   dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
  324   return NULL;
  325 }
  326 
  327 static struct atomic_int lock_checker_done;
  328 
  329 static void *
  330 lock_checker_thread (void *arg)
  331 {
  332   while (get_atomic_int_value (&lock_checker_done) == 0)
  333     {
  334       dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
  335       gl_lock_lock (my_lock);
  336       check_accounts ();
  337       gl_lock_unlock (my_lock);
  338       dbgprintf ("Checker %p after  check unlock\n", gl_thread_self_pointer ());
  339 
  340       yield ();
  341     }
  342 
  343   dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
  344   return NULL;
  345 }
  346 
  347 static void
  348 test_lock (void)
  349 {
  350   int i;
  351   gl_thread_t checkerthread;
  352   gl_thread_t threads[THREAD_COUNT];
  353 
  354   /* Initialization.  */
  355   for (i = 0; i < ACCOUNT_COUNT; i++)
  356     account[i] = 1000;
  357   init_atomic_int (&lock_checker_done);
  358   set_atomic_int_value (&lock_checker_done, 0);
  359 
  360   /* Spawn the threads.  */
  361   checkerthread = gl_thread_create (lock_checker_thread, NULL);
  362   for (i = 0; i < THREAD_COUNT; i++)
  363     threads[i] = gl_thread_create (lock_mutator_thread, NULL);
  364 
  365   /* Wait for the threads to terminate.  */
  366   for (i = 0; i < THREAD_COUNT; i++)
  367     gl_thread_join (threads[i], NULL);
  368   set_atomic_int_value (&lock_checker_done, 1);
  369   gl_thread_join (checkerthread, NULL);
  370   check_accounts ();
  371 }
  372 
  373 
  374 /* ----------------- Test read-write (non-recursive) locks ----------------- */
  375 
  376 /* Test read-write locks by having several bank accounts and several threads
  377    which shuffle around money between the accounts and several other threads
  378    that check that all the money is still there.  */
  379 
  380 gl_rwlock_define_initialized(static, my_rwlock)
  381 
  382 static void *
  383 rwlock_mutator_thread (void *arg)
  384 {
  385   int repeat;
  386 
  387   for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
  388     {
  389       int i1, i2, value;
  390 
  391       dbgprintf ("Mutator %p before wrlock\n", gl_thread_self_pointer ());
  392       gl_rwlock_wrlock (my_rwlock);
  393       dbgprintf ("Mutator %p after  wrlock\n", gl_thread_self_pointer ());
  394 
  395       i1 = random_account ();
  396       i2 = random_account ();
  397       value = ((unsigned int) rand () >> 3) % 10;
  398       account[i1] += value;
  399       account[i2] -= value;
  400 
  401       dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
  402       gl_rwlock_unlock (my_rwlock);
  403       dbgprintf ("Mutator %p after  unlock\n", gl_thread_self_pointer ());
  404 
  405       yield ();
  406     }
  407 
  408   dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
  409   return NULL;
  410 }
  411 
  412 static struct atomic_int rwlock_checker_done;
  413 
  414 static void *
  415 rwlock_checker_thread (void *arg)
  416 {
  417   while (get_atomic_int_value (&rwlock_checker_done) == 0)
  418     {
  419       dbgprintf ("Checker %p before check rdlock\n", gl_thread_self_pointer ());
  420       gl_rwlock_rdlock (my_rwlock);
  421       check_accounts ();
  422       gl_rwlock_unlock (my_rwlock);
  423       dbgprintf ("Checker %p after  check unlock\n", gl_thread_self_pointer ());
  424 
  425       yield ();
  426     }
  427 
  428   dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
  429   return NULL;
  430 }
  431 
  432 static void
  433 test_rwlock (void)
  434 {
  435   int i;
  436   gl_thread_t checkerthreads[THREAD_COUNT];
  437   gl_thread_t threads[THREAD_COUNT];
  438 
  439   /* Initialization.  */
  440   for (i = 0; i < ACCOUNT_COUNT; i++)
  441     account[i] = 1000;
  442   init_atomic_int (&rwlock_checker_done);
  443   set_atomic_int_value (&rwlock_checker_done, 0);
  444 
  445   /* Spawn the threads.  */
  446   for (i = 0; i < THREAD_COUNT; i++)
  447     checkerthreads[i] = gl_thread_create (rwlock_checker_thread, NULL);
  448   for (i = 0; i < THREAD_COUNT; i++)
  449     threads[i] = gl_thread_create (rwlock_mutator_thread, NULL);
  450 
  451   /* Wait for the threads to terminate.  */
  452   for (i = 0; i < THREAD_COUNT; i++)
  453     gl_thread_join (threads[i], NULL);
  454   set_atomic_int_value (&rwlock_checker_done, 1);
  455   for (i = 0; i < THREAD_COUNT; i++)
  456     gl_thread_join (checkerthreads[i], NULL);
  457   check_accounts ();
  458 }
  459 
  460 
  461 /* -------------------------- Test recursive locks -------------------------- */
  462 
  463 /* Test recursive locks by having several bank accounts and several threads
  464    which shuffle around money between the accounts (recursively) and another
  465    thread checking that all the money is still there.  */
  466 
  467 gl_recursive_lock_define_initialized(static, my_reclock)
  468 
  469 static void
  470 recshuffle (void)
  471 {
  472   int i1, i2, value;
  473 
  474   dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
  475   gl_recursive_lock_lock (my_reclock);
  476   dbgprintf ("Mutator %p after  lock\n", gl_thread_self_pointer ());
  477 
  478   i1 = random_account ();
  479   i2 = random_account ();
  480   value = ((unsigned int) rand () >> 3) % 10;
  481   account[i1] += value;
  482   account[i2] -= value;
  483 
  484   /* Recursive with probability 0.5.  */
  485   if (((unsigned int) rand () >> 3) % 2)
  486     recshuffle ();
  487 
  488   dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
  489   gl_recursive_lock_unlock (my_reclock);
  490   dbgprintf ("Mutator %p after  unlock\n", gl_thread_self_pointer ());
  491 }
  492 
  493 static void *
  494 reclock_mutator_thread (void *arg)
  495 {
  496   int repeat;
  497 
  498   for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
  499     {
  500       recshuffle ();
  501 
  502       dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
  503       gl_recursive_lock_lock (my_reclock);
  504       check_accounts ();
  505       gl_recursive_lock_unlock (my_reclock);
  506       dbgprintf ("Mutator %p after  check unlock\n", gl_thread_self_pointer ());
  507 
  508       yield ();
  509     }
  510 
  511   dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
  512   return NULL;
  513 }
  514 
  515 static struct atomic_int reclock_checker_done;
  516 
  517 static void *
  518 reclock_checker_thread (void *arg)
  519 {
  520   while (get_atomic_int_value (&reclock_checker_done) == 0)
  521     {
  522       dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
  523       gl_recursive_lock_lock (my_reclock);
  524       check_accounts ();
  525       gl_recursive_lock_unlock (my_reclock);
  526       dbgprintf ("Checker %p after  check unlock\n", gl_thread_self_pointer ());
  527 
  528       yield ();
  529     }
  530 
  531   dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
  532   return NULL;
  533 }
  534 
  535 static void
  536 test_recursive_lock (void)
  537 {
  538   int i;
  539   gl_thread_t checkerthread;
  540   gl_thread_t threads[THREAD_COUNT];
  541 
  542   /* Initialization.  */
  543   for (i = 0; i < ACCOUNT_COUNT; i++)
  544     account[i] = 1000;
  545   init_atomic_int (&reclock_checker_done);
  546   set_atomic_int_value (&reclock_checker_done, 0);
  547 
  548   /* Spawn the threads.  */
  549   checkerthread = gl_thread_create (reclock_checker_thread, NULL);
  550   for (i = 0; i < THREAD_COUNT; i++)
  551     threads[i] = gl_thread_create (reclock_mutator_thread, NULL);
  552 
  553   /* Wait for the threads to terminate.  */
  554   for (i = 0; i < THREAD_COUNT; i++)
  555     gl_thread_join (threads[i], NULL);
  556   set_atomic_int_value (&reclock_checker_done, 1);
  557   gl_thread_join (checkerthread, NULL);
  558   check_accounts ();
  559 }
  560 
  561 
  562 /* ------------------------ Test once-only execution ------------------------ */
  563 
  564 /* Test once-only execution by having several threads attempt to grab a
  565    once-only task simultaneously (triggered by releasing a read-write lock).  */
  566 
  567 gl_once_define(static, fresh_once)
  568 static int ready[THREAD_COUNT];
  569 static gl_lock_t ready_lock[THREAD_COUNT];
  570 #if ENABLE_LOCKING
  571 static gl_rwlock_t fire_signal[REPEAT_COUNT];
  572 #else
  573 static volatile int fire_signal_state;
  574 #endif
  575 static gl_once_t once_control;
  576 static int performed;
  577 gl_lock_define_initialized(static, performed_lock)
  578 
  579 static void
  580 once_execute (void)
  581 {
  582   gl_lock_lock (performed_lock);
  583   performed++;
  584   gl_lock_unlock (performed_lock);
  585 }
  586 
  587 static void *
  588 once_contender_thread (void *arg)
  589 {
  590   int id = (int) (long) arg;
  591   int repeat;
  592 
  593   for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
  594     {
  595       /* Tell the main thread that we're ready.  */
  596       gl_lock_lock (ready_lock[id]);
  597       ready[id] = 1;
  598       gl_lock_unlock (ready_lock[id]);
  599 
  600       if (repeat == REPEAT_COUNT)
  601         break;
  602 
  603       dbgprintf ("Contender %p waiting for signal for round %d\n",
  604                  gl_thread_self_pointer (), repeat);
  605 #if ENABLE_LOCKING
  606       /* Wait for the signal to go.  */
  607       gl_rwlock_rdlock (fire_signal[repeat]);
  608       /* And don't hinder the others (if the scheduler is unfair).  */
  609       gl_rwlock_unlock (fire_signal[repeat]);
  610 #else
  611       /* Wait for the signal to go.  */
  612       while (fire_signal_state <= repeat)
  613         yield ();
  614 #endif
  615       dbgprintf ("Contender %p got the     signal for round %d\n",
  616                  gl_thread_self_pointer (), repeat);
  617 
  618       /* Contend for execution.  */
  619       gl_once (once_control, once_execute);
  620     }
  621 
  622   return NULL;
  623 }
  624 
  625 static void
  626 test_once (void)
  627 {
  628   int i, repeat;
  629   gl_thread_t threads[THREAD_COUNT];
  630 
  631   /* Initialize all variables.  */
  632   for (i = 0; i < THREAD_COUNT; i++)
  633     {
  634       ready[i] = 0;
  635       gl_lock_init (ready_lock[i]);
  636     }
  637 #if ENABLE_LOCKING
  638   for (i = 0; i < REPEAT_COUNT; i++)
  639     gl_rwlock_init (fire_signal[i]);
  640 #else
  641   fire_signal_state = 0;
  642 #endif
  643 
  644   /* Block all fire_signals.  */
  645   for (i = REPEAT_COUNT-1; i >= 0; i--)
  646     gl_rwlock_wrlock (fire_signal[i]);
  647 
  648   /* Spawn the threads.  */
  649   for (i = 0; i < THREAD_COUNT; i++)
  650     threads[i] = gl_thread_create (once_contender_thread, (void *) (long) i);
  651 
  652   for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
  653     {
  654       /* Wait until every thread is ready.  */
  655       dbgprintf ("Main thread before synchronizing for round %d\n", repeat);
  656       for (;;)
  657         {
  658           int ready_count = 0;
  659           for (i = 0; i < THREAD_COUNT; i++)
  660             {
  661               gl_lock_lock (ready_lock[i]);
  662               ready_count += ready[i];
  663               gl_lock_unlock (ready_lock[i]);
  664             }
  665           if (ready_count == THREAD_COUNT)
  666             break;
  667           yield ();
  668         }
  669       dbgprintf ("Main thread after  synchronizing for round %d\n", repeat);
  670 
  671       if (repeat > 0)
  672         {
  673           /* Check that exactly one thread executed the once_execute()
  674              function.  */
  675           if (performed != 1)
  676             abort ();
  677         }
  678 
  679       if (repeat == REPEAT_COUNT)
  680         break;
  681 
  682       /* Preparation for the next round: Initialize once_control.  */
  683       memcpy (&once_control, &fresh_once, sizeof (gl_once_t));
  684 
  685       /* Preparation for the next round: Reset the performed counter.  */
  686       performed = 0;
  687 
  688       /* Preparation for the next round: Reset the ready flags.  */
  689       for (i = 0; i < THREAD_COUNT; i++)
  690         {
  691           gl_lock_lock (ready_lock[i]);
  692           ready[i] = 0;
  693           gl_lock_unlock (ready_lock[i]);
  694         }
  695 
  696       /* Signal all threads simultaneously.  */
  697       dbgprintf ("Main thread giving signal for round %d\n", repeat);
  698 #if ENABLE_LOCKING
  699       gl_rwlock_unlock (fire_signal[repeat]);
  700 #else
  701       fire_signal_state = repeat + 1;
  702 #endif
  703     }
  704 
  705   /* Wait for the threads to terminate.  */
  706   for (i = 0; i < THREAD_COUNT; i++)
  707     gl_thread_join (threads[i], NULL);
  708 }
  709 
  710 
  711 /* -------------------------------------------------------------------------- */
  712 
  713 int
  714 main ()
  715 {
  716 #if TEST_PTH_THREADS
  717   if (!pth_init ())
  718     abort ();
  719 #endif
  720 
  721 #if DO_TEST_LOCK
  722   printf ("Starting test_lock ..."); fflush (stdout);
  723   test_lock ();
  724   printf (" OK\n"); fflush (stdout);
  725 #endif
  726 #if DO_TEST_RWLOCK
  727   printf ("Starting test_rwlock ..."); fflush (stdout);
  728   test_rwlock ();
  729   printf (" OK\n"); fflush (stdout);
  730 #endif
  731 #if DO_TEST_RECURSIVE_LOCK
  732   printf ("Starting test_recursive_lock ..."); fflush (stdout);
  733   test_recursive_lock ();
  734   printf (" OK\n"); fflush (stdout);
  735 #endif
  736 #if DO_TEST_ONCE
  737   printf ("Starting test_once ..."); fflush (stdout);
  738   test_once ();
  739   printf (" OK\n"); fflush (stdout);
  740 #endif
  741 
  742   return 0;
  743 }
  744 
  745 #else
  746 
  747 /* No multithreading available.  */
  748 
  749 #include <stdio.h>
  750 
  751 int
  752 main ()
  753 {
  754   fputs ("Skipping test: multithreading not enabled\n", stderr);
  755   return 77;
  756 }
  757 
  758 #endif