LCOV - code coverage report
Current view: top level - lib/gltests - test-lock.c (source / functions) Hit Total Coverage
Test: GNU Libidn Lines: 179 181 98.9 %
Date: 2015-07-08 23:12:53 Functions: 16 16 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Test of locking in multithreaded situations.
       2             :    Copyright (C) 2005, 2008-2015 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     1895258 : check_accounts (void)
     118             : {
     119             :   int i, sum;
     120             : 
     121     1895258 :   sum = 0;
     122     9458755 :   for (i = 0; i < ACCOUNT_COUNT; i++)
     123     7563497 :     sum += account[i];
     124     1895258 :   if (sum != ACCOUNT_COUNT * 1000)
     125           0 :     abort ();
     126     1895258 : }
     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        1611 : lock_mutator_thread (void *arg)
     139             : {
     140             :   int repeat;
     141             : 
     142      496186 :   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      496176 :       gl_lock_lock (my_lock);
     148             :       dbgprintf ("Mutator %p after  lock\n", gl_thread_self_pointer ());
     149             : 
     150      500744 :       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      498393 :       gl_lock_lock (my_lock);
     162      500445 :       check_accounts ();
     163      500000 :       gl_lock_unlock (my_lock);
     164             :       dbgprintf ("Mutator %p after  check unlock\n", gl_thread_self_pointer ());
     165             : 
     166      497808 :       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       96523 :   while (!lock_checker_done)
     179             :     {
     180             :       dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
     181       96521 :       gl_lock_lock (my_lock);
     182       96521 :       check_accounts ();
     183       96521 :       gl_lock_unlock (my_lock);
     184             :       dbgprintf ("Checker %p after  check unlock\n", gl_thread_self_pointer ());
     185             : 
     186       96521 :       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         938 : rwlock_mutator_thread (void *arg)
     229             : {
     230             :   int repeat;
     231             : 
     232      497071 :   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      497061 :       gl_rwlock_wrlock (my_rwlock);
     238             :       dbgprintf ("Mutator %p after  wrlock\n", gl_thread_self_pointer ());
     239             : 
     240      500296 :       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      497381 :       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      687761 :   while (!rwlock_checker_done)
     263             :     {
     264             :       dbgprintf ("Checker %p before check rdlock\n", gl_thread_self_pointer ());
     265      687741 :       gl_rwlock_rdlock (my_rwlock);
     266      698576 :       check_accounts ();
     267      697394 :       gl_rwlock_unlock (my_rwlock);
     268             :       dbgprintf ("Checker %p after  check unlock\n", gl_thread_self_pointer ());
     269             : 
     270      695301 :       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      992902 : recshuffle (void)
     315             : {
     316             :   int i1, i2, value;
     317             : 
     318             :   dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
     319      992902 :   gl_recursive_lock_lock (my_reclock);
     320             :   dbgprintf ("Mutator %p after  lock\n", gl_thread_self_pointer ());
     321             : 
     322     1000716 :   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      998338 : }
     336             : 
     337             : static void *
     338         883 : reclock_mutator_thread (void *arg)
     339             : {
     340             :   int repeat;
     341             : 
     342      497489 :   for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
     343             :     {
     344      497479 :       recshuffle ();
     345             : 
     346             :       dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
     347      497971 :       gl_recursive_lock_lock (my_reclock);
     348      499419 :       check_accounts ();
     349      500000 :       gl_recursive_lock_unlock (my_reclock);
     350             :       dbgprintf ("Mutator %p after  check unlock\n", gl_thread_self_pointer ());
     351             : 
     352      498105 :       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      101312 :   while (!reclock_checker_done)
     365             :     {
     366             :       dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
     367      101310 :       gl_recursive_lock_lock (my_reclock);
     368      101310 :       check_accounts ();
     369      101310 :       gl_recursive_lock_unlock (my_reclock);
     370             :       dbgprintf ("Checker %p after  check unlock\n", gl_thread_self_pointer ());
     371             : 
     372      101310 :       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        6010 : once_contender_thread (void *arg)
     432             : {
     433        6010 :   int id = (int) (long) arg;
     434             :   int repeat;
     435             : 
     436      493424 :   for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
     437             :     {
     438             :       /* Tell the main thread that we're ready.  */
     439      493424 :       gl_lock_lock (ready_lock[id]);
     440      492383 :       ready[id] = 1;
     441      492383 :       gl_lock_unlock (ready_lock[id]);
     442             : 
     443      501032 :       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      501022 :       gl_rwlock_rdlock (fire_signal[repeat]);
     451             :       /* And don't hinder the others (if the scheduler is unfair).  */
     452      502921 :       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      489014 :       gl_once (once_control, once_execute);
     463             :     }
     464             : 
     465          10 :   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      738432 :           int ready_count = 0;
     502     8122752 :           for (i = 0; i < THREAD_COUNT; i++)
     503             :             {
     504     7384320 :               gl_lock_lock (ready_lock[i]);
     505     7384320 :               ready_count += ready[i];
     506     7384320 :               gl_lock_unlock (ready_lock[i]);
     507             :             }
     508      738432 :           if (ready_count == THREAD_COUNT)
     509       50001 :             break;
     510      688431 :           yield ();
     511      688431 :         }
     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

Generated by: LCOV version 1.11