root/maint/gnulib/tests/test-pthread-rwlock.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. random_account
  2. check_accounts
  3. rwlock_mutator_thread
  4. rwlock_checker_thread
  5. test_rwlock
  6. main
  7. main

   1 /* Test of read-write locks in multithreaded situations.
   2    Copyright (C) 2005, 2008-2021 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_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
  22 
  23 /* Whether to enable locking.
  24    Uncomment this to get a test program without locking, to verify that
  25    it crashes.  */
  26 #define ENABLE_LOCKING 1
  27 
  28 /* Whether to help the scheduler through explicit sched_yield().
  29    Uncomment this to see if the operating system has a fair scheduler.  */
  30 #define EXPLICIT_YIELD 1
  31 
  32 /* Whether to print debugging messages.  */
  33 #define ENABLE_DEBUGGING 0
  34 
  35 /* Number of simultaneous threads.  */
  36 #define THREAD_COUNT 10
  37 
  38 /* Number of operations performed in each thread.
  39    This is quite high, because with a smaller count, say 5000, we often get
  40    an "OK" result even without ENABLE_LOCKING (on Linux/x86).  */
  41 #define REPEAT_COUNT 50000
  42 
  43 #include <pthread.h>
  44 #include <stdint.h>
  45 #include <stdio.h>
  46 #include <stdlib.h>
  47 #include <string.h>
  48 
  49 #if EXPLICIT_YIELD
  50 # include <sched.h>
  51 #endif
  52 
  53 #if HAVE_DECL_ALARM
  54 # include <signal.h>
  55 # include <unistd.h>
  56 #endif
  57 
  58 #include "macros.h"
  59 #include "atomic-int-posix.h"
  60 
  61 #if ENABLE_DEBUGGING
  62 # define dbgprintf printf
  63 #else
  64 # define dbgprintf if (0) printf
  65 #endif
  66 
  67 #if EXPLICIT_YIELD
  68 # define yield() sched_yield ()
  69 #else
  70 # define yield()
  71 #endif
  72 
  73 /* Returns a reference to the current thread as a pointer, for debugging.  */
  74 #if defined __MVS__
  75   /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field.
  76      The first three bytes of this field appear to uniquely identify a
  77      pthread_t, though not necessarily representing a pointer.  */
  78 # define pthread_self_pointer() (*((void **) pthread_self ().__))
  79 #else
  80 # define pthread_self_pointer() ((void *) (uintptr_t) pthread_self ())
  81 #endif
  82 
  83 #define ACCOUNT_COUNT 4
  84 
  85 static int account[ACCOUNT_COUNT];
  86 
  87 static int
  88 random_account (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90   return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
  91 }
  92 
  93 static void
  94 check_accounts (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96   int i, sum;
  97 
  98   sum = 0;
  99   for (i = 0; i < ACCOUNT_COUNT; i++)
 100     sum += account[i];
 101   if (sum != ACCOUNT_COUNT * 1000)
 102     abort ();
 103 }
 104 
 105 
 106 /* ----------------- Test read-write (non-recursive) locks ----------------- */
 107 
 108 /* Test read-write locks by having several bank accounts and several threads
 109    which shuffle around money between the accounts and several other threads
 110    that check that all the money is still there.  */
 111 
 112 static pthread_rwlock_t my_rwlock = PTHREAD_RWLOCK_INITIALIZER;
 113 
 114 static void *
 115 rwlock_mutator_thread (void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 116 {
 117   int repeat;
 118 
 119   for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
 120     {
 121       int i1, i2, value;
 122 
 123       dbgprintf ("Mutator %p before wrlock\n", pthread_self_pointer ());
 124       ASSERT (pthread_rwlock_wrlock (&my_rwlock) == 0);
 125       dbgprintf ("Mutator %p after  wrlock\n", pthread_self_pointer ());
 126 
 127       i1 = random_account ();
 128       i2 = random_account ();
 129       value = ((unsigned int) rand () >> 3) % 10;
 130       account[i1] += value;
 131       account[i2] -= value;
 132 
 133       dbgprintf ("Mutator %p before unlock\n", pthread_self_pointer ());
 134       ASSERT (pthread_rwlock_unlock (&my_rwlock) == 0);
 135       dbgprintf ("Mutator %p after  unlock\n", pthread_self_pointer ());
 136 
 137       yield ();
 138     }
 139 
 140   dbgprintf ("Mutator %p dying.\n", pthread_self_pointer ());
 141   return NULL;
 142 }
 143 
 144 static struct atomic_int rwlock_checker_done;
 145 
 146 static void *
 147 rwlock_checker_thread (void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149   while (get_atomic_int_value (&rwlock_checker_done) == 0)
 150     {
 151       dbgprintf ("Checker %p before check rdlock\n", pthread_self_pointer ());
 152       ASSERT (pthread_rwlock_rdlock (&my_rwlock) == 0);
 153       check_accounts ();
 154       ASSERT (pthread_rwlock_unlock (&my_rwlock) == 0);
 155       dbgprintf ("Checker %p after  check unlock\n", pthread_self_pointer ());
 156 
 157       yield ();
 158     }
 159 
 160   dbgprintf ("Checker %p dying.\n", pthread_self_pointer ());
 161   return NULL;
 162 }
 163 
 164 static void
 165 test_rwlock (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167   int i;
 168   pthread_t checkerthreads[THREAD_COUNT];
 169   pthread_t threads[THREAD_COUNT];
 170 
 171   /* Initialization.  */
 172   for (i = 0; i < ACCOUNT_COUNT; i++)
 173     account[i] = 1000;
 174   init_atomic_int (&rwlock_checker_done);
 175   set_atomic_int_value (&rwlock_checker_done, 0);
 176 
 177   /* Spawn the threads.  */
 178   for (i = 0; i < THREAD_COUNT; i++)
 179     ASSERT (pthread_create (&checkerthreads[i], NULL,
 180                             rwlock_checker_thread, NULL)
 181             == 0);
 182   for (i = 0; i < THREAD_COUNT; i++)
 183     ASSERT (pthread_create (&threads[i], NULL, rwlock_mutator_thread, NULL)
 184             == 0);
 185 
 186   /* Wait for the threads to terminate.  */
 187   for (i = 0; i < THREAD_COUNT; i++)
 188     ASSERT (pthread_join (threads[i], NULL) == 0);
 189   set_atomic_int_value (&rwlock_checker_done, 1);
 190   for (i = 0; i < THREAD_COUNT; i++)
 191     ASSERT (pthread_join (checkerthreads[i], NULL) == 0);
 192   check_accounts ();
 193 }
 194 
 195 
 196 /* -------------------------------------------------------------------------- */
 197 
 198 int
 199 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201 #if HAVE_DECL_ALARM
 202   /* Declare failure if test takes too long, by using default abort
 203      caused by SIGALRM.  */
 204   int alarm_value = 600;
 205   signal (SIGALRM, SIG_DFL);
 206   alarm (alarm_value);
 207 #endif
 208 
 209   printf ("Starting test_rwlock ..."); fflush (stdout);
 210   test_rwlock ();
 211   printf (" OK\n"); fflush (stdout);
 212 
 213   return 0;
 214 }
 215 
 216 #else
 217 
 218 /* No multithreading available.  */
 219 
 220 #include <stdio.h>
 221 
 222 int
 223 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 224 {
 225   fputs ("Skipping test: multithreading not enabled\n", stderr);
 226   return 77;
 227 }
 228 
 229 #endif

/* [previous][next][first][last][top][bottom][index][help] */