Introduce `art::FastExit` to replace all uses of `quick_exit` in ART.
No longer use `quick_exit(3)` in ART, as it does not play well with
Clang's code coverage instrumentation (see b/187935521 and
b/186576313). Replace all its uses with a new routine,
`art::FastExit`, calling either `exit(3)` when ART is built with
Clang's code coverage instrumentation (in order to dump coverage
profiles when the program terminates) or `_exit(2)` otherwise (to exit
quickly).
Function `art::FastExit` is implemented as part of the
`art_libartbase_headers` header library, so that it can be used easily
in `dalvikvm`.
Test: mmma art
Test: ART tests
Bug: 186576313
Bug: 187935521
Change-Id: I7b4f86f6f0e7b12814684ecea73a2ed0ef994395
diff --git a/dalvikvm/Android.bp b/dalvikvm/Android.bp
index a1f57ca..6e06eba 100644
--- a/dalvikvm/Android.bp
+++ b/dalvikvm/Android.bp
@@ -34,6 +34,9 @@
"liblog",
"libnativehelper",
],
+ header_libs: [
+ "art_libartbase_headers", // For base/fast_exit.h
+ ],
target: {
android: {
shared_libs: [
diff --git a/dalvikvm/dalvikvm.cc b/dalvikvm/dalvikvm.cc
index f2cc225..27709fd 100644
--- a/dalvikvm/dalvikvm.cc
+++ b/dalvikvm/dalvikvm.cc
@@ -21,6 +21,7 @@
#include <algorithm>
#include <memory>
+#include "base/fast_exit.h"
#include "jni.h"
#include "nativehelper/JniInvocation.h"
#include "nativehelper/ScopedLocalRef.h"
@@ -215,8 +216,6 @@
int main(int argc, char** argv) {
// Do not allow static destructors to be called, since it's conceivable that
- // daemons may still awaken (literally); but still have functions registered
- // with `at_quick_exit` (for instance LLVM's code coverage profile dumping
- // routine) be called before exiting.
- quick_exit(art::dalvikvm(argc, argv));
+ // daemons may still awaken (literally).
+ art::FastExit(art::dalvikvm(argc, argv));
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 38dd23e..4cf42cc 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -52,6 +52,7 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "base/os.h"
+#include "base/fast_exit.h"
#include "base/scoped_flock.h"
#include "base/stl_util.h"
#include "base/time_utils.h"
@@ -3157,11 +3158,9 @@
int result = static_cast<int>(art::Dex2oat(argc, argv));
// Everything was done, do an explicit exit here to avoid running Runtime destructors that take
// time (bug 10645725) unless we're a debug or instrumented build or running on a memory tool.
- // Also have functions registered with `at_quick_exit` (for instance LLVM's code coverage
- // profile dumping routine) be called before exiting.
// Note: The Dex2Oat class should not destruct the runtime in this case.
if (!art::kIsDebugBuild && !art::kIsPGOInstrumentation && !art::kRunningOnMemoryTool) {
- quick_exit(result);
+ art::FastExit(result);
}
return result;
}
diff --git a/libartbase/base/fast_exit.h b/libartbase/base/fast_exit.h
new file mode 100644
index 0000000..35dd85e
--- /dev/null
+++ b/libartbase/base/fast_exit.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 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_FAST_EXIT_H_
+#define ART_LIBARTBASE_BASE_FAST_EXIT_H_
+
+// Header-only definition of `art::FastExit`.
+//
+// Ideally, this routine should be declared in `base/os.h` and defined in
+// `base/os_linux.cc`, but as `libartbase` is not linked (directly) with
+// `dalvikvm`, we would not be able to easily use `art::FastExit` in
+// `dex2oat`. Use a header-only approach and define `art::FastExit` in its own
+// file for clarity.
+
+#include <base/macros.h>
+
+namespace art {
+
+#ifdef __ANDROID_CLANG_COVERAGE__
+static constexpr bool kAndroidClangCoverage = true;
+#else
+static constexpr bool kAndroidClangCoverage = false;
+#endif
+
+// Terminate program without completely cleaning the resources (e.g. without
+// calling destructors), unless ART is built with Clang (native) code coverage
+// instrumentation; in that case, exit normally to allow LLVM's code coverage
+// profile dumping routine (`__llvm_profile_write_file`), registered via
+// `atexit` in Android when Clang instrumentation is enabled, to be called
+// before terminating the program.
+NO_RETURN inline void FastExit(int exit_code) {
+ if (kAndroidClangCoverage) {
+ exit(exit_code);
+ } else {
+ _exit(exit_code);
+ }
+}
+
+} // namespace art
+
+#endif // ART_LIBARTBASE_BASE_FAST_EXIT_H_
diff --git a/openjdkjvm/OpenjdkJvm.cc b/openjdkjvm/OpenjdkJvm.cc
index 90c944c..9b514af 100644
--- a/openjdkjvm/OpenjdkJvm.cc
+++ b/openjdkjvm/OpenjdkJvm.cc
@@ -35,7 +35,6 @@
#include <dlfcn.h>
#include <limits.h>
#include <stdio.h>
-#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -46,6 +45,7 @@
#include "../../libcore/ojluni/src/main/native/jvm.h" // TODO(narayan): fix it
#include "base/macros.h"
+#include "base/fast_exit.h"
#include "common_throws.h"
#include "gc/heap.h"
#include "handle_scope-inl.h"
@@ -315,10 +315,8 @@
LOG(INFO) << "System.exit called, status: " << status;
art::Runtime::Current()->CallExitHook(status);
// Unsafe to call exit() while threads may still be running. They would race
- // with static destructors. However, have functions registered with
- // `at_quick_exit` (for instance LLVM's code coverage profile dumping routine)
- // be called before exiting.
- quick_exit(status);
+ // with static destructors.
+ art::FastExit(status);
}
JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
diff --git a/perfetto_hprof/perfetto_hprof.cc b/perfetto_hprof/perfetto_hprof.cc
index 0a7f380..3affe8d 100644
--- a/perfetto_hprof/perfetto_hprof.cc
+++ b/perfetto_hprof/perfetto_hprof.cc
@@ -19,11 +19,11 @@
#include "perfetto_hprof.h"
#include <android-base/logging.h>
+#include <base/fast_exit.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sched.h>
#include <signal.h>
-#include <stdlib.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -847,11 +847,9 @@
});
LOG(INFO) << "finished dumping heap for " << parent_pid;
- // Prevent the atexit handlers to run. We do not want to call cleanup
- // functions the parent process has registered. However, have functions
- // registered with `at_quick_exit` (for instance LLVM's code coverage profile
- // dumping routine) be called before exiting.
- quick_exit(0);
+ // Prevent the `atexit` handlers from running. We do not want to call cleanup
+ // functions the parent process has registered.
+ art::FastExit(0);
}
// The plugin initialization function.
diff --git a/runtime/runtime_options.cc b/runtime/runtime_options.cc
index 12dab15..e21587a 100644
--- a/runtime/runtime_options.cc
+++ b/runtime/runtime_options.cc
@@ -18,6 +18,7 @@
#include <memory>
+#include "base/fast_exit.h"
#include "base/sdk_version.h"
#include "base/utils.h"
#include "debugger.h"
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 9667484..c60c0b3 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -156,12 +156,10 @@
RUNTIME_OPTIONS_KEY (bool (*)(), HookIsSensitiveThread)
RUNTIME_OPTIONS_KEY (int32_t (*)(FILE* stream, const char* format, va_list ap), \
HookVfprintf, vfprintf)
-// Use `quick_exit` instead of `exit` so that we won't get DCHECK failures
-// in global data destructors (see b/28106055); but still have functions
-// registered with `at_quick_exit` (for instance LLVM's code coverage profile
-// dumping routine) be called before exiting.
+// Use `art::FastExit` instead of `exit` so that we won't get DCHECK failures
+// in global data destructors (see b/28106055).
RUNTIME_OPTIONS_KEY (void (*)(int32_t status), \
- HookExit, quick_exit)
+ HookExit, art::FastExit)
// We don't call abort(3) by default; see
// Runtime::Abort.
RUNTIME_OPTIONS_KEY (void (*)(), HookAbort, nullptr)