From 1cae0f53a9d37fbae9471bd942f7157429a85cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Thu, 7 Sep 2023 16:12:55 +0000 Subject: [PATCH] 8315220: Event NativeLibraryLoad breaks invariant by taking a stacktrace when thread is in state _thread_in_native Reviewed-by: mbaesken, egahlin --- src/hotspot/os/aix/os_aix.cpp | 25 +--- src/hotspot/os/bsd/os_bsd.cpp | 41 ++---- src/hotspot/os/linux/os_linux.cpp | 25 +--- src/hotspot/os/posix/os_posix.cpp | 19 +-- src/hotspot/os/windows/os_windows.cpp | 62 ++------- src/hotspot/share/jfr/metadata/metadata.xml | 4 +- .../jfr/support/jfrNativeLibraryLoadEvent.cpp | 123 ++++++++++++++++++ .../jfr/support/jfrNativeLibraryLoadEvent.hpp | 71 ++++++++++ src/hotspot/share/jfr/utilities/jfrTime.hpp | 12 +- .../runtime/TestNativeLibraryLoadEvent.java | 51 ++++++-- 10 files changed, 281 insertions(+), 152 deletions(-) create mode 100644 src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.cpp create mode 100644 src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.hpp diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 641a1652bbd..040f569d907 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -81,7 +81,7 @@ #include "utilities/growableArray.hpp" #include "utilities/vmError.hpp" #if INCLUDE_JFR -#include "jfr/jfrEvents.hpp" +#include "jfr/support/jfrNativeLibraryLoadEvent.hpp" #endif // put OS-includes here (sorted alphabetically) @@ -1116,11 +1116,6 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { return nullptr; } -#if INCLUDE_JFR - EventNativeLibraryLoad event; - event.set_name(filename); -#endif - // RTLD_LAZY has currently the same behavior as RTLD_NOW // The dl is loaded immediately with all its dependants. int dflags = RTLD_LAZY; @@ -1131,19 +1126,14 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { dflags |= RTLD_MEMBER; } - void * result= ::dlopen(filename, dflags); + void* result; + JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) + result = ::dlopen(filename, dflags); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); // Reload dll cache. Don't do this in signal handling. LoadedLibraries::reload(); log_info(os)("shared library load of %s was successful", filename); - -#if INCLUDE_JFR - event.set_success(true); - event.set_errorMessage(nullptr); - event.commit(); -#endif - return result; } else { // error analysis when dlopen fails @@ -1157,12 +1147,7 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); - -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage(error_report); - event.commit(); -#endif + JFR_ONLY(load_event.set_error_msg(error_report);) } return nullptr; } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 054c89f5554..53f4c5ad703 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -71,6 +71,7 @@ #include "utilities/vmError.hpp" #if INCLUDE_JFR #include "jfr/jfrEvents.hpp" +#include "jfr/support/jfrNativeLibraryLoadEvent.hpp" #endif // put OS-includes here @@ -979,21 +980,13 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { #else log_info(os)("attempting shared library load of %s", filename); -#if INCLUDE_JFR - EventNativeLibraryLoad event; - event.set_name(filename); -#endif - - void * result= ::dlopen(filename, RTLD_LAZY); + void* result; + JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) + result = ::dlopen(filename, RTLD_LAZY); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); // Successful loading log_info(os)("shared library load of %s was successful", filename); -#if INCLUDE_JFR - event.set_success(true); - event.set_errorMessage(nullptr); - event.commit(); -#endif return result; } @@ -1008,11 +1001,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage(error_report); - event.commit(); -#endif + JFR_ONLY(load_event.set_error_msg(error_report);) return nullptr; #endif // STATIC_BUILD @@ -1024,21 +1013,13 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { #else log_info(os)("attempting shared library load of %s", filename); -#if INCLUDE_JFR - EventNativeLibraryLoad event; - event.set_name(filename); -#endif - - void * result= ::dlopen(filename, RTLD_LAZY); + void* result; + JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) + result = ::dlopen(filename, RTLD_LAZY); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); // Successful loading log_info(os)("shared library load of %s was successful", filename); -#if INCLUDE_JFR - event.set_success(true); - event.set_errorMessage(nullptr); - event.commit(); -#endif return result; } @@ -1055,11 +1036,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage(error_report); - event.commit(); -#endif + JFR_ONLY(load_event.set_error_msg(error_report);) int diag_msg_max_length=ebuflen-strlen(ebuf); char* diag_msg_buf=ebuf+strlen(ebuf); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 3a1785b27b5..9845aded4c7 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -82,6 +82,7 @@ #include "utilities/vmError.hpp" #if INCLUDE_JFR #include "jfr/jfrEvents.hpp" +#include "jfr/support/jfrNativeLibraryLoadEvent.hpp" #endif // put OS-includes here @@ -1794,15 +1795,10 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { return nullptr; } -void * os::Linux::dlopen_helper(const char *filename, char *ebuf, - int ebuflen) { - void * result = ::dlopen(filename, RTLD_LAZY); - -#if INCLUDE_JFR - EventNativeLibraryLoad event; - event.set_name(filename); -#endif - +void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) { + void* result; + JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) + result = ::dlopen(filename, RTLD_LAZY); if (result == nullptr) { const char* error_report = ::dlerror(); if (error_report == nullptr) { @@ -1814,19 +1810,10 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage(error_report); - event.commit(); -#endif + JFR_ONLY(load_event.set_error_msg(error_report);) } else { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); log_info(os)("shared library load of %s was successful", filename); -#if INCLUDE_JFR - event.set_success(true); - event.set_errorMessage(nullptr); - event.commit(); -#endif } return result; } diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index c302a5d031c..95b90dd9f4a 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -51,7 +51,7 @@ #include "utilities/macros.hpp" #include "utilities/vmError.hpp" #if INCLUDE_JFR -#include "jfr/jfrEvents.hpp" +#include "jfr/support/jfrNativeLibraryLoadEvent.hpp" #endif #ifdef AIX @@ -728,10 +728,7 @@ void os::dll_unload(void *lib) { } #endif // LINUX -#if INCLUDE_JFR - EventNativeLibraryUnload event; - event.set_name(l_path); -#endif + JFR_ONLY(NativeLibraryUnloadEvent unload_event(l_path);) if (l_path == nullptr) { l_path = ""; @@ -742,11 +739,7 @@ void os::dll_unload(void *lib) { Events::log_dll_message(nullptr, "Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib)); log_info(os)("Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib)); -#if INCLUDE_JFR - event.set_success(true); - event.set_errorMessage(nullptr); - event.commit(); -#endif + JFR_ONLY(unload_event.set_result(true);) } else { const char* error_report = ::dlerror(); if (error_report == nullptr) { @@ -757,11 +750,7 @@ void os::dll_unload(void *lib) { l_path, p2i(lib), error_report); log_info(os)("Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s", l_path, p2i(lib), error_report); -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage(error_report); - event.commit(); -#endif + JFR_ONLY(unload_event.set_error_msg(error_report);) } // Update the dll cache AIX_ONLY(LoadedLibraries::reload()); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 5563169151b..d2da73ac0aa 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -80,6 +80,7 @@ #include "windbghelp.hpp" #if INCLUDE_JFR #include "jfr/jfrEvents.hpp" +#include "jfr/support/jfrNativeLibraryLoadEvent.hpp" #endif #ifdef _DEBUG @@ -1246,33 +1247,22 @@ void os::dll_unload(void *lib) { snprintf(name, MAX_PATH, ""); } -#if INCLUDE_JFR - EventNativeLibraryUnload event; - event.set_name(name); -#endif + JFR_ONLY(NativeLibraryUnloadEvent unload_event(name);) if (::FreeLibrary((HMODULE)lib)) { Events::log_dll_message(nullptr, "Unloaded dll \"%s\" [" INTPTR_FORMAT "]", name, p2i(lib)); log_info(os)("Unloaded dll \"%s\" [" INTPTR_FORMAT "]", name, p2i(lib)); -#if INCLUDE_JFR - event.set_success(true); - event.set_errorMessage(nullptr); - event.commit(); -#endif + JFR_ONLY(unload_event.set_result(true);) } else { const DWORD errcode = ::GetLastError(); char buf[500]; size_t tl = os::lasterror(buf, sizeof(buf)); Events::log_dll_message(nullptr, "Attempt to unload dll \"%s\" [" INTPTR_FORMAT "] failed (error code %d)", name, p2i(lib), errcode); log_info(os)("Attempt to unload dll \"%s\" [" INTPTR_FORMAT "] failed (error code %d)", name, p2i(lib), errcode); -#if INCLUDE_JFR - event.set_success(false); if (tl == 0) { os::snprintf(buf, sizeof(buf), "Attempt to unload dll failed (error code %d)", (int) errcode); } - event.set_errorMessage(buf); - event.commit(); -#endif + JFR_ONLY(unload_event.set_error_msg(buf);) } } @@ -1541,21 +1531,14 @@ static int _print_module(const char* fname, address base_address, // same architecture as Hotspot is running on void * os::dll_load(const char *name, char *ebuf, int ebuflen) { log_info(os)("attempting shared library load of %s", name); -#if INCLUDE_JFR - EventNativeLibraryLoad event; - event.set_name(name); -#endif - void * result = LoadLibrary(name); + void* result; + JFR_ONLY(NativeLibraryLoadEvent load_event(name, &result);) + result = LoadLibrary(name); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", name); // Recalculate pdb search path if a DLL was loaded successfully. SymbolEngine::recalc_search_path(); log_info(os)("shared library load of %s was successful", name); -#if INCLUDE_JFR - event.set_success(true); - event.set_errorMessage(nullptr); - event.commit(); -#endif return result; } DWORD errcode = GetLastError(); @@ -1569,11 +1552,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { if (errcode == ERROR_MOD_NOT_FOUND) { strncpy(ebuf, "Can't find dependent libraries", ebuflen - 1); ebuf[ebuflen - 1] = '\0'; -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage(ebuf); - event.commit(); -#endif + JFR_ONLY(load_event.set_error_msg(ebuf);) return nullptr; } @@ -1584,11 +1563,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { // else call os::lasterror to obtain system error message int fd = ::open(name, O_RDONLY | O_BINARY, 0); if (fd < 0) { -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage("open on dll file did not work"); - event.commit(); -#endif + JFR_ONLY(load_event.set_error_msg("open on dll file did not work");) return nullptr; } @@ -1615,11 +1590,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { ::close(fd); if (failed_to_get_lib_arch) { // file i/o error - report os::lasterror(...) msg -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage("failed to get lib architecture"); - event.commit(); -#endif + JFR_ONLY(load_event.set_error_msg("failed to get lib architecture");) return nullptr; } @@ -1664,11 +1635,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { // If the architecture is right // but some other error took place - report os::lasterror(...) msg if (lib_arch == running_arch) { -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage("lib architecture matches, but other error occured"); - event.commit(); -#endif + JFR_ONLY(load_event.set_error_msg("lib architecture matches, but other error occured");) return nullptr; } @@ -1682,12 +1649,7 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { "Can't load this .dll (machine code=0x%x) on a %s-bit platform", lib_arch, running_arch_str); } -#if INCLUDE_JFR - event.set_success(false); - event.set_errorMessage(ebuf); - event.commit(); -#endif - + JFR_ONLY(load_event.set_error_msg(ebuf);) return nullptr; } diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index f8fc4e5bccd..3a2a63276bf 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -939,14 +939,14 @@ - - diff --git a/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.cpp b/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.cpp new file mode 100644 index 00000000000..42919e69085 --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.cpp @@ -0,0 +1,123 @@ +/* +* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +* +*/ + +#include "precompiled.hpp" +#include "jfr/jfrEvents.hpp" +#include "jfr/support/jfrNativeLibraryLoadEvent.hpp" +#include "jfr/utilities/jfrTime.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/thread.inline.hpp" + +JfrNativeLibraryEventBase::JfrNativeLibraryEventBase(const char* name) : _name(name), _error_msg(nullptr), _start_time(nullptr) {} + +JfrNativeLibraryEventBase::~JfrNativeLibraryEventBase() { + delete _start_time; +} + +const char* JfrNativeLibraryEventBase::name() const { + return _name; +} + +JfrTicksWrapper* JfrNativeLibraryEventBase::start_time() const { + return _start_time; +} + +bool JfrNativeLibraryEventBase::has_start_time() const { + return _start_time != nullptr; +} + +const char* JfrNativeLibraryEventBase::error_msg() const { + return _error_msg; +} + +void JfrNativeLibraryEventBase::set_error_msg(const char* error_msg) { + assert(_error_msg == nullptr, "invariant"); + _error_msg = error_msg; +} + +/* + * The JfrTicks value is heap allocated inside an object of type JfrTicksWrapper. + * The reason is that a raw value object of type Ticks is not possible at this + * location because this code runs as part of early VM bootstrap, at a moment + * where Ticks support is not yet initialized. + */ +template +static inline JfrTicksWrapper* allocate_start_time() { + return EventType::is_enabled() ? new JfrTicksWrapper() : nullptr; +} + +NativeLibraryLoadEvent::NativeLibraryLoadEvent(const char* name, void** result) : JfrNativeLibraryEventBase(name), _result(result) { + assert(_result != nullptr, "invariant"); + _start_time = allocate_start_time(); +} + +bool NativeLibraryLoadEvent::success() const { + return *_result != nullptr; +} + +NativeLibraryUnloadEvent::NativeLibraryUnloadEvent(const char* name) : JfrNativeLibraryEventBase(name), _result(false) { + _start_time = allocate_start_time(); +} + +bool NativeLibraryUnloadEvent::success() const { + return _result; +} + +void NativeLibraryUnloadEvent::set_result(bool result) { + _result = result; +} + +template +static void commit(HelperType& helper) { + if (!helper.has_start_time()) { + return; + } + EventType event(UNTIMED); + event.set_endtime(JfrTicks::now()); + event.set_starttime(*helper.start_time()); + event.set_name(helper.name()); + event.set_errorMessage(helper.error_msg()); + event.set_success(helper.success()); + Thread* thread = Thread::current(); + assert(thread != nullptr, "invariant"); + if (thread->is_Java_thread()) { + JavaThread* jt = JavaThread::cast(thread); + if (jt->thread_state() != _thread_in_vm) { + assert(jt->thread_state() == _thread_in_native, "invariant"); + // For a JavaThread to take a JFR stacktrace, it must be in _thread_in_vm. Can safepoint here. + ThreadInVMfromNative transition(jt); + event.commit(); + return; + } + } + event.commit(); +} + +NativeLibraryLoadEvent::~NativeLibraryLoadEvent() { + commit(*this); +} + +NativeLibraryUnloadEvent::~NativeLibraryUnloadEvent() { + commit(*this); +} diff --git a/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.hpp b/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.hpp new file mode 100644 index 00000000000..fe8431fdc43 --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrNativeLibraryLoadEvent.hpp @@ -0,0 +1,71 @@ +/* +* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +* +*/ + +#ifndef SHARE_JFR_SUPPORT_JFRNATIVELIBRARYLOADEVENT_HPP +#define SHARE_JFR_SUPPORT_JFRNATIVELIBRARYLOADEVENT_HPP + +#include "memory/allocation.hpp" + +class JfrTicksWrapper; + +/* + * Helper types for populating NativeLibrary events. + * Event commit is run as part of destructors. + */ + +class JfrNativeLibraryEventBase : public StackObj { + protected: + const char* _name; + const char* _error_msg; + JfrTicksWrapper* _start_time; + JfrNativeLibraryEventBase(const char* name); + ~JfrNativeLibraryEventBase(); + public: + const char* name() const; + const char* error_msg() const; + void set_error_msg(const char* error_msg); + JfrTicksWrapper* start_time() const; + bool has_start_time() const; +}; + +class NativeLibraryLoadEvent : public JfrNativeLibraryEventBase { + private: + void** _result; + public: + NativeLibraryLoadEvent(const char* name, void** result); + ~NativeLibraryLoadEvent(); + bool success() const; +}; + +class NativeLibraryUnloadEvent : public JfrNativeLibraryEventBase { + private: + bool _result; + public: + NativeLibraryUnloadEvent(const char* name); + ~NativeLibraryUnloadEvent(); + bool success() const; + void set_result(bool result); +}; + +#endif // SHARE_JFR_SUPPORT_JFRNATIVELIBRARYLOADEVENT_HPP diff --git a/src/hotspot/share/jfr/utilities/jfrTime.hpp b/src/hotspot/share/jfr/utilities/jfrTime.hpp index 3b919b38535..b92b95a8692 100644 --- a/src/hotspot/share/jfr/utilities/jfrTime.hpp +++ b/src/hotspot/share/jfr/utilities/jfrTime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef SHARE_JFR_UTILITIES_JFRTIME_HPP #define SHARE_JFR_UTILITIES_JFRTIME_HPP +#include "jfr/utilities/jfrAllocation.hpp" #include "utilities/ticks.hpp" typedef TimeInstant JfrTicks; @@ -41,4 +42,13 @@ class JfrTime { static const void* time_function(); }; +// For dynamically allocated Ticks values. +class JfrTicksWrapper : public JfrCHeapObj { + private: + JfrTicks _ticks; + public: + JfrTicksWrapper() : _ticks(JfrTicks::now()) {} + operator JfrTicks() const { return _ticks; } +}; + #endif // SHARE_JFR_UTILITIES_JFRTIME_HPP diff --git a/test/jdk/jdk/jfr/event/runtime/TestNativeLibraryLoadEvent.java b/test/jdk/jdk/jfr/event/runtime/TestNativeLibraryLoadEvent.java index 55053e92800..240045c1d60 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestNativeLibraryLoadEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestNativeLibraryLoadEvent.java @@ -23,14 +23,15 @@ package jdk.jfr.event.runtime; +import static jdk.test.lib.Asserts.assertNotNull; +import static jdk.test.lib.Asserts.assertNull; import static jdk.test.lib.Asserts.assertTrue; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.consumer.RecordedStackTrace; import jdk.test.lib.Platform; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; @@ -46,25 +47,49 @@ import jdk.test.lib.jfr.Events; public class TestNativeLibraryLoadEvent { private final static String EVENT_NAME = EventNames.NativeLibraryLoad; + private final static String LOAD_CLASS_NAME = "java.lang.System"; + private final static String LOAD_METHOD_NAME = "loadLibrary"; + private final static String LIBRARY = "instrument"; + private final static String PLATFORM_LIBRARY_NAME = Platform.buildSharedLibraryName(LIBRARY); public static void main(String[] args) throws Throwable { try (Recording recording = new Recording()) { recording.enable(EVENT_NAME); recording.start(); - System.loadLibrary("instrument"); + System.loadLibrary(LIBRARY); recording.stop(); - String expectedLib = Platform.buildSharedLibraryName("instrument"); - boolean expectedLibFound = false; for (RecordedEvent event : Events.fromRecording(recording)) { - System.out.println("Event:" + event); - String lib = Events.assertField(event, "name").notEmpty().getValue(); - Events.assertField(event, "success"); - if (lib.contains(expectedLib)) { - expectedLibFound = true; + if (validate(event)) { + return; } } - assertTrue(expectedLibFound, "Missing library " + expectedLib); + assertTrue(false, "Missing library " + PLATFORM_LIBRARY_NAME); } } + + private static boolean validate(RecordedEvent event) { + assertTrue(event.getEventType().getName().equals(EVENT_NAME)); + String lib = Events.assertField(event, "name").notEmpty().getValue(); + System.out.println(lib); + if (!lib.endsWith(PLATFORM_LIBRARY_NAME)) { + return false; + } + assertTrue(Events.assertField(event, "success").getValue()); + assertNull(Events.assertField(event, "errorMessage").getValue()); + RecordedStackTrace stacktrace = event.getStackTrace(); + assertNotNull(stacktrace); + for (RecordedFrame f : stacktrace.getFrames()) { + if (match(f.getMethod())) { + return true; + } + } + return false; + } + + private static boolean match(RecordedMethod method) { + assertNotNull(method); + System.out.println(method.getType().getName() + "." + method.getName()); + return method.getName().equals(LOAD_METHOD_NAME) && method.getType().getName().equals(LOAD_CLASS_NAME); + } }