1membarrier(2) System Calls Manual membarrier(2)
2
3
4
6 membarrier - issue memory barriers on a set of threads
7
9 Standard C library (libc, -lc)
10
12 #include <linux/membarrier.h> /* Definition of MEMBARRIER_* constants */
13 #include <sys/syscall.h> /* Definition of SYS_* constants */
14 #include <unistd.h>
15
16 int syscall(SYS_membarrier, int cmd, unsigned int flags, int cpu_id);
17
18 Note: glibc provides no wrapper for membarrier(), necessitating the use
19 of syscall(2).
20
22 The membarrier() system call helps reducing the overhead of the memory
23 barrier instructions required to order memory accesses on multi-core
24 systems. However, this system call is heavier than a memory barrier,
25 so using it effectively is not as simple as replacing memory barriers
26 with this system call, but requires understanding of the details below.
27
28 Use of memory barriers needs to be done taking into account that a mem‐
29 ory barrier always needs to be either matched with its memory barrier
30 counterparts, or that the architecture's memory model doesn't require
31 the matching barriers.
32
33 There are cases where one side of the matching barriers (which we will
34 refer to as "fast side") is executed much more often than the other
35 (which we will refer to as "slow side"). This is a prime target for
36 the use of membarrier(). The key idea is to replace, for these match‐
37 ing barriers, the fast-side memory barriers by simple compiler barri‐
38 ers, for example:
39
40 asm volatile ("" : : : "memory")
41
42 and replace the slow-side memory barriers by calls to membarrier().
43
44 This will add overhead to the slow side, and remove overhead from the
45 fast side, thus resulting in an overall performance increase as long as
46 the slow side is infrequent enough that the overhead of the membar‐
47 rier() calls does not outweigh the performance gain on the fast side.
48
49 The cmd argument is one of the following:
50
51 MEMBARRIER_CMD_QUERY (since Linux 4.3)
52 Query the set of supported commands. The return value of the
53 call is a bit mask of supported commands. MEMBARRIER_CMD_QUERY,
54 which has the value 0, is not itself included in this bit mask.
55 This command is always supported (on kernels where membarrier()
56 is provided).
57
58 MEMBARRIER_CMD_GLOBAL (since Linux 4.16)
59 Ensure that all threads from all processes on the system pass
60 through a state where all memory accesses to user-space ad‐
61 dresses match program order between entry to and return from the
62 membarrier() system call. All threads on the system are tar‐
63 geted by this command.
64
65 MEMBARRIER_CMD_GLOBAL_EXPEDITED (since Linux 4.16)
66 Execute a memory barrier on all running threads of all processes
67 that previously registered with MEMBARRIER_CMD_REGIS‐
68 TER_GLOBAL_EXPEDITED.
69
70 Upon return from the system call, the calling thread has a guar‐
71 antee that all running threads have passed through a state where
72 all memory accesses to user-space addresses match program order
73 between entry to and return from the system call (non-running
74 threads are de facto in such a state). This guarantee is pro‐
75 vided only for the threads of processes that previously regis‐
76 tered with MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED.
77
78 Given that registration is about the intent to receive the bar‐
79 riers, it is valid to invoke MEMBARRIER_CMD_GLOBAL_EXPEDITED
80 from a process that has not employed MEMBARRIER_CMD_REGIS‐
81 TER_GLOBAL_EXPEDITED.
82
83 The "expedited" commands complete faster than the non-expedited
84 ones; they never block, but have the downside of causing extra
85 overhead.
86
87 MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED (since Linux 4.16)
88 Register the process's intent to receive MEMBAR‐
89 RIER_CMD_GLOBAL_EXPEDITED memory barriers.
90
91 MEMBARRIER_CMD_PRIVATE_EXPEDITED (since Linux 4.14)
92 Execute a memory barrier on each running thread belonging to the
93 same process as the calling thread.
94
95 Upon return from the system call, the calling thread has a guar‐
96 antee that all its running thread siblings have passed through a
97 state where all memory accesses to user-space addresses match
98 program order between entry to and return from the system call
99 (non-running threads are de facto in such a state). This guar‐
100 antee is provided only for threads in the same process as the
101 calling thread.
102
103 The "expedited" commands complete faster than the non-expedited
104 ones; they never block, but have the downside of causing extra
105 overhead.
106
107 A process must register its intent to use the private expedited
108 command prior to using it.
109
110 MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED (since Linux 4.14)
111 Register the process's intent to use MEMBARRIER_CMD_PRIVATE_EX‐
112 PEDITED.
113
114 MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE (since Linux 4.16)
115 In addition to providing the memory ordering guarantees de‐
116 scribed in MEMBARRIER_CMD_PRIVATE_EXPEDITED, upon return from
117 system call the calling thread has a guarantee that all its run‐
118 ning thread siblings have executed a core serializing instruc‐
119 tion. This guarantee is provided only for threads in the same
120 process as the calling thread.
121
122 The "expedited" commands complete faster than the non-expedited
123 ones, they never block, but have the downside of causing extra
124 overhead.
125
126 A process must register its intent to use the private expedited
127 sync core command prior to using it.
128
129 MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE (since Linux 4.16)
130 Register the process's intent to use MEMBARRIER_CMD_PRIVATE_EX‐
131 PEDITED_SYNC_CORE.
132
133 MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ (since Linux 5.10)
134 Ensure the caller thread, upon return from system call, that all
135 its running thread siblings have any currently running rseq
136 critical sections restarted if flags parameter is 0; if flags
137 parameter is MEMBARRIER_CMD_FLAG_CPU, then this operation is
138 performed only on CPU indicated by cpu_id. This guarantee is
139 provided only for threads in the same process as the calling
140 thread.
141
142 RSEQ membarrier is only available in the "private expedited"
143 form.
144
145 A process must register its intent to use the private expedited
146 rseq command prior to using it.
147
148 MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ (since Linux 5.10)
149 Register the process's intent to use MEMBARRIER_CMD_PRIVATE_EX‐
150 PEDITED_RSEQ.
151
152 MEMBARRIER_CMD_SHARED (since Linux 4.3)
153 This is an alias for MEMBARRIER_CMD_GLOBAL that exists for
154 header backward compatibility.
155
156 The flags argument must be specified as 0 unless the command is MEMBAR‐
157 RIER_CMD_PRIVATE_EXPEDITED_RSEQ, in which case flags can be either 0 or
158 MEMBARRIER_CMD_FLAG_CPU.
159
160 The cpu_id argument is ignored unless flags is MEMBARRIER_CMD_FLAG_CPU,
161 in which case it must specify the CPU targeted by this membarrier com‐
162 mand.
163
164 All memory accesses performed in program order from each targeted
165 thread are guaranteed to be ordered with respect to membarrier().
166
167 If we use the semantic barrier() to represent a compiler barrier forc‐
168 ing memory accesses to be performed in program order across the bar‐
169 rier, and smp_mb() to represent explicit memory barriers forcing full
170 memory ordering across the barrier, we have the following ordering ta‐
171 ble for each pairing of barrier(), membarrier(), and smp_mb(). The
172 pair ordering is detailed as (O: ordered, X: not ordered):
173
174 barrier() smp_mb() membarrier()
175 barrier() X X O
176 smp_mb() X O O
177 membarrier() O O O
178
180 On success, the MEMBARRIER_CMD_QUERY operation returns a bit mask of
181 supported commands, and the MEMBARRIER_CMD_GLOBAL, MEMBAR‐
182 RIER_CMD_GLOBAL_EXPEDITED, MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED,
183 MEMBARRIER_CMD_PRIVATE_EXPEDITED, MEMBARRIER_CMD_REGISTER_PRIVATE_EXPE‐
184 DITED, MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, and MEMBAR‐
185 RIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE operations return zero.
186 On error, -1 is returned, and errno is set to indicate the error.
187
188 For a given command, with flags set to 0, this system call is guaran‐
189 teed to always return the same value until reboot. Further calls with
190 the same arguments will lead to the same result. Therefore, with flags
191 set to 0, error handling is required only for the first call to membar‐
192 rier().
193
195 EINVAL cmd is invalid, or flags is nonzero, or the MEMBAR‐
196 RIER_CMD_GLOBAL command is disabled because the nohz_full CPU
197 parameter has been set, or the MEMBARRIER_CMD_PRIVATE_EXPE‐
198 DITED_SYNC_CORE and MEMBARRIER_CMD_REGISTER_PRIVATE_EXPE‐
199 DITED_SYNC_CORE commands are not implemented by the architec‐
200 ture.
201
202 ENOSYS The membarrier() system call is not implemented by this kernel.
203
204 EPERM The current process was not registered prior to using private
205 expedited commands.
206
208 Linux.
209
211 Linux 4.3.
212
213 Before Linux 5.10, the prototype was:
214
215 int membarrier(int cmd, int flags);
216
218 A memory barrier instruction is part of the instruction set of archi‐
219 tectures with weakly ordered memory models. It orders memory accesses
220 prior to the barrier and after the barrier with respect to matching
221 barriers on other cores. For instance, a load fence can order loads
222 prior to and following that fence with respect to stores ordered by
223 store fences.
224
225 Program order is the order in which instructions are ordered in the
226 program assembly code.
227
228 Examples where membarrier() can be useful include implementations of
229 Read-Copy-Update libraries and garbage collectors.
230
232 Assuming a multithreaded application where "fast_path()" is executed
233 very frequently, and where "slow_path()" is executed infrequently, the
234 following code (x86) can be transformed using membarrier():
235
236 #include <stdlib.h>
237
238 static volatile int a, b;
239
240 static void
241 fast_path(int *read_b)
242 {
243 a = 1;
244 asm volatile ("mfence" : : : "memory");
245 *read_b = b;
246 }
247
248 static void
249 slow_path(int *read_a)
250 {
251 b = 1;
252 asm volatile ("mfence" : : : "memory");
253 *read_a = a;
254 }
255
256 int
257 main(void)
258 {
259 int read_a, read_b;
260
261 /*
262 * Real applications would call fast_path() and slow_path()
263 * from different threads. Call those from main() to keep
264 * this example short.
265 */
266
267 slow_path(&read_a);
268 fast_path(&read_b);
269
270 /*
271 * read_b == 0 implies read_a == 1 and
272 * read_a == 0 implies read_b == 1.
273 */
274
275 if (read_b == 0 && read_a == 0)
276 abort();
277
278 exit(EXIT_SUCCESS);
279 }
280
281 The code above transformed to use membarrier() becomes:
282
283 #define _GNU_SOURCE
284 #include <stdlib.h>
285 #include <stdio.h>
286 #include <unistd.h>
287 #include <sys/syscall.h>
288 #include <linux/membarrier.h>
289
290 static volatile int a, b;
291
292 static int
293 membarrier(int cmd, unsigned int flags, int cpu_id)
294 {
295 return syscall(__NR_membarrier, cmd, flags, cpu_id);
296 }
297
298 static int
299 init_membarrier(void)
300 {
301 int ret;
302
303 /* Check that membarrier() is supported. */
304
305 ret = membarrier(MEMBARRIER_CMD_QUERY, 0, 0);
306 if (ret < 0) {
307 perror("membarrier");
308 return -1;
309 }
310
311 if (!(ret & MEMBARRIER_CMD_GLOBAL)) {
312 fprintf(stderr,
313 "membarrier does not support MEMBARRIER_CMD_GLOBAL\n");
314 return -1;
315 }
316
317 return 0;
318 }
319
320 static void
321 fast_path(int *read_b)
322 {
323 a = 1;
324 asm volatile ("" : : : "memory");
325 *read_b = b;
326 }
327
328 static void
329 slow_path(int *read_a)
330 {
331 b = 1;
332 membarrier(MEMBARRIER_CMD_GLOBAL, 0, 0);
333 *read_a = a;
334 }
335
336 int
337 main(int argc, char *argv[])
338 {
339 int read_a, read_b;
340
341 if (init_membarrier())
342 exit(EXIT_FAILURE);
343
344 /*
345 * Real applications would call fast_path() and slow_path()
346 * from different threads. Call those from main() to keep
347 * this example short.
348 */
349
350 slow_path(&read_a);
351 fast_path(&read_b);
352
353 /*
354 * read_b == 0 implies read_a == 1 and
355 * read_a == 0 implies read_b == 1.
356 */
357
358 if (read_b == 0 && read_a == 0)
359 abort();
360
361 exit(EXIT_SUCCESS);
362 }
363
364
365
366Linux man-pages 6.04 2023-03-30 membarrier(2)