1 /* Atomic integers.  Useful for testing multithreaded locking primitives.
2    Copyright (C) 2005, 2008-2020 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
init_atomic_int(struct atomic_int * ai)54 init_atomic_int (struct atomic_int *ai)
55 {
56 }
57 static int
get_atomic_int_value(struct atomic_int * ai)58 get_atomic_int_value (struct atomic_int *ai)
59 {
60   return ai->value;
61 }
62 static void
set_atomic_int_value(struct atomic_int * ai,int new_value)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
init_atomic_int(struct atomic_int * ai)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
init_atomic_int(struct atomic_int * ai)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
get_atomic_int_value(struct atomic_int * ai)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
set_atomic_int_value(struct atomic_int * ai,int new_value)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
init_atomic_int(struct atomic_int * ai)154 init_atomic_int (struct atomic_int *ai)
155 {
156   gl_lock_init (ai->lock);
157 }
158 static int
get_atomic_int_value(struct atomic_int * ai)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
set_atomic_int_value(struct atomic_int * ai,int new_value)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
174