summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Orion Hodson <oth@google.com> 2018-09-20 05:58:08 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2018-09-20 05:58:08 +0000
commitb32535defe6fcec752f4e78f8cfa2746037a1f70 (patch)
tree1bf8605b2a00731c3e20d4b0ca2ee3834bcdfb52
parent144f0826919bf7af915bd165fc67eb12aead843c (diff)
parent563ada2e5570d947ee2b96e3651ded3692be33be (diff)
Merge "ART: Add wrappers for membarrier and memfd_create()"
-rw-r--r--libartbase/Android.bp4
-rw-r--r--libartbase/base/membarrier.cc72
-rw-r--r--libartbase/base/membarrier.h51
-rw-r--r--libartbase/base/membarrier_test.cc111
-rw-r--r--libartbase/base/memfd.cc52
-rw-r--r--libartbase/base/memfd.h27
-rw-r--r--libartbase/base/memfd_test.cc30
-rw-r--r--libartbase/base/utils.cc38
-rw-r--r--libartbase/base/utils.h3
-rw-r--r--runtime/jit/jit_code_cache.cc11
10 files changed, 355 insertions, 44 deletions
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 1b603b51e1..19f15322ef 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -29,6 +29,8 @@ cc_defaults {
"base/hex_dump.cc",
"base/logging.cc",
"base/malloc_arena_pool.cc",
+ "base/membarrier.cc",
+ "base/memfd.cc",
"base/memory_region.cc",
"base/mem_map.cc",
// "base/mem_map_fuchsia.cc", put in target when fuchsia supported by soong
@@ -186,6 +188,8 @@ art_cc_test {
"base/indenter_test.cc",
"base/leb128_test.cc",
"base/logging_test.cc",
+ "base/memfd_test.cc",
+ "base/membarrier_test.cc",
"base/memory_region_test.cc",
"base/mem_map_test.cc",
"base/safe_copy_test.cc",
diff --git a/libartbase/base/membarrier.cc b/libartbase/base/membarrier.cc
new file mode 100644
index 0000000000..490dbf3fa0
--- /dev/null
+++ b/libartbase/base/membarrier.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "membarrier.h"
+
+#include <errno.h>
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include "macros.h"
+
+#if defined(__BIONIC__)
+
+#include <atomic>
+#include <android/get_device_api_level.h>
+#include <linux/membarrier.h>
+
+#define CHECK_MEMBARRIER_CMD(art_value, membarrier_value) \
+ static_assert(static_cast<int>(art_value) == membarrier_value, "Bad value for " # art_value)
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kQuery, MEMBARRIER_CMD_QUERY);
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kGlobal, MEMBARRIER_CMD_SHARED);
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kPrivateExpedited, MEMBARRIER_CMD_PRIVATE_EXPEDITED);
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kRegisterPrivateExpedited,
+ MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED);
+CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kPrivateExpedited, MEMBARRIER_CMD_PRIVATE_EXPEDITED);
+#undef CHECK_MEMBARRIER_CMD
+
+#endif // __BIONIC
+
+namespace art {
+
+#if defined(__NR_membarrier)
+
+int membarrier(MembarrierCommand command) {
+#if defined(__BIONIC__)
+ // Avoid calling membarrier on older Android versions where membarrier may be barred by secomp
+ // causing the current process to be killed. The probing here could be considered expensive so
+ // endeavour not to repeat too often.
+ static int api_level = android_get_device_api_level();
+ if (api_level < __ANDROID_API_Q__) {
+ errno = ENOSYS;
+ return -1;
+ }
+#endif // __BIONIC__
+ return syscall(__NR_membarrier, static_cast<int>(command), 0);
+}
+
+#else // __NR_membarrier
+
+int membarrier(MembarrierCommand command ATTRIBUTE_UNUSED) {
+ // In principle this could be supported on linux, but Android's prebuilt glibc does not include
+ // the system call number defintions (b/111199492).
+ errno = ENOSYS;
+ return -1;
+}
+
+#endif // __NR_membarrier
+
+} // namespace art
diff --git a/libartbase/base/membarrier.h b/libartbase/base/membarrier.h
new file mode 100644
index 0000000000..f829fc1f80
--- /dev/null
+++ b/libartbase/base/membarrier.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_LIBARTBASE_BASE_MEMBARRIER_H_
+#define ART_LIBARTBASE_BASE_MEMBARRIER_H_
+
+namespace art {
+ // Command types for the linux membarrier system call. Different Linux installation may include
+ // different subsets of these commands (at the same codepoints).
+ //
+ // Hardcoding these values is temporary until bionic and prebuilts glibc have an up to date
+ // linux/membarrier.h. The order and values follow the current linux definitions.
+ enum class MembarrierCommand : int {
+ // MEMBARRIER_CMD_QUERY
+ kQuery = 0,
+ // MEMBARRIER_CMD_GLOBAL
+ kGlobal = (1 << 0),
+ // MEMBARRIER_CMD_GLOBAL_EXPEDITED
+ kGlobalExpedited = (1 << 1),
+ // MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED
+ kRegisterGlobalExpedited = (1 << 2),
+ // MEMBARRIER_CMD_PRIVATE_EXPEDITED
+ kPrivateExpedited = (1 << 3),
+ // MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED
+ kRegisterPrivateExpedited = (1 << 4),
+ // MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE
+ kPrivateExpeditedSyncCore = (1 << 5),
+ // MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE
+ kRegisterPrivateExpeditedSyncCore = (1 << 6)
+ };
+
+ // Call membarrier(2) if available on platform and return result. This method can fail if the
+ // command is not supported by the kernel. The underlying system call is linux specific.
+ int membarrier(MembarrierCommand command);
+
+} // namespace art
+
+#endif // ART_LIBARTBASE_BASE_MEMBARRIER_H_
diff --git a/libartbase/base/membarrier_test.cc b/libartbase/base/membarrier_test.cc
new file mode 100644
index 0000000000..3eedf14dcd
--- /dev/null
+++ b/libartbase/base/membarrier_test.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "membarrier.h"
+
+class ScopedErrnoCleaner {
+ public:
+ ScopedErrnoCleaner() { errno = 0; }
+ ~ScopedErrnoCleaner() { errno = 0; }
+};
+
+bool HasMembarrier(art::MembarrierCommand cmd) {
+ ScopedErrnoCleaner errno_cleaner;
+ int supported_cmds = art::membarrier(art::MembarrierCommand::kQuery);
+ return (supported_cmds > 0) && ((supported_cmds & static_cast<int>(cmd)) != 0);
+}
+
+TEST(membarrier, query) {
+ ScopedErrnoCleaner errno_cleaner;
+ int supported = art::membarrier(art::MembarrierCommand::kQuery);
+ if (errno == 0) {
+ ASSERT_LE(0, supported);
+ } else {
+ ASSERT_TRUE(errno == ENOSYS && supported == -1);
+ }
+}
+
+TEST(membarrier, global_barrier) {
+ if (!HasMembarrier(art::MembarrierCommand::kGlobal)) {
+ GTEST_LOG_(INFO) << "MembarrierCommand::kGlobal not supported, skipping test.";
+ return;
+ }
+ ASSERT_EQ(0, art::membarrier(art::MembarrierCommand::kGlobal));
+}
+
+static const char* MembarrierCommandToName(art::MembarrierCommand cmd) {
+#define CASE_VALUE(x) case (x): return #x;
+ switch (cmd) {
+ CASE_VALUE(art::MembarrierCommand::kQuery);
+ CASE_VALUE(art::MembarrierCommand::kGlobal);
+ CASE_VALUE(art::MembarrierCommand::kGlobalExpedited);
+ CASE_VALUE(art::MembarrierCommand::kRegisterGlobalExpedited);
+ CASE_VALUE(art::MembarrierCommand::kPrivateExpedited);
+ CASE_VALUE(art::MembarrierCommand::kRegisterPrivateExpedited);
+ CASE_VALUE(art::MembarrierCommand::kPrivateExpeditedSyncCore);
+ CASE_VALUE(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore);
+ }
+}
+
+static void TestRegisterAndBarrierCommands(art::MembarrierCommand membarrier_cmd_register,
+ art::MembarrierCommand membarrier_cmd_barrier) {
+ if (!HasMembarrier(membarrier_cmd_register)) {
+ GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_register)
+ << " not supported, skipping test.";
+ return;
+ }
+ if (!HasMembarrier(membarrier_cmd_barrier)) {
+ GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_barrier)
+ << " not supported, skipping test.";
+ return;
+ }
+
+ ScopedErrnoCleaner errno_cleaner;
+
+ // Check barrier use without prior registration.
+ if (membarrier_cmd_register == art::MembarrierCommand::kRegisterGlobalExpedited) {
+ // Global barrier use is always okay.
+ ASSERT_EQ(0, art::membarrier(membarrier_cmd_barrier));
+ } else {
+ // Private barrier should fail.
+ ASSERT_EQ(-1, art::membarrier(membarrier_cmd_barrier));
+ ASSERT_EQ(EPERM, errno);
+ errno = 0;
+ }
+
+ // Check registration for barrier succeeds.
+ ASSERT_EQ(0, art::membarrier(membarrier_cmd_register));
+
+ // Check barrier use after registration succeeds.
+ ASSERT_EQ(0, art::membarrier(membarrier_cmd_barrier));
+}
+
+TEST(membarrier, global_expedited) {
+ TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterGlobalExpedited,
+ art::MembarrierCommand::kGlobalExpedited);
+}
+
+TEST(membarrier, private_expedited) {
+ TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterPrivateExpedited,
+ art::MembarrierCommand::kPrivateExpedited);
+}
+
+TEST(membarrier, private_expedited_sync_core) {
+ TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore,
+ art::MembarrierCommand::kPrivateExpeditedSyncCore);
+}
diff --git a/libartbase/base/memfd.cc b/libartbase/base/memfd.cc
new file mode 100644
index 0000000000..1afcd7b311
--- /dev/null
+++ b/libartbase/base/memfd.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "memfd.h"
+
+#include <errno.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "macros.h"
+
+// When building for linux host, glibc in prebuilts does not include memfd_create system call
+// number. As a temporary testing measure, we add the definition here.
+#if defined(__linux__) && !defined(__NR_memfd_create)
+#if defined(__x86_64__)
+#define __NR_memfd_create 319
+#elif defined(__i386__)
+#define __NR_memfd_create 356
+#endif // defined(__i386__)
+#endif // defined(__linux__) && !defined(__NR_memfd_create)
+
+namespace art {
+
+#if defined(__NR_memfd_create)
+
+int memfd_create(const char* name, unsigned int flags) {
+ return syscall(__NR_memfd_create, name, flags);
+}
+
+#else // __NR_memfd_create
+
+int memfd_create(const char* name ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) {
+ errno = ENOSYS;
+ return -1;
+}
+
+#endif // __NR_memfd_create
+
+} // namespace art
diff --git a/libartbase/base/memfd.h b/libartbase/base/memfd.h
new file mode 100644
index 0000000000..4367198185
--- /dev/null
+++ b/libartbase/base/memfd.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_LIBARTBASE_BASE_MEMFD_H_
+#define ART_LIBARTBASE_BASE_MEMFD_H_
+
+namespace art {
+
+ // Call memfd(2) if available on platform and return result.
+int memfd_create(const char* name, unsigned int flags);
+
+} // namespace art
+
+#endif // ART_LIBARTBASE_BASE_MEMFD_H_
diff --git a/libartbase/base/memfd_test.cc b/libartbase/base/memfd_test.cc
new file mode 100644
index 0000000000..1edf3a11ce
--- /dev/null
+++ b/libartbase/base/memfd_test.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "memfd.h"
+
+TEST(memfd, basic) {
+ errno = 0;
+ int fd = art::memfd_create("memfd_create_test", 0);
+ if (fd < 0) {
+ ASSERT_EQ(ENOSYS, errno);
+ GTEST_LOG_(INFO) << "memfd_create not supported, skipping test.";
+ return;
+ }
+ ASSERT_TRUE(close(fd) == 0 || errno != EBADF);
+}
diff --git a/libartbase/base/utils.cc b/libartbase/base/utils.cc
index 74cc5b97b2..2242fe877e 100644
--- a/libartbase/base/utils.cc
+++ b/libartbase/base/utils.cc
@@ -213,42 +213,4 @@ void SleepForever() {
}
}
-bool FlushInstructionPipeline() {
- // membarrier(2) is only supported for target builds (b/111199492).
-#if defined(__BIONIC__)
- static constexpr int kSyncCoreMask =
- MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE |
- MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE;
- static bool have_probed = false;
- static bool have_sync_core = false;
-
- if (UNLIKELY(!have_probed)) {
- // Probe membarrier(2) commands supported by kernel.
- int commands = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
- if (commands >= 0) {
- have_sync_core = (commands & kSyncCoreMask) == kSyncCoreMask;
- if (have_sync_core) {
- // Register with kernel that we'll be using the private expedited sync core command.
- CheckedCall(syscall,
- "membarrier register sync core",
- __NR_membarrier,
- MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,
- 0);
- }
- }
- have_probed = true;
- }
-
- if (have_sync_core) {
- CheckedCall(syscall,
- "membarrier sync core",
- __NR_membarrier,
- MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE,
- 0);
- return true;
- }
-#endif // defined(__BIONIC__)
- return false;
-}
-
} // namespace art
diff --git a/libartbase/base/utils.h b/libartbase/base/utils.h
index d85960d811..e6a0459e27 100644
--- a/libartbase/base/utils.h
+++ b/libartbase/base/utils.h
@@ -162,9 +162,6 @@ inline void FlushInstructionCache(void* begin, void* end) {
__builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
}
-// Flush instruction pipeline. Returns true on success, false if feature is unsupported.
-bool FlushInstructionPipeline();
-
template <typename T>
constexpr PointerSize ConvertToPointerSize(T any) {
if (any == 4 || any == 8) {
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index bcbdc3bece..191795be91 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -23,6 +23,7 @@
#include "base/enums.h"
#include "base/histogram-inl.h"
#include "base/logging.h" // For VLOG.
+#include "base/membarrier.h"
#include "base/mem_map.h"
#include "base/quasi_atomic.h"
#include "base/stl_util.h"
@@ -187,6 +188,11 @@ JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
return nullptr;
}
+ // Register for membarrier expedited sync core if JIT will be generating code.
+ if (!used_only_for_profile_data) {
+ art::membarrier(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore);
+ }
+
// Decide how we should map the code and data sections.
// If we use the code cache just for profiling we do not need to map the code section as
// executable.
@@ -809,9 +815,8 @@ uint8_t* JitCodeCache::CommitCodeInternal(Thread* self,
// shootdown (incidentally invalidating the CPU pipelines by sending an IPI to all cores to
// notify them of the TLB invalidation). Some architectures, notably ARM and ARM64, have
// hardware support that broadcasts TLB invalidations and so their kernels have no software
- // based TLB shootdown. FlushInstructionPipeline() is a wrapper around the Linux
- // membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED) syscall which does the appropriate flushing.
- FlushInstructionPipeline();
+ // based TLB shootdown.
+ art::membarrier(art::MembarrierCommand::kPrivateExpeditedSyncCore);
DCHECK(!Runtime::Current()->IsAotCompiler());
if (has_should_deoptimize_flag) {