8245113: JFR Recorder Thread to run in thread state "_thread_in_native"

Reviewed-by: egahlin
This commit is contained in:
Markus Grönlund 2020-06-11 10:48:35 +02:00
parent b9ce3b435e
commit 0228a5c767
14 changed files with 154 additions and 90 deletions

@ -723,18 +723,20 @@ static bool check_exclusion_state_on_thread_start(JavaThread* jt) {
return true;
}
jlong JfrJavaSupport::jfr_thread_id(jobject thread) {
static JavaThread* get_native(jobject thread) {
ThreadsListHandle tlh;
JavaThread* native_thread = NULL;
(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
return native_thread;
}
jlong JfrJavaSupport::jfr_thread_id(jobject thread) {
JavaThread* native_thread = get_native(thread);
return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0;
}
void JfrJavaSupport::exclude(jobject thread) {
HandleMark hm;
ThreadsListHandle tlh;
JavaThread* native_thread = NULL;
(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
JavaThread* native_thread = get_native(thread);
if (native_thread != NULL) {
JfrThreadLocal::exclude(native_thread);
} else {
@ -744,10 +746,7 @@ void JfrJavaSupport::exclude(jobject thread) {
}
void JfrJavaSupport::include(jobject thread) {
HandleMark hm;
ThreadsListHandle tlh;
JavaThread* native_thread = NULL;
(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
JavaThread* native_thread = get_native(thread);
if (native_thread != NULL) {
JfrThreadLocal::include(native_thread);
} else {
@ -757,10 +756,7 @@ void JfrJavaSupport::include(jobject thread) {
}
bool JfrJavaSupport::is_excluded(jobject thread) {
HandleMark hm;
ThreadsListHandle tlh;
JavaThread* native_thread = NULL;
(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
JavaThread* native_thread = get_native(thread);
return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread);
}

@ -179,6 +179,12 @@ NO_TRANSITION(jboolean, jfr_should_rotate_disk(JNIEnv* env, jobject jvm))
return JfrChunkRotation::should_rotate() ? JNI_TRUE : JNI_FALSE;
NO_TRANSITION_END
NO_TRANSITION(jlong, jfr_get_type_id_from_string(JNIEnv * env, jobject jvm, jstring type))
const char* type_name = env->GetStringUTFChars(type, NULL);
jlong id = JfrType::name_to_id(type_name);
env->ReleaseStringUTFChars(type, type_name);
return id;
NO_TRANSITION_END
/*
* JVM_ENTRY_NO_ENV entries
*
@ -350,11 +356,3 @@ JVM_END
JVM_ENTRY_NO_ENV(jboolean, jfr_set_handler(JNIEnv * env, jobject jvm, jobject clazz, jobject handler))
return JfrJavaSupport::set_handler(clazz, handler, thread);
JVM_END
NO_TRANSITION(jlong, jfr_get_type_id_from_string(JNIEnv * env, jobject jvm, jstring type))
const char* type_name= env->GetStringUTFChars(type, NULL);
jlong id = JfrType::name_to_id(type_name);
env->ReleaseStringUTFChars(type, type_name);
return id;
NO_TRANSITION_END

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/leakprofiler/chains/edgeStore.hpp"
#include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
@ -40,10 +41,12 @@
#include "jfr/utilities/jfrHashtable.hpp"
#include "jfr/utilities/jfrPredicate.hpp"
#include "jfr/utilities/jfrRelation.hpp"
#include "memory/resourceArea.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/thread.hpp"
#include "runtime/thread.inline.hpp"
const int initial_array_size = 64;
@ -248,17 +251,21 @@ static void install_stack_traces(const ObjectSampler* sampler, JfrStackTraceRepo
assert(sampler != NULL, "invariant");
const ObjectSample* const last = sampler->last();
if (last != sampler->last_resolved()) {
ResourceMark rm;
JfrKlassUnloading::sort();
StackTraceBlobInstaller installer(stack_trace_repo);
iterate_samples(installer);
}
}
// caller needs ResourceMark
void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) {
assert(JfrStream_lock->owned_by_self(), "invariant");
assert(sampler != NULL, "invariant");
assert(LeakProfiler::is_running(), "invariant");
Thread* const thread = Thread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread);)
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)thread);
MutexLocker lock(ClassLoaderDataGraph_lock);
// the lock is needed to ensure the unload lists do not grow in the middle of inspection.
install_stack_traces(sampler, stack_trace_repo);
@ -416,6 +423,7 @@ static void save_type_set_blob(JfrCheckpointWriter& writer, bool copy = false) {
void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
assert(LeakProfiler::is_running(), "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(Thread::current());)
const ObjectSample* last = ObjectSampler::sampler()->last();
if (writer.has_data() && last != NULL) {
save_type_set_blob(writer);

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
@ -48,6 +49,7 @@
#include "memory/resourceArea.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/mutex.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/safepoint.hpp"
@ -325,6 +327,7 @@ void JfrCheckpointManager::end_epoch_shift() {
}
size_t JfrCheckpointManager::write() {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
assert(_mspace->free_list_is_empty(), "invariant");
WriteOperation wo(_chunkwriter);
MutexedWriteOperation mwo(wo);
@ -357,6 +360,11 @@ size_t JfrCheckpointManager::write_static_type_set(Thread* thread) {
size_t JfrCheckpointManager::write_threads(Thread* thread) {
assert(thread != NULL, "invariant");
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)thread);
ResetNoHandleMark rnhm;
ResourceMark rm(thread);
HandleMark hm(thread);
JfrCheckpointWriter writer(true, thread, THREADS);
JfrTypeManager::write_threads(writer);
return writer.used_size();
@ -364,8 +372,7 @@ size_t JfrCheckpointManager::write_threads(Thread* thread) {
size_t JfrCheckpointManager::write_static_type_set_and_threads() {
Thread* const thread = Thread::current();
ResourceMark rm(thread);
HandleMark hm(thread);
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread));
write_static_type_set(thread);
write_threads(thread);
return write();
@ -380,7 +387,11 @@ void JfrCheckpointManager::on_rotation() {
void JfrCheckpointManager::clear_type_set() {
assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
assert(!JfrRecorder::is_recording(), "invariant");
Thread* t = Thread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(t));
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)t);
ResetNoHandleMark rnhm;
MutexLocker cld_lock(ClassLoaderDataGraph_lock);
MutexLocker module_lock(Module_lock);
JfrTypeSet::clear();
@ -388,21 +399,23 @@ void JfrCheckpointManager::clear_type_set() {
void JfrCheckpointManager::write_type_set() {
assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
Thread* const thread = Thread::current();
if (LeakProfiler::is_running()) {
{
Thread* const thread = Thread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread));
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)thread);
ResetNoHandleMark rnhm;
MutexLocker cld_lock(thread, ClassLoaderDataGraph_lock);
MutexLocker module_lock(thread, Module_lock);
JfrCheckpointWriter leakp_writer(true, thread);
JfrCheckpointWriter writer(true, thread);
JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
ObjectSampleCheckpoint::on_type_set(leakp_writer);
} else {
// can safepoint here
MutexLocker cld_lock(ClassLoaderDataGraph_lock);
MutexLocker module_lock(Module_lock);
JfrCheckpointWriter writer(true, thread);
JfrTypeSet::serialize(&writer, NULL, false, false);
if (LeakProfiler::is_running()) {
JfrCheckpointWriter leakp_writer(true, thread);
JfrCheckpointWriter writer(true, thread);
JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
ObjectSampleCheckpoint::on_type_set(leakp_writer);
} else {
JfrCheckpointWriter writer(true, thread);
JfrTypeSet::serialize(&writer, NULL, false, false);
}
}
write();
}
@ -416,13 +429,33 @@ void JfrCheckpointManager::on_unloading_classes() {
}
}
class JavaThreadToVM : public StackObj {
private:
JavaThread* _jt;
public:
JavaThreadToVM(Thread* thread) : _jt(thread->is_Java_thread() ? (JavaThread*)thread : NULL) {
if (_jt != NULL) {
assert(_jt->thread_state() == _thread_in_native, "invariant");
_jt->set_thread_state(_thread_in_vm);
}
}
~JavaThreadToVM() {
if (_jt != NULL) {
_jt->set_thread_state(_thread_in_native);
}
}
};
size_t JfrCheckpointManager::flush_type_set() {
size_t elements = 0;
if (JfrTraceIdEpoch::has_changed_tag_state()) {
JfrCheckpointWriter writer(Thread::current());
// can safepoint here
MutexLocker cld_lock(ClassLoaderDataGraph_lock);
MutexLocker module_lock(Module_lock);
Thread* const t = Thread::current();
// can safepoint here (if JavaThread)
JavaThreadToVM transition(t);
ResetNoHandleMark rnhm;
MutexLocker cld_lock(t, ClassLoaderDataGraph_lock);
MutexLocker module_lock(t, Module_lock);
JfrCheckpointWriter writer(t);
elements = JfrTypeSet::serialize(&writer, NULL, false, true);
}
if (is_constant_pending()) {

@ -29,14 +29,18 @@
#include "oops/klass.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/thread.inline.hpp"
static jbyteArray metadata_blob = NULL;
static u8 metadata_id = 0;
static u8 last_metadata_id = 0;
static void write_metadata_blob(JfrChunkWriter& chunkwriter) {
static void write_metadata_blob(JfrChunkWriter& chunkwriter, Thread* thread) {
assert(chunkwriter.is_valid(), "invariant");
assert(thread != NULL, "invariant");
assert(metadata_blob != NULL, "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
const typeArrayOop arr = (typeArrayOop)JfrJavaSupport::resolve_non_null(metadata_blob);
assert(arr != NULL, "invariant");
const int length = arr->length();
@ -47,11 +51,15 @@ static void write_metadata_blob(JfrChunkWriter& chunkwriter) {
chunkwriter.write_unbuffered(data_address, length);
}
bool JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) {
void JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) {
assert(chunkwriter.is_valid(), "invariant");
if (last_metadata_id == metadata_id && chunkwriter.has_metadata()) {
return false;
return;
}
JavaThread* const jt = (JavaThread*)Thread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
// can safepoint here
ThreadInVMfromNative transition(jt);
// header
const int64_t metadata_offset = chunkwriter.reserve(sizeof(u4));
chunkwriter.write<u8>(EVENT_METADATA); // ID 0
@ -59,13 +67,12 @@ bool JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) {
chunkwriter.write(JfrTicks::now());
chunkwriter.write((u8)0); // duration
chunkwriter.write(metadata_id); // metadata id
write_metadata_blob(chunkwriter); // payload
write_metadata_blob(chunkwriter, jt); // payload
// fill in size of metadata descriptor event
const int64_t size_written = chunkwriter.current_offset() - metadata_offset;
chunkwriter.write_padded_at_offset((u4)size_written, metadata_offset);
chunkwriter.set_last_metadata_offset(metadata_offset);
last_metadata_id = metadata_id;
return true;
}
void JfrMetadataEvent::update(jbyteArray metadata) {

@ -36,7 +36,7 @@ class JfrChunkWriter;
//
class JfrMetadataEvent : AllStatic {
public:
static bool write(JfrChunkWriter& writer);
static void write(JfrChunkWriter& writer);
static void update(jbyteArray metadata);
};

@ -1038,6 +1038,7 @@ size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* l
* Clear all tags from the previous epoch.
*/
void JfrTypeSet::clear() {
ResourceMark rm;
JfrKlassUnloading::clear();
clear_artifacts = true;
setup(NULL, NULL, false, false);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, 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
@ -27,6 +27,7 @@
#include "jfr/recorder/repository/jfrChunkRotation.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
static jobject chunk_monitor = NULL;
static int64_t threshold = 0;
@ -53,6 +54,9 @@ static jobject get_chunk_monitor(Thread* thread) {
static void notify() {
Thread* const thread = Thread::current();
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)thread);
ResetNoHandleMark rnhm;
JfrJavaSupport::notify_all(get_chunk_monitor(thread), thread);
}

@ -33,6 +33,7 @@
#include "logging/log.hpp"
#include "runtime/atomic.hpp"
#include "runtime/globals.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "runtime/thread.inline.hpp"
@ -422,7 +423,7 @@ const char* JfrEmergencyDump::chunk_path(const char* repository_path) {
*/
static bool prepare_for_emergency_dump(Thread* thread) {
assert(thread != NULL, "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
if (thread->is_Watcher_thread()) {
// need WatcherThread as a safeguard against potential deadlocks
return false;
@ -501,29 +502,38 @@ static bool guard_reentrancy() {
return Atomic::cmpxchg(&jfr_shutdown_lock, 0, 1) == 0;
}
class JavaThreadInVM : public StackObj {
class JavaThreadInVMAndNative : public StackObj {
private:
JavaThread* const _jt;
JavaThreadState _original_state;
public:
JavaThreadInVM(Thread* t) : _jt(t->is_Java_thread() ? (JavaThread*)t : NULL),
_original_state(_thread_max_state) {
if ((_jt != NULL) && (_jt->thread_state() != _thread_in_vm)) {
JavaThreadInVMAndNative(Thread* t) : _jt(t->is_Java_thread() ? (JavaThread*)t : NULL),
_original_state(_thread_max_state) {
if (_jt != NULL) {
_original_state = _jt->thread_state();
_jt->set_thread_state(_thread_in_vm);
if (_original_state != _thread_in_vm) {
_jt->set_thread_state(_thread_in_vm);
}
}
}
~JavaThreadInVM() {
~JavaThreadInVMAndNative() {
if (_original_state != _thread_max_state) {
_jt->set_thread_state(_original_state);
}
}
void transition_to_native() {
if (_jt != NULL) {
assert(_jt->thread_state() == _thread_in_vm, "invariant");
_jt->set_thread_state(_thread_in_native);
}
}
};
static void post_events(bool exception_handler) {
static void post_events(bool exception_handler, Thread* thread) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
if (exception_handler) {
EventShutdown e;
e.set_reason("VM Error");
@ -547,11 +557,14 @@ void JfrEmergencyDump::on_vm_shutdown(bool exception_handler) {
return;
}
// Ensure a JavaThread is _thread_in_vm when we make this call
JavaThreadInVM jtivm(thread);
JavaThreadInVMAndNative jtivm(thread);
if (!prepare_for_emergency_dump(thread)) {
return;
}
post_events(exception_handler);
post_events(exception_handler, thread);
// if JavaThread, transition to _thread_in_native to issue a final flushpoint
NoHandleMark nhm;
jtivm.transition_to_native();
const int messages = MSGBIT(MSG_VM_ERROR);
JfrRecorderService service;
service.rotate(messages);

@ -45,9 +45,8 @@
#include "jfr/writers/jfrJavaEventWriter.hpp"
#include "jfr/utilities/jfrTypes.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "runtime/safepoint.hpp"
@ -373,8 +372,6 @@ static void stop() {
}
void JfrRecorderService::clear() {
ResourceMark rm;
HandleMark hm;
pre_safepoint_clear();
invoke_safepoint_clear();
post_safepoint_clear();
@ -388,6 +385,7 @@ void JfrRecorderService::pre_safepoint_clear() {
void JfrRecorderService::invoke_safepoint_clear() {
JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_clear> safepoint_task(*this);
ThreadInVMfromNative transition((JavaThread*)Thread::current());
VMThread::execute(&safepoint_task);
}
@ -474,6 +472,7 @@ void JfrRecorderService::vm_error_rotation() {
void JfrRecorderService::rotate(int msgs) {
assert(!JfrStream_lock->owned_by_self(), "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
if (msgs & MSGBIT(MSG_VM_ERROR)) {
// emergency dump
if (!prepare_for_vm_error_rotation()) {
@ -521,8 +520,6 @@ void JfrRecorderService::finalize_current_chunk() {
}
void JfrRecorderService::write() {
ResourceMark rm;
HandleMark hm;
pre_safepoint_write();
invoke_safepoint_write();
post_safepoint_write();
@ -547,6 +544,8 @@ void JfrRecorderService::pre_safepoint_write() {
void JfrRecorderService::invoke_safepoint_write() {
JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this);
// can safepoint here
ThreadInVMfromNative transition((JavaThread*)Thread::current());
VMThread::execute(&safepoint_task);
}
@ -632,8 +631,6 @@ void JfrRecorderService::invoke_flush() {
assert(JfrStream_lock->owned_by_self(), "invariant");
assert(_chunkwriter.is_valid(), "invariant");
Thread* const t = Thread::current();
ResourceMark rm(t);
HandleMark hm(t);
++flushpoint_id;
reset_thread_local_buffer(t);
FlushFunctor flushpoint(*this);
@ -644,6 +641,7 @@ void JfrRecorderService::invoke_flush() {
}
void JfrRecorderService::flushpoint() {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
MutexLocker lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
if (_chunkwriter.is_valid()) {
invoke_flush();
@ -651,11 +649,13 @@ void JfrRecorderService::flushpoint() {
}
void JfrRecorderService::process_full_buffers() {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
if (_chunkwriter.is_valid()) {
_storage.write_full();
}
}
void JfrRecorderService::evaluate_chunk_size_for_rotation() {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
JfrChunkRotation::evaluate(_chunkwriter);
}

@ -23,11 +23,15 @@
*/
#include "precompiled.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/service/jfrPostBox.hpp"
#include "jfr/recorder/service/jfrRecorderService.hpp"
#include "jfr/recorder/service/jfrRecorderThread.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "logging/log.hpp"
#include "runtime/handles.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.inline.hpp"
@ -59,18 +63,24 @@ void recorderthread_entry(JavaThread* thread, Thread* unused) {
}
msgs = post_box.collect();
JfrMsg_lock->unlock();
if (PROCESS_FULL_BUFFERS) {
service.process_full_buffers();
}
// Check amount of data written to chunk already
// if it warrants asking for a new chunk
service.evaluate_chunk_size_for_rotation();
if (START) {
service.start();
} else if (ROTATE) {
service.rotate(msgs);
} else if (FLUSHPOINT) {
service.flushpoint();
{
// Run as _thread_in_native as much a possible
// to minimize impact on safepoint synchronizations.
NoHandleMark nhm;
ThreadToNativeFromVM transition(thread);
if (PROCESS_FULL_BUFFERS) {
service.process_full_buffers();
}
// Check amount of data written to chunk already
// if it warrants asking for a new chunk.
service.evaluate_chunk_size_for_rotation();
if (START) {
service.start();
} else if (ROTATE) {
service.rotate(msgs);
} else if (FLUSHPOINT) {
service.flushpoint();
}
}
JfrMsg_lock->lock();
post_box.notify_waiters();

@ -65,11 +65,11 @@
*
* We say that the FIFO solution is "mostly" concurrent, in certain situations.
*
* Safe memory reclamation is based on a reference tracking scheme based on versions, implemented using JfrVersion.
* An access to the list is "version controlled", with clients checking out the latest version of the list.
* Destructive modifications made by clients, i.e. deletions, are committed to describe new versions of the list.
* Before reclamation, a client inspects the versioning system to ensure checkouts for versions strictly
* less than the version of the modification have all been relinquished. See utilities/JfrVersion.hpp.
* Safe memory reclamation is based on a reference tracking scheme based on versioning, implemented using JfrVersionSystem.
* An access to the list is "versioned", with clients checking out the latest version describing the list.
* Destructive modifications made by clients, i.e. deletions, are signalled by incrementing the version.
* Before reclamation, a client inspects JfrVersionSystem to ensure checkouts with versions strictly
* less than the version of the modification have been relinquished. See utilities/JfrVersionSystem.hpp.
*
* Insertions can only take place from one end of the list, head or tail, exclusively.
* Specializations, a.k.a clients, must ensure this requirement.

@ -222,7 +222,7 @@ typename Client::Node* JfrConcurrentLinkedListHost<Client, SearchPolicy, AllocPo
assert(is_marked_for_removal(successor->_next), "invariant");
// Now attempt to physically excise the successor node.
// If the cas fails, we can optimize for the slow path if we know we are not performing
// insertions from the head. Then a failed cas results not from new a node being inserted,
// insertions from the head. Then a failed cas results not from a new node being inserted,
// but only because another thread excised us already.
if (!cas(&predecessor->_next, successor, successor_next) && insert_is_head) {
// Physically excise using slow path, can be completed asynchronously by other threads.

@ -25,11 +25,9 @@
#ifndef SHARE_JFR_UTILITIES_JFRVERSIONSYSTEM_INLINE_HPP
#define SHARE_JFR_UTILITIES_JFRVERSIONSYSTEM_INLINE_HPP
#include "jfr/utilities/jfrSpinlockHelper.hpp"
#include "jfr/utilities/jfrVersionSystem.hpp"
#include "runtime/atomic.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/vm_version.hpp"
inline JfrVersionSystem::Node::Node() : _next(NULL), _version(0), _live(true) {}
@ -65,10 +63,6 @@ inline JfrVersionSystem::Type JfrVersionSystem::tip() const {
}
inline JfrVersionSystem::Type JfrVersionSystem::increment() {
if (!VM_Version::supports_cx8()) {
JfrSpinlockHelper lock(&_spinlock);
return ++_tip._value;
}
traceid cmp;
traceid xchg;
do {