1 /*
 2  * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
 3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 4  *
 5  * This code is free software; you can redistribute it and/or modify it
 6  * under the terms of the GNU General Public License version 2 only, as
 7  * published by the Free Software Foundation.
 8  *
 9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 #include "precompiled.hpp"
26 #include "logging/log.hpp"
27 #include "runtime/os.hpp"
28 #include "utilities/debug.hpp"
29 #include "utilities/systemMemoryBarrier.hpp"
30 
31 #include <sys/syscall.h>
32 
33 // Syscall defined in kernel 4.3
34 // Oracle x64 builds may use old sysroot (pre 4.3)
35 #ifndef SYS_membarrier
36   #if defined(AMD64)
37   #define SYS_membarrier 324
38   #elif defined(X86)
39   #define SYS_membarrier 375
40   #elif defined(PPC64)
41   #define SYS_membarrier 365
42   #elif defined(AARCH64)
43   #define SYS_membarrier 283
44   #elif defined(ALPHA)
45   #define SYS_membarrier 517
46   #else
47   #error define SYS_membarrier for the arch
48   #endif
49 #endif // SYS_membarrier
50 
51 // Expedited defined in kernel 4.14
52 // Therefore we define it here instead of including linux/membarrier.h
53 enum membarrier_cmd {
54   MEMBARRIER_CMD_QUERY                      = 0,
55   MEMBARRIER_CMD_PRIVATE_EXPEDITED          = (1 << 3),
56   MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = (1 << 4),
57 };
58 
59 #define check_with_errno(check_type, cond, msg)                             \
60   do {                                                                      \
61     int err = errno;                                                        \
62     check_type(cond, "%s: error='%s' (errno=%s)", msg, os::strerror(err),   \
63                os::errno_name(err));                                        \
64 } while (false)
65 
66 #define guarantee_with_errno(cond, msg) check_with_errno(guarantee, cond, msg)
67 
68 static int membarrier(int cmd, unsigned int flags, int cpu_id) {
69   return syscall(SYS_membarrier, cmd, flags, cpu_id); // cpu_id only on >= 5.10
70 }
71 
72 bool LinuxSystemMemoryBarrier::initialize() {
73   int ret = membarrier(MEMBARRIER_CMD_QUERY, 0, 0);
74   if (ret < 0) {
75     log_info(os)("MEMBARRIER_CMD_QUERY unsupported");
76     return false;
77   }
78   if (!(ret & MEMBARRIER_CMD_PRIVATE_EXPEDITED) ||
79       !(ret & MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED)) {
80     log_info(os)("MEMBARRIER PRIVATE_EXPEDITED unsupported");
81     return false;
82   }
83   ret = membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0, 0);
84   guarantee_with_errno(ret == 0, "MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED failed");
85   log_info(os)("Using MEMBARRIER PRIVATE_EXPEDITED");
86   return true;
87 }
88 
89 void LinuxSystemMemoryBarrier::emit() {
90   int s = membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED, 0, 0);
91   guarantee_with_errno(s >= 0, "MEMBARRIER_CMD_PRIVATE_EXPEDITED failed");
92 }