From 53f1b82506bb66f7dddc78d6558b5f577ed09446 Mon Sep 17 00:00:00 2001 From: kuenking Date: Tue, 22 Dec 2020 15:37:01 +0800 Subject: [PATCH] I2ACJN: add appcds file lock --- add-appcds-file-lock.patch | 461 +++++++++++++++++++++++++++++++++++++ java-1.8.0-openjdk.spec | 7 +- 2 files changed, 467 insertions(+), 1 deletion(-) create mode 100755 add-appcds-file-lock.patch diff --git a/add-appcds-file-lock.patch b/add-appcds-file-lock.patch new file mode 100755 index 0000000..b338d12 --- /dev/null +++ b/add-appcds-file-lock.patch @@ -0,0 +1,461 @@ +diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp +index f27d04d0..306315e9 100644 +--- a/hotspot/src/share/vm/classfile/classFileParser.cpp ++++ b/hotspot/src/share/vm/classfile/classFileParser.cpp +@@ -4022,8 +4022,12 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, + if (_host_klass == NULL && SystemDictionaryShared::is_sharing_possible(loader_data)) { + if (name != NULL) { + ResourceMark rm(THREAD); +- classlist_file->print_cr("%s", name->as_C_string()); +- classlist_file->flush(); ++ char *class_name = name->as_C_string(); ++ // TODO Skip JFR-related classes in classlist file to avoid conflicts between appcds and jfr. ++ if ((class_name != NULL) && (strstr(class_name, "jfr") == NULL)) { ++ classlist_file->print_cr("%s", class_name); ++ classlist_file->flush(); ++ } + } + } + } +diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp +index d27bf484..3f28d38e 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp ++++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp +@@ -1283,41 +1283,43 @@ instanceKlassHandle SystemDictionary::load_shared_class( + // null) or the same class loader is used to load previously + // defined class + bool bFound = false; +- if (class_loader.is_null()) { +- // condition1: Bootstrap class loader loaded +- bFound = (ik()->class_loader_data() == NULL || ik()->class_loader_data()->is_the_null_class_loader_data()); +- } else if (ik()->class_loader_data() != NULL) { +- // condition2: App Class Loader +- // condition3: ExtClass Loader +- // Condition4: not fake class Loader, real one +- bFound = ((ik->has_fake_loader_data_App() && SystemDictionary::is_app_class_loader(class_loader)) || +- (ik->has_fake_loader_data_Ext() && SystemDictionary::is_ext_class_loader(class_loader)) || +- (!ik->has_fake_loader_data() && ik()->class_loader() == class_loader())); +- } +- if (!bFound) { +- return instanceKlassHandle(); +- } ++ if (class_loader.is_null()) { ++ // condition1: Bootstrap class loader loaded ++ bFound = (ik()->class_loader_data() == NULL || ik()->class_loader_data()->is_the_null_class_loader_data()); ++ } else if (ik()->class_loader_data() != NULL) { ++ // condition2: App Class Loader ++ // condition3: ExtClass Loader ++ // condition4: not fake class Loader, real one ++ bFound = ((ik->has_fake_loader_data_App() && SystemDictionary::is_app_class_loader(class_loader)) || ++ (ik->has_fake_loader_data_Ext() && SystemDictionary::is_ext_class_loader(class_loader)) || ++ (!ik->has_fake_loader_data() && ik()->class_loader() == class_loader())); ++ } ++ if (!bFound) { ++ return instanceKlassHandle(); ++ } + +- // get protection domain for this class if not loaded by null class loader +- if (class_loader.not_null()) { +- ResourceMark rm(THREAD); +- char* name = ik->name()->as_C_string(); +- Handle klass_name = java_lang_String::create_from_str(name, CHECK_0); +- JavaValue result(T_OBJECT); +- +- // ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); +- JavaCalls::call_virtual(&result, +- class_loader, +- KlassHandle(THREAD, SystemDictionary::URLClassLoader_klass()), +- vmSymbols::getProtectionDomainInternal_name(), +- vmSymbols::getProtectionDomainInternal_signature(), +- klass_name, +- THREAD); +- return load_shared_class(ik, class_loader, Handle(THREAD, (oop) result.get_jobject()), THREAD); +- } else { +- return load_shared_class(ik, class_loader, Handle(), THREAD); +- } ++ // get protection domain for this class if not loaded by null class loader ++ if (class_loader.not_null()) { ++ ResourceMark rm(THREAD); ++ char* name = ik->name()->as_C_string(); ++ Handle klass_name = java_lang_String::create_from_str(name, CHECK_0); ++ JavaValue result(T_OBJECT); ++ ++ // load_shared_class need protected domain to handle non-bootstrap loaded class, ++ // so here call_virtual to call getProtectionDomainInternal function of URLClassLoader.java, ++ // to get protected domain and save into result. ++ JavaCalls::call_virtual(&result, ++ class_loader, ++ KlassHandle(THREAD, SystemDictionary::URLClassLoader_klass()), ++ vmSymbols::getProtectionDomainInternal_name(), ++ vmSymbols::getProtectionDomainInternal_signature(), ++ klass_name, ++ THREAD); ++ return load_shared_class(ik, class_loader, Handle(THREAD, (oop) result.get_jobject()), THREAD); ++ } else { ++ return load_shared_class(ik, class_loader, Handle(), THREAD); + } ++ } + } + return instanceKlassHandle(); + } +@@ -1396,8 +1398,12 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, + // unless AppCDS is enabled + if (SystemDictionaryShared::is_sharing_possible(loader_data)) { + ResourceMark rm(THREAD); +- classlist_file->print_cr("%s", ik->name()->as_C_string()); +- classlist_file->flush(); ++ char *class_name = ik->name()->as_C_string(); ++ // TODO Skip JFR-related classes in classlist file to avoid conflicts between appcds and jfr. ++ if ((class_name != NULL) && (strstr(class_name, "jfr") == NULL)) { ++ classlist_file->print_cr("%s", class_name); ++ classlist_file->flush(); ++ } + } + } + +@@ -1472,8 +1478,10 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Ha + // the call stack. Bootstrap classloader is parallel-capable, + // so no concurrency issues are expected. + CLEAR_PENDING_EXCEPTION; +- k = JfrUpcalls::load_event_handler_proxy_class(THREAD); +- assert(!k.is_null(), "invariant"); ++ if (!DumpSharedSpaces) { ++ k = JfrUpcalls::load_event_handler_proxy_class(THREAD); ++ assert(!k.is_null(), "invariant"); ++ } + } + #endif + +diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +index a8dbda2e..1bd61b02 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp ++++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +@@ -28,6 +28,7 @@ + + #include "classfile/dictionary.hpp" + #include "classfile/systemDictionary.hpp" ++#include "verifier.hpp" + + class SystemDictionaryShared: public SystemDictionary { + public: +@@ -70,7 +71,16 @@ public: + static void finalize_verification_dependencies() {} + static bool check_verification_dependencies(Klass* k, Handle class_loader, + Handle protection_domain, +- char** message_buffer, TRAPS) {return true;} ++ char** message_buffer, TRAPS) { ++ if (EnableSplitVerifierForAppCDS) { ++ ClassVerifier split_verifier(k, THREAD); ++ split_verifier.verify_class(THREAD); ++ if (HAS_PENDING_EXCEPTION) { ++ return false; // use the existing exception ++ } ++ } ++ return true; ++ } + }; + + #endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP +diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp +index 9923058b..eb267b83 100644 +--- a/hotspot/src/share/vm/classfile/verifier.cpp ++++ b/hotspot/src/share/vm/classfile/verifier.cpp +@@ -561,7 +561,8 @@ void ClassVerifier::verify_class(TRAPS) { + + for (int index = 0; index < num_methods; index++) { + // Check for recursive re-verification before each method. +- if (was_recursively_verified()) return; ++ // in CDS Sharing state we still verify the code. ++ if (!UseAppCDS && was_recursively_verified()) return; + + Method* m = methods->at(index); + if (m->is_native() || m->is_abstract() || m->is_overpass()) { +diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp +index 17447587..d2095e63 100644 +--- a/hotspot/src/share/vm/memory/filemap.cpp ++++ b/hotspot/src/share/vm/memory/filemap.cpp +@@ -22,6 +22,7 @@ + * + */ + ++#include "jvm.h" + #include "precompiled.hpp" + #include "classfile/classLoader.hpp" + #include "classfile/sharedClassUtil.hpp" +@@ -33,10 +34,13 @@ + #include "memory/oopFactory.hpp" + #include "oops/objArrayOop.hpp" + #include "runtime/arguments.hpp" ++#include "runtime/globals.hpp" + #include "runtime/java.hpp" + #include "runtime/os.hpp" + #include "services/memTracker.hpp" ++#include "utilities/debug.hpp" + #include "utilities/defaultStream.hpp" ++#include "utilities/ostream.hpp" + + # include + # include +@@ -362,11 +366,33 @@ bool FileMapInfo::open_for_read() { + return true; + } + +- + // Write the FileMapInfo information to the file. +- + void FileMapInfo::open_for_write() { +- _full_path = make_log_name(Arguments::GetSharedArchivePath(), NULL); ++ if (UseAppCDS && AppCDSLockFile != NULL) { ++ char* pos = strrchr(const_cast(AppCDSLockFile), '/'); ++ if (pos != NULL && pos != AppCDSLockFile) { // No directory path specified ++ char buf[PATH_MAX + 1] = "\0"; ++ char filePath[PATH_MAX] = "\0"; ++ int length = pos - AppCDSLockFile + 1; ++ strncpy(filePath, AppCDSLockFile, length); ++ if (realpath(filePath, buf) == NULL) { ++ fail_stop("A risky filePath:%s, buf:%s, length:%d", filePath, buf, length); ++ } ++ _appcds_file_lock_path = os::strdup(AppCDSLockFile, mtInternal); ++ if (_appcds_file_lock_path == NULL) { ++ fail_stop("Failed to create appcds file lock."); ++ } ++ int lock_fd = open(_appcds_file_lock_path, O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR); ++ if (lock_fd < 0) { ++ tty->print_cr("The lock path is: %s", _appcds_file_lock_path); ++ tty->print_cr("Failed to create jsa file !\n Please check: \n 1. The directory exists.\n " ++ "2. You have the permission.\n 3. Make sure no other process using the same lock file.\n"); ++ JVM_Exit(0); ++ } ++ tty->print_cr("You are using file lock %s in concurrent mode", AppCDSLockFile); ++ } ++ } ++ _full_path = make_log_name(Arguments::GetSharedArchivePath(), NULL); + if (PrintSharedSpaces) { + tty->print_cr("Dumping shared data to file: "); + tty->print_cr(" %s", _full_path); +@@ -452,6 +478,7 @@ void FileMapInfo::write_bytes(const void* buffer, int nbytes) { + // close and remove the file. See bug 6372906. + close(); + remove(_full_path); ++ remove(_appcds_file_lock_path); + fail_stop("Unable to write to shared archive file.", NULL); + } + } +@@ -492,6 +519,10 @@ void FileMapInfo::write_bytes_aligned(const void* buffer, int nbytes) { + // Close the shared archive file. This does NOT unmap mapped regions. + + void FileMapInfo::close() { ++ if (UseAppCDS && AppCDSLockFile != NULL) { ++ // delete appcds.lock ++ remove(_appcds_file_lock_path); ++ } + if (_file_open) { + if (::close(_fd) < 0) { + fail_stop("Unable to close the shared archive file."); +diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp +index acff6c9d..c09fbca1 100644 +--- a/hotspot/src/share/vm/memory/filemap.hpp ++++ b/hotspot/src/share/vm/memory/filemap.hpp +@@ -143,6 +143,7 @@ public: + FileMapHeader * _header; + + const char* _full_path; ++ const char* _appcds_file_lock_path; + char* _paths_misc_info; + + static FileMapInfo* _current_info; +diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp +index 073c38ac..ebb5e114 100644 +--- a/hotspot/src/share/vm/runtime/arguments.cpp ++++ b/hotspot/src/share/vm/runtime/arguments.cpp +@@ -36,6 +36,7 @@ + #include "prims/jvmtiExport.hpp" + #include "runtime/arguments.hpp" + #include "runtime/arguments_ext.hpp" ++#include "runtime/globals.hpp" + #include "runtime/globals_extension.hpp" + #include "runtime/java.hpp" + #include "services/management.hpp" +@@ -1493,7 +1494,6 @@ void Arguments::set_use_compressed_oops() { + // the only value that can override MaxHeapSize if we are + // to use UseCompressedOops is InitialHeapSize. + size_t max_heap_size = MAX2(MaxHeapSize, InitialHeapSize); +- + if (max_heap_size <= max_heap_for_compressed_oops()) { + #if !defined(COMPILER1) || defined(TIERED) + if (FLAG_IS_DEFAULT(UseCompressedOops)) { +@@ -3023,9 +3023,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, + if (!process_argument("+UseAppCDS", args->ignoreUnrecognized, origin)) { + return JNI_EINVAL; + } else { +- const char* n = "SharedArchiveFile"; +- Flag* shared_archive_flag = Flag::find_flag(n, strlen(n), true, true); +- shared_archive_flag->unlock_diagnostic(); + FLAG_SET_CMDLINE(bool, UseAppCDS, true); + } + } +@@ -3382,6 +3379,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, + } else if (match_option(option, "-Xshare:off", &tail)) { + FLAG_SET_CMDLINE(bool, UseSharedSpaces, false); + FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false); ++ // -Xtypecheck ++ } else if (match_option(option, "-Xtypecheck:on", &tail)) { ++ FLAG_SET_CMDLINE(bool, EnableSplitVerifierForAppCDS, true); + // -Xverify + } else if (match_option(option, "-Xverify", &tail)) { + if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) { +@@ -3632,7 +3632,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, + FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true); + FLAG_SET_CMDLINE(bool, TraceClassPaths, true); + } +- ++ if (DumpSharedSpaces && !UseAppCDS && AppCDSLockFile != NULL) { ++ jio_fprintf(defaultStream::error_stream(), "AppCDSLockFile is only used when AppCDS is enabled."); ++ return JNI_ERR; ++ } + // Change the default value for flags which have different default values + // when working with older JDKs. + #ifdef LINUX +@@ -4057,6 +4060,7 @@ static char* get_shared_archive_path() { + return shared_archive_path; + } + ++ + #ifndef PRODUCT + // Determine whether LogVMOutput should be implicitly turned on. + static bool use_vm_log() { +@@ -4199,6 +4203,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { + return JNI_ENOMEM; + } + ++ + // Set up VerifySharedSpaces + if (FLAG_IS_DEFAULT(VerifySharedSpaces) && SharedArchiveFile != NULL) { + VerifySharedSpaces = true; +diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp +index 6f7ff138..03f293e3 100644 +--- a/hotspot/src/share/vm/runtime/arguments.hpp ++++ b/hotspot/src/share/vm/runtime/arguments.hpp +@@ -473,6 +473,7 @@ class Arguments : AllStatic { + static bool CheckCompileOnly; + + static char* SharedArchivePath; ++ static char* AppCDSLockPath; + + public: + // Parses the arguments, first phase +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 65b11caa..b72efd45 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -4007,15 +4007,21 @@ class CommandLineFlags { + product(ccstr, SharedClassListFile, NULL, \ + "Override the default CDS class list") \ + \ +- diagnostic(ccstr, SharedArchiveFile, NULL, \ ++ product(ccstr, SharedArchiveFile, NULL, \ + "Override the default location of the CDS archive file") \ + \ ++ product(ccstr, AppCDSLockFile, NULL, \ ++ "Override the default location of the AppCDS lock file") \ ++ \ + product(ccstr, ExtraSharedClassListFile, NULL, \ + "Extra classlist for building the CDS archive file") \ + \ + product(bool, UseAppCDS, false, \ + "Enable Application Class Data Sharing (AppCDS)") \ + \ ++ product(bool, EnableSplitVerifierForAppCDS, false, \ ++ "Enable Type Check (AppCDS)") \ ++ \ + experimental(uintx, ArrayAllocatorMallocLimit, \ + SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx), \ + "Allocation less than this value will be allocated " \ +diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp +index 2b458fe4..587b839b 100644 +--- a/hotspot/src/share/vm/utilities/ostream.cpp ++++ b/hotspot/src/share/vm/utilities/ostream.cpp +@@ -34,6 +34,9 @@ + #include "utilities/ostream.hpp" + #include "utilities/top.hpp" + #include "utilities/xmlstream.hpp" ++ ++# include ++ + #ifdef TARGET_OS_FAMILY_linux + # include "os_linux.inline.hpp" + #endif +@@ -376,7 +379,7 @@ stringStream::~stringStream() {} + xmlStream* xtty; + outputStream* tty; + outputStream* gclog_or_tty; +-CDS_ONLY(fileStream* classlist_file;) // Only dump the classes that can be stored into the CDS archive ++CDS_ONLY(jsaFileStream* classlist_file;) // Only dump the classes that can be stored into the CDS archive + extern Mutex* tty_lock; + + #define EXTRACHARLEN 32 +@@ -760,6 +763,36 @@ void fileStream::flush() { + fflush(_file); + } + ++jsaFileStream::jsaFileStream(const char* file_name) : fileStream(file_name, "a") { ++ if (_file != NULL) { ++ if (flock(fileno(_file), LOCK_EX | LOCK_NB) != 0) { ++ if (errno == EWOULDBLOCK) { ++ warning("file %s is locked by another process\n", file_name); ++ } else { ++ warning("Cannot lock file %s due to %s\n", file_name, strerror(errno)); ++ } ++ fclose(_file); ++ _file = NULL; ++ _need_close = false; ++ } else { ++ if (::ftruncate(fileno(_file), 0) != 0) { ++ warning("Fail to ftruncate file %s due to %s\n", file_name, strerror(errno)); ++ } ++ ::rewind(_file); ++ } ++ } ++} ++ ++jsaFileStream::~jsaFileStream() { ++ // flock is released automatically when _file is closed ++ // Ensure the following sequnce in fclose ++ // 1. fflush. 2. flock(unlock); 3. close ++ if (_file != NULL) { ++ if (_need_close) fclose(_file); ++ _file = NULL; ++ } ++} ++ + fdStream::fdStream(const char* file_name) { + _fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); + _need_close = true; +@@ -1362,7 +1395,7 @@ void ostream_init_log() { + if (DumpLoadedClassList != NULL) { + const char* list_name = make_log_name(DumpLoadedClassList, NULL); + classlist_file = new(ResourceObj::C_HEAP, mtInternal) +- fileStream(list_name); ++ jsaFileStream(list_name); + FREE_C_HEAP_ARRAY(char, list_name, mtInternal); + } + #endif +diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp +index 530c523c..c69289fb 100644 +--- a/hotspot/src/share/vm/utilities/ostream.hpp ++++ b/hotspot/src/share/vm/utilities/ostream.hpp +@@ -214,7 +214,13 @@ class fileStream : public outputStream { + void flush(); + }; + +-CDS_ONLY(extern fileStream* classlist_file;) ++class jsaFileStream : public fileStream { ++ public: ++ jsaFileStream(const char* file_name); ++ ~jsaFileStream(); ++}; ++ ++CDS_ONLY(extern jsaFileStream* classlist_file;) + + // unlike fileStream, fdStream does unbuffered I/O by calling + // open() and write() directly. It is async-safe, but output diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index c69aaea..4659dca 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -915,7 +915,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 7 +Release: 8 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1063,6 +1063,7 @@ Patch134: PS-GC-adding-acquire_size-method-for-PSParallelCompa.patch Patch135: 8223940-Private-key-not-supported-by-chosen-signature.patch Patch136: 8236512-PKCS11-Connection-closed-after-Cipher.doFinal-and-NoPadding.patch Patch137: 8250861-Crash-in-MinINode-Ideal-PhaseGVN-bool.patch +Patch138: add-appcds-file-lock.patch ############################################# # @@ -1481,6 +1482,7 @@ pushd %{top_level_dir_name} %patch135 -p1 %patch136 -p1 %patch137 -p1 +%patch138 -p1 popd @@ -2097,6 +2099,9 @@ require "copy_jdk_configs.lua" %endif %changelog +* Thu Dec 22 2020 kuenking - 1:1.8.0.272-b10.8 +- add add-appcds-file-lock.patch + * Mon Dec 21 2020 noah - 1:1.8.0.272-b10.7 - add a license to this repo -- Gitee