root/maint/gnulib/tests/test-asyncsafe-spin2.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_asyncsafe_spin
  6. main
  7. main

   1 /* Test of spin locks for communication between threads and signal handlers.
   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 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 #if !(defined _WIN32 && ! defined __CYGWIN__) && HAVE_PTHREAD_H && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __clang_major__ >= 3) && !defined __ibmxl__
  40 
  41 /* The GCC built-ins are known to work fine.  */
  42 # define REPEAT_COUNT 5000
  43 #else
  44 /* This is quite high, because with a smaller count, say 50000, we often get
  45    an "OK" result even with the racy implementation that we pick on Fedora 13
  46    Linux/x86_64 (gcc 4.4).  */
  47 # define REPEAT_COUNT 100000
  48 #endif
  49 
  50 #include <signal.h>
  51 #include <stdint.h>
  52 #include <stdio.h>
  53 #include <stdlib.h>
  54 #include <string.h>
  55 
  56 #include "asyncsafe-spin.h"
  57 #if !ENABLE_LOCKING
  58 # define asyncsafe_spin_init(lock) (void)(lock)
  59 # define asyncsafe_spin_lock(lock, mask, saved_mask) \
  60     ((void)(lock), (void)(mask), (void)(saved_mask))
  61 # define asyncsafe_spin_unlock(lock, saved_mask) \
  62     ((void)(lock), (void)(saved_mask))
  63 # define asyncsafe_spin_destroy(lock) (void)(lock)
  64 #endif
  65 
  66 #include "glthread/lock.h"
  67 #include "glthread/thread.h"
  68 #include "glthread/yield.h"
  69 
  70 #if HAVE_DECL_ALARM
  71 # include <signal.h>
  72 # include <unistd.h>
  73 #endif
  74 
  75 #include "atomic-int-gnulib.h"
  76 
  77 #if ENABLE_DEBUGGING
  78 # define dbgprintf printf
  79 #else
  80 # define dbgprintf if (0) printf
  81 #endif
  82 
  83 #if EXPLICIT_YIELD
  84 # define yield() gl_thread_yield ()
  85 #else
  86 # define yield()
  87 #endif
  88 
  89 static sigset_t signals_to_block;
  90 
  91 #define ACCOUNT_COUNT 4
  92 
  93 static int account[ACCOUNT_COUNT];
  94 
  95 static int
  96 random_account (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98   return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
  99 }
 100 
 101 static void
 102 check_accounts (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104   int i, sum;
 105 
 106   sum = 0;
 107   for (i = 0; i < ACCOUNT_COUNT; i++)
 108     sum += account[i];
 109   if (sum != ACCOUNT_COUNT * 1000)
 110     abort ();
 111 }
 112 
 113 
 114 /* ------------------- Test use like normal locks ------------------- */
 115 
 116 /* Test normal locks by having several bank accounts and several threads
 117    which shuffle around money between the accounts and another thread
 118    checking that all the money is still there.  */
 119 
 120 static asyncsafe_spinlock_t my_lock;
 121 
 122 static void *
 123 lock_mutator_thread (void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125   int repeat;
 126 
 127   for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
 128     {
 129       sigset_t saved_signals;
 130       int i1, i2, value;
 131 
 132       dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
 133       asyncsafe_spin_lock (&my_lock, &signals_to_block, &saved_signals);
 134       dbgprintf ("Mutator %p after  lock\n", gl_thread_self_pointer ());
 135 
 136       i1 = random_account ();
 137       i2 = random_account ();
 138       value = ((unsigned int) rand () >> 3) % 10;
 139       account[i1] += value;
 140       account[i2] -= value;
 141 
 142       dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
 143       asyncsafe_spin_unlock (&my_lock, &saved_signals);
 144       dbgprintf ("Mutator %p after  unlock\n", gl_thread_self_pointer ());
 145 
 146       dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
 147       asyncsafe_spin_lock (&my_lock, &signals_to_block, &saved_signals);
 148       check_accounts ();
 149       asyncsafe_spin_unlock (&my_lock, &saved_signals);
 150       dbgprintf ("Mutator %p after  check unlock\n", gl_thread_self_pointer ());
 151 
 152       yield ();
 153     }
 154 
 155   dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
 156   return NULL;
 157 }
 158 
 159 static struct atomic_int lock_checker_done;
 160 
 161 static void *
 162 lock_checker_thread (void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164   while (get_atomic_int_value (&lock_checker_done) == 0)
 165     {
 166       sigset_t saved_signals;
 167 
 168       dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
 169       asyncsafe_spin_lock (&my_lock, &signals_to_block, &saved_signals);
 170       check_accounts ();
 171       asyncsafe_spin_unlock (&my_lock, &saved_signals);
 172       dbgprintf ("Checker %p after  check unlock\n", gl_thread_self_pointer ());
 173 
 174       yield ();
 175     }
 176 
 177   dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
 178   return NULL;
 179 }
 180 
 181 static void
 182 test_asyncsafe_spin (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184   int i;
 185   gl_thread_t checkerthread;
 186   gl_thread_t threads[THREAD_COUNT];
 187 
 188   /* Initialization.  */
 189   for (i = 0; i < ACCOUNT_COUNT; i++)
 190     account[i] = 1000;
 191   init_atomic_int (&lock_checker_done);
 192   set_atomic_int_value (&lock_checker_done, 0);
 193 
 194   /* Spawn the threads.  */
 195   checkerthread = gl_thread_create (lock_checker_thread, NULL);
 196   for (i = 0; i < THREAD_COUNT; i++)
 197     threads[i] = gl_thread_create (lock_mutator_thread, NULL);
 198 
 199   /* Wait for the threads to terminate.  */
 200   for (i = 0; i < THREAD_COUNT; i++)
 201     gl_thread_join (threads[i], NULL);
 202   set_atomic_int_value (&lock_checker_done, 1);
 203   gl_thread_join (checkerthread, NULL);
 204   check_accounts ();
 205 }
 206 
 207 
 208 /* -------------------------------------------------------------------------- */
 209 
 210 int
 211 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 212 {
 213 #if HAVE_DECL_ALARM
 214   /* Declare failure if test takes too long, by using default abort
 215      caused by SIGALRM.  */
 216   int alarm_value = 600;
 217   signal (SIGALRM, SIG_DFL);
 218   alarm (alarm_value);
 219 #endif
 220 
 221   sigemptyset (&signals_to_block);
 222   sigaddset (&signals_to_block, SIGINT);
 223 
 224   asyncsafe_spin_init (&my_lock);
 225 
 226   printf ("Starting test_asyncsafe_spin ..."); fflush (stdout);
 227   test_asyncsafe_spin ();
 228   printf (" OK\n"); fflush (stdout);
 229 
 230   return 0;
 231 }
 232 
 233 #else
 234 
 235 /* No multithreading available.  */
 236 
 237 #include <stdio.h>
 238 
 239 int
 240 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 241 {
 242   fputs ("Skipping test: multithreading not enabled\n", stderr);
 243   return 77;
 244 }
 245 
 246 #endif

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