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

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

DEFINITIONS

This source file includes following definitions.
  1. random_account
  2. check_accounts
  3. lock_mutator_thread
  4. lock_checker_thread
  5. test_pthread_spin
  6. main
  7. main

   1 /* Test of POSIX spin locks.
   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 #define REPEAT_COUNT 50000
  40 
  41 #include <pthread.h>
  42 #include <stdint.h>
  43 #include <stdio.h>
  44 #include <stdlib.h>
  45 #include <string.h>
  46 
  47 #if EXPLICIT_YIELD
  48 # include <sched.h>
  49 #endif
  50 
  51 #if HAVE_DECL_ALARM
  52 # include <signal.h>
  53 # include <unistd.h>
  54 #endif
  55 
  56 #include "macros.h"
  57 #include "atomic-int-posix.h"
  58 
  59 #if ENABLE_DEBUGGING
  60 # define dbgprintf printf
  61 #else
  62 # define dbgprintf if (0) printf
  63 #endif
  64 
  65 #if EXPLICIT_YIELD
  66 # define yield() sched_yield ()
  67 #else
  68 # define yield()
  69 #endif
  70 
  71 /* Returns a reference to the current thread as a pointer, for debugging.  */
  72 #if defined __MVS__
  73   /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field.
  74      The first three bytes of this field appear to uniquely identify a
  75      pthread_t, though not necessarily representing a pointer.  */
  76 # define pthread_self_pointer() (*((void **) pthread_self ().__))
  77 #else
  78 # define pthread_self_pointer() ((void *) (uintptr_t) pthread_self ())
  79 #endif
  80 
  81 #define ACCOUNT_COUNT 4
  82 
  83 static int account[ACCOUNT_COUNT];
  84 
  85 static int
  86 random_account (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88   return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
  89 }
  90 
  91 static void
  92 check_accounts (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94   int i, sum;
  95 
  96   sum = 0;
  97   for (i = 0; i < ACCOUNT_COUNT; i++)
  98     sum += account[i];
  99   if (sum != ACCOUNT_COUNT * 1000)
 100     abort ();
 101 }
 102 
 103 
 104 /* ------------------- Test use like normal locks ------------------- */
 105 
 106 /* Test normal locks by having several bank accounts and several threads
 107    which shuffle around money between the accounts and another thread
 108    checking that all the money is still there.  */
 109 
 110 static pthread_spinlock_t my_lock;
 111 
 112 static void *
 113 lock_mutator_thread (void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 114 {
 115   int repeat;
 116 
 117   for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
 118     {
 119       int i1, i2, value;
 120 
 121       dbgprintf ("Mutator %p before lock\n", pthread_self_pointer ());
 122       ASSERT (pthread_spin_lock (&my_lock) == 0);
 123       dbgprintf ("Mutator %p after  lock\n", pthread_self_pointer ());
 124 
 125       i1 = random_account ();
 126       i2 = random_account ();
 127       value = ((unsigned int) rand () >> 3) % 10;
 128       account[i1] += value;
 129       account[i2] -= value;
 130 
 131       dbgprintf ("Mutator %p before unlock\n", pthread_self_pointer ());
 132       ASSERT (pthread_spin_unlock (&my_lock) == 0);
 133       dbgprintf ("Mutator %p after  unlock\n", pthread_self_pointer ());
 134 
 135       dbgprintf ("Mutator %p before check lock\n", pthread_self_pointer ());
 136       ASSERT (pthread_spin_lock (&my_lock) == 0);
 137       check_accounts ();
 138       ASSERT (pthread_spin_unlock (&my_lock) == 0);
 139       dbgprintf ("Mutator %p after  check unlock\n", pthread_self_pointer ());
 140 
 141       yield ();
 142     }
 143 
 144   dbgprintf ("Mutator %p dying.\n", pthread_self_pointer ());
 145   return NULL;
 146 }
 147 
 148 static struct atomic_int lock_checker_done;
 149 
 150 static void *
 151 lock_checker_thread (void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153   while (get_atomic_int_value (&lock_checker_done) == 0)
 154     {
 155       dbgprintf ("Checker %p before check lock\n", pthread_self_pointer ());
 156       ASSERT (pthread_spin_lock (&my_lock) == 0);
 157       check_accounts ();
 158       ASSERT (pthread_spin_unlock (&my_lock) == 0);
 159       dbgprintf ("Checker %p after  check unlock\n", pthread_self_pointer ());
 160 
 161       yield ();
 162     }
 163 
 164   dbgprintf ("Checker %p dying.\n", pthread_self_pointer ());
 165   return NULL;
 166 }
 167 
 168 static void
 169 test_pthread_spin (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 170 {
 171   int i;
 172   pthread_t checkerthread;
 173   pthread_t threads[THREAD_COUNT];
 174 
 175   /* Initialization.  */
 176   for (i = 0; i < ACCOUNT_COUNT; i++)
 177     account[i] = 1000;
 178   init_atomic_int (&lock_checker_done);
 179   set_atomic_int_value (&lock_checker_done, 0);
 180 
 181   /* Spawn the threads.  */
 182   ASSERT (pthread_create (&checkerthread, NULL, lock_checker_thread, NULL)
 183           == 0);
 184   for (i = 0; i < THREAD_COUNT; i++)
 185     ASSERT (pthread_create (&threads[i], NULL, lock_mutator_thread, NULL) == 0);
 186 
 187   /* Wait for the threads to terminate.  */
 188   for (i = 0; i < THREAD_COUNT; i++)
 189     ASSERT (pthread_join (threads[i], NULL) == 0);
 190   set_atomic_int_value (&lock_checker_done, 1);
 191   ASSERT (pthread_join (checkerthread, 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   ASSERT (pthread_spin_init (&my_lock, 0) == 0);
 210 
 211   printf ("Starting test_pthread_spin ..."); fflush (stdout);
 212   test_pthread_spin ();
 213   printf (" OK\n"); fflush (stdout);
 214 
 215   return 0;
 216 }
 217 
 218 #else
 219 
 220 /* No multithreading available.  */
 221 
 222 #include <stdio.h>
 223 
 224 int
 225 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 226 {
 227   fputs ("Skipping test: multithreading not enabled\n", stderr);
 228   return 77;
 229 }
 230 
 231 #endif

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