membarrier(2) System Calls Manual membarrier(2) membarrier - LIBRARY Standard C library (libc, -lc) #include /* MEMBARRIER_* */ #include /* SYS_* */ #include int syscall(SYS_membarrier, int cmd, unsigned int flags, int cpu_id); Note: glibc provides no wrapper for membarrier(), necessitating the use of syscall(2). membarrier() , . , , . , , . , ( << >>) ( << >>). membarrier(). : -- : asm volatile ("" : : : "memory") -- membarrier(). , , membarrier() , - , . cmd : MEMBARRIER_CMD_QUERY ( Linux 4.3) . . MEMBARRIER_CMD_QUERY 0 . ( membarrier()). MEMBARRIER_CMD_GLOBAL ( Linux 4.16) , , membarrier(). . MEMBARRIER_CMD_GLOBAL_EXPEDITED ( Linux 4.16) , MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED. , , ( ). , MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED. , MEMBARRIER_CMD_GLOBAL_EXPEDITED , MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED. <<>> (expedited) ; , . MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED ( Linux 4.16) MEMBARRIER_CMD_GLOBAL_EXPEDITED. MEMBARRIER_CMD_PRIVATE_EXPEDITED ( Linux 4.14) , , . , , , ( ). , . <<>> (expedited) ; , . . MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED ( Linux 4.14) MEMBARRIER_CMD_PRIVATE_EXPEDITED. MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE ( Linux 4.16) , MEMBARRIER_CMD_PRIVATE_EXPEDITED, , , (core serializing instruction). , . <<>> (expedited) ; , . . MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE ( Linux 4.16) MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE. MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ ( Linux 5.10) Ensure the caller thread, upon return from system call, that all its running thread siblings have any currently running rseq critical sections restarted if flags parameter is 0; if flags parameter is MEMBARRIER_CMD_FLAG_CPU, then this operation is performed only on CPU indicated by cpu_id. This guarantee is provided only for threads in the same process as the calling thread. RSEQ membarrier is only available in the "private expedited" form. A process must register its intent to use the private expedited rseq command prior to using it. MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ ( Linux 5.10) MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ. MEMBARRIER_CMD_SHARED ( Linux 4.3) MEMBARRIER_CMD_GLOBAL, . The flags argument must be specified as 0 unless the command is MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ, in which case flags can be either 0 or MEMBARRIER_CMD_FLAG_CPU. The cpu_id argument is ignored unless flags is MEMBARRIER_CMD_FLAG_CPU, in which case it must specify the CPU targeted by this membarrier command. , , membarrier(). barrier() , , , smp_mb() -- , , barrier(), membarrier() smp_mb(). (O: , X: ): barrier() smp_mb() membarrier() barrier() X X O smp_mb() X O O membarrier() O O O On success, the MEMBARRIER_CMD_QUERY operation returns a bit mask of supported commands, and the MEMBARRIER_CMD_GLOBAL, MEMBARRIER_CMD_GLOBAL_EXPEDITED, MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, MEMBARRIER_CMD_PRIVATE_EXPEDITED, MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, and MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE operations return zero. On error, -1 is returned, and errno is set to indicate the error. , flags 0, . . , flags 0, membarrier(). EINVAL cmd, flags , MEMBARRIER_CMD_GLOBAL, nohz_full MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE . ENOSYS membarrier() . EPERM . Linux. Linux 4.3. Before Linux 5.10, the prototype was: int membarrier(int cmd, int flags); . . , (fence) , . -- , . membarrier() -- . , <> , <> -- , (x86) membarrier(): #include static volatile int a, b; static void fast_path(int *read_b) { a = 1; asm volatile ("mfence" : : : "memory"); *read_b = b; } static void slow_path(int *read_a) { b = 1; asm volatile ("mfence" : : : "memory"); *read_a = a; } int main(void) { int read_a, read_b; /* * Real applications would call fast_path() and slow_path() * from different threads. Call those from main() to keep * this example short. */ slow_path(&read_a); fast_path(&read_b); /* * read_b == 0 implies read_a == 1 and * read_a == 0 implies read_b == 1. */ if (read_b == 0 && read_a == 0) abort(); exit(EXIT_SUCCESS); } , membarrier(): #define _GNU_SOURCE #include #include #include #include #include static volatile int a, b; static int membarrier(int cmd, unsigned int flags, int cpu_id) { return syscall(__NR_membarrier, cmd, flags, cpu_id); } static int init_membarrier(void) { int ret; /* Check that membarrier() is supported. */ ret = membarrier(MEMBARRIER_CMD_QUERY, 0, 0); if (ret < 0) { perror("membarrier"); return -1; } if (!(ret & MEMBARRIER_CMD_GLOBAL)) { fprintf(stderr, "membarrier does not support MEMBARRIER_CMD_GLOBAL\n"); return -1; } return 0; } static void fast_path(int *read_b) { a = 1; asm volatile ("" : : : "memory"); *read_b = b; } static void slow_path(int *read_a) { b = 1; membarrier(MEMBARRIER_CMD_GLOBAL, 0, 0); *read_a = a; } int main(int argc, char *argv[]) { int read_a, read_b; if (init_membarrier()) exit(EXIT_FAILURE); /* * Real applications would call fast_path() and slow_path() * from different threads. Call those from main() to keep * this example short. */ slow_path(&read_a); fast_path(&read_b); /* * read_b == 0 implies read_a == 1 and * read_a == 0 implies read_b == 1. */ if (read_b == 0 && read_a == 0) abort(); exit(EXIT_SUCCESS); } aereiae , Alexey , Azamat Hackimov , Dmitriy S. Seregin , Dmitry Bolkhovskikh , ITriskTI , Max Is , Yuri Kozlov , ; GNU 3 , . . , , . Linux man-pages 6.06 31 2023 . membarrier(2)