root/maint/gnulib/tests/atomic-int-posix.h

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

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. init_atomic_int
  2. get_atomic_int_value
  3. set_atomic_int_value
  4. init_atomic_int
  5. init_atomic_int
  6. get_atomic_int_value
  7. set_atomic_int_value
  8. init_atomic_int
  9. get_atomic_int_value
  10. set_atomic_int_value

   1 /* Atomic integers.  Useful for testing multithreaded locking primitives.
   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 
  18 /* Whether to use 'volatile' on some variables that communicate information
  19    between threads.  If set to 0, a semaphore or a lock is used to protect
  20    these variables.  If set to 1, 'volatile' is used; this is theoretically
  21    equivalent but can lead to much slower execution (e.g. 30x slower total
  22    run time on a 40-core machine), because 'volatile' does not imply any
  23    synchronization/communication between different CPUs.  */
  24 #define USE_VOLATILE 0
  25 
  26 #if USE_POSIX_THREADS && HAVE_SEMAPHORE_H
  27 /* Whether to use a semaphore to communicate information between threads.
  28    If set to 0, a lock is used. If set to 1, a semaphore is used.
  29    Uncomment this to reduce the dependencies of this test.  */
  30 # define USE_SEMAPHORE 1
  31 /* Mac OS X provides only named semaphores (sem_open); its facility for
  32    unnamed semaphores (sem_init) does not work.  */
  33 # if defined __APPLE__ && defined __MACH__
  34 #  define USE_NAMED_SEMAPHORE 1
  35 # else
  36 #  define USE_UNNAMED_SEMAPHORE 1
  37 # endif
  38 #endif
  39 
  40 
  41 #if USE_SEMAPHORE
  42 # include <errno.h>
  43 # include <fcntl.h>
  44 # include <semaphore.h>
  45 # include <unistd.h>
  46 #endif
  47 
  48 
  49 #if USE_VOLATILE
  50 struct atomic_int {
  51   volatile int value;
  52 };
  53 static void
  54 init_atomic_int (struct atomic_int *ai)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56 }
  57 static int
  58 get_atomic_int_value (struct atomic_int *ai)
     /* [previous][next][first][last][top][bottom][index][help] */
  59 {
  60   return ai->value;
  61 }
  62 static void
  63 set_atomic_int_value (struct atomic_int *ai, int new_value)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65   ai->value = new_value;
  66 }
  67 #elif USE_SEMAPHORE
  68 /* This atomic_int implementation can only support the values 0 and 1.
  69    It is initially 0 and can be set to 1 only once.  */
  70 # if USE_UNNAMED_SEMAPHORE
  71 struct atomic_int {
  72   sem_t semaphore;
  73 };
  74 #define atomic_int_semaphore(ai) (&(ai)->semaphore)
  75 static void
  76 init_atomic_int (struct atomic_int *ai)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78   sem_init (&ai->semaphore, 0, 0);
  79 }
  80 # endif
  81 # if USE_NAMED_SEMAPHORE
  82 struct atomic_int {
  83   sem_t *semaphore;
  84 };
  85 #define atomic_int_semaphore(ai) ((ai)->semaphore)
  86 static void
  87 init_atomic_int (struct atomic_int *ai)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89   sem_t *s;
  90   unsigned int count;
  91   for (count = 0; ; count++)
  92     {
  93       char name[80];
  94       /* Use getpid() in the name, so that different processes running at the
  95          same time will not interfere.  Use ai in the name, so that different
  96          atomic_int in the same process will not interfere.  Use a count in
  97          the name, so that even in the (unlikely) case that a semaphore with
  98          the specified name already exists, we can try a different name.  */
  99       sprintf (name, "test-lock-%lu-%p-%u",
 100                (unsigned long) getpid (), ai, count);
 101       s = sem_open (name, O_CREAT | O_EXCL, 0600, 0);
 102       if (s == SEM_FAILED)
 103         {
 104           if (errno == EEXIST)
 105             /* Retry with a different name.  */
 106             continue;
 107           else
 108             {
 109               perror ("sem_open failed");
 110               abort ();
 111             }
 112         }
 113       else
 114         {
 115           /* Try not to leave a semaphore hanging around on the file system
 116              eternally, if we can avoid it.  */
 117           sem_unlink (name);
 118           break;
 119         }
 120     }
 121   ai->semaphore = s;
 122 }
 123 # endif
 124 static int
 125 get_atomic_int_value (struct atomic_int *ai)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127   if (sem_trywait (atomic_int_semaphore (ai)) == 0)
 128     {
 129       if (sem_post (atomic_int_semaphore (ai)))
 130         abort ();
 131       return 1;
 132     }
 133   else if (errno == EAGAIN)
 134     return 0;
 135   else
 136     abort ();
 137 }
 138 static void
 139 set_atomic_int_value (struct atomic_int *ai, int new_value)
     /* [previous][next][first][last][top][bottom][index][help] */
 140 {
 141   if (new_value == 0)
 142     /* It's already initialized with 0.  */
 143     return;
 144   /* To set the value 1: */
 145   if (sem_post (atomic_int_semaphore (ai)))
 146     abort ();
 147 }
 148 #else
 149 struct atomic_int {
 150   pthread_mutex_t lock;
 151   int value;
 152 };
 153 static void
 154 init_atomic_int (struct atomic_int *ai)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156   pthread_mutexattr_t attr;
 157 
 158   ASSERT (pthread_mutexattr_init (&attr) == 0);
 159   ASSERT (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL) == 0);
 160   ASSERT (pthread_mutex_init (&ai->lock, &attr) == 0);
 161   ASSERT (pthread_mutexattr_destroy (&attr) == 0);
 162 }
 163 static int
 164 get_atomic_int_value (struct atomic_int *ai)
     /* [previous][next][first][last][top][bottom][index][help] */
 165 {
 166   ASSERT (pthread_mutex_lock (&ai->lock) == 0);
 167   int ret = ai->value;
 168   ASSERT (pthread_mutex_unlock (&ai->lock) == 0);
 169   return ret;
 170 }
 171 static void
 172 set_atomic_int_value (struct atomic_int *ai, int new_value)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174   ASSERT (pthread_mutex_lock (&ai->lock) == 0);
 175   ai->value = new_value;
 176   ASSERT (pthread_mutex_unlock (&ai->lock) == 0);
 177 }
 178 #endif

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