(root)/
m4-1.4.19/
tests/
atomic-int-gnulib.h
       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)
      55  {
      56  }
      57  static int
      58  get_atomic_int_value (struct atomic_int *ai)
      59  {
      60    return ai->value;
      61  }
      62  static void
      63  set_atomic_int_value (struct atomic_int *ai, int new_value)
      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)
      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)
      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)
     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)
     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    gl_lock_define (, lock)
     151    int value;
     152  };
     153  static void
     154  init_atomic_int (struct atomic_int *ai)
     155  {
     156    gl_lock_init (ai->lock);
     157  }
     158  static int
     159  get_atomic_int_value (struct atomic_int *ai)
     160  {
     161    gl_lock_lock (ai->lock);
     162    int ret = ai->value;
     163    gl_lock_unlock (ai->lock);
     164    return ret;
     165  }
     166  static void
     167  set_atomic_int_value (struct atomic_int *ai, int new_value)
     168  {
     169    gl_lock_lock (ai->lock);
     170    ai->value = new_value;
     171    gl_lock_unlock (ai->lock);
     172  }
     173  #endif