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