Skip to content

Commit d207ed3

Browse files
author
Markus Grönlund
committed
8352066: JVM.commit() and JVM.flush() exhibit race conditions against JFR epochs
Reviewed-by: egahlin
1 parent 0450ba9 commit d207ed3

File tree

8 files changed

+23
-56
lines changed

8 files changed

+23
-56
lines changed

src/hotspot/share/jfr/jni/jfrJniMethod.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,13 +300,13 @@ JVM_ENTRY_NO_ENV(jobject, jfr_new_event_writer(JNIEnv* env, jclass jvm))
300300
return JfrJavaEventWriter::new_event_writer(thread);
301301
JVM_END
302302

303-
NO_TRANSITION(void, jfr_event_writer_flush(JNIEnv* env, jclass jvm, jobject writer, jint used_size, jint requested_size))
304-
JfrJavaEventWriter::flush(writer, used_size, requested_size, JavaThread::current());
305-
NO_TRANSITION_END
303+
JVM_ENTRY_NO_ENV(void, jfr_event_writer_flush(JNIEnv* env, jclass jvm, jobject writer, jint used_size, jint requested_size))
304+
JfrJavaEventWriter::flush(writer, used_size, requested_size, thread);
305+
JVM_END
306306

307-
NO_TRANSITION(jlong, jfr_commit(JNIEnv* env, jclass jvm, jlong next_position))
308-
return JfrJavaEventWriter::commit(next_position);
309-
NO_TRANSITION_END
307+
JVM_ENTRY_NO_ENV(jlong, jfr_commit(JNIEnv* env, jclass jvm, jlong next_position))
308+
return JfrJavaEventWriter::commit(next_position, thread);
309+
JVM_END
310310

311311
JVM_ENTRY_NO_ENV(void, jfr_flush(JNIEnv* env, jclass jvm))
312312
JfrRepository::flush(thread);

src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it

src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ void JfrRecorderService::safepoint_clear() {
486486
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
487487
_checkpoint_manager.begin_epoch_shift();
488488
_storage.clear();
489+
_checkpoint_manager.notify_threads();
489490
_chunkwriter.set_time_stamp();
490491
JfrDeprecationManager::on_safepoint_clear();
491492
JfrStackTraceRepository::clear();
@@ -650,9 +651,7 @@ size_t JfrRecorderService::flush() {
650651
if (_string_pool.is_modified()) {
651652
total_elements += flush_stringpool(_string_pool, _chunkwriter);
652653
}
653-
if (_stack_trace_repository.is_modified()) {
654-
total_elements += flush_stacktrace(_stack_trace_repository, _chunkwriter);
655-
}
654+
total_elements += flush_stacktrace(_stack_trace_repository, _chunkwriter);
656655
return flush_typeset(_checkpoint_manager, _chunkwriter) + total_elements;
657656
}
658657

src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,9 @@ void JfrStackTraceRepository::destroy() {
9292
_leak_profiler_instance = nullptr;
9393
}
9494

95-
bool JfrStackTraceRepository::is_modified() const {
96-
return _last_entries != _entries;
97-
}
98-
9995
size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) {
10096
MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
101-
if (_entries == 0) {
97+
if ((_entries == _last_entries) && !clear) {
10298
return 0;
10399
}
104100
int count = 0;

src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -56,7 +56,6 @@ class JfrStackTraceRepository : public JfrCHeapObj {
5656
static void destroy();
5757
bool initialize();
5858

59-
bool is_modified() const;
6059
static size_t clear();
6160
static size_t clear(JfrStackTraceRepository& repo);
6261
size_t write(JfrChunkWriter& cw, bool clear);

src/hotspot/share/jfr/support/jfrIntrinsics.cpp

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,35 +37,14 @@ static void assert_precondition(JavaThread* jt) {
3737
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_java(jt);)
3838
assert(jt->has_last_Java_frame(), "invariant");
3939
}
40-
41-
static void assert_epoch_identity(JavaThread* jt, u2 current_epoch) {
42-
assert_precondition(jt);
43-
// Verify the epoch updates got written through also to the vthread object.
44-
const u2 epoch_raw = ThreadIdAccess::epoch(jt->vthread());
45-
const bool excluded = epoch_raw & excluded_bit;
46-
assert(!excluded, "invariant");
47-
assert(!JfrThreadLocal::is_excluded(jt), "invariant");
48-
const u2 vthread_epoch = epoch_raw & epoch_mask;
49-
assert(vthread_epoch == current_epoch, "invariant");
50-
}
51-
#endif // ASSERT
40+
#endif
5241

5342
void* JfrIntrinsicSupport::write_checkpoint(JavaThread* jt) {
5443
DEBUG_ONLY(assert_precondition(jt);)
5544
assert(JfrThreadLocal::is_vthread(jt), "invariant");
56-
const u2 vthread_thread_local_epoch = JfrThreadLocal::vthread_epoch(jt);
57-
const u2 current_epoch = ThreadIdAccess::current_epoch();
58-
MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt));
59-
if (vthread_thread_local_epoch == current_epoch) {
60-
// After the epoch test in the intrinsic, the thread sampler interleaved
61-
// and suspended the thread. As part of taking a sample, it updated
62-
// the vthread object and the thread local "for us". We are good.
63-
DEBUG_ONLY(assert_epoch_identity(jt, current_epoch);)
64-
ThreadInVMfromJava transition(jt);
65-
return JfrJavaEventWriter::event_writer(jt);
66-
}
6745
const traceid vthread_tid = JfrThreadLocal::vthread_id(jt);
68-
// Transition before reading the epoch generation anew, now as _thread_in_vm. Can safepoint here.
46+
// Transition before reading the epoch generation, now as _thread_in_vm.
47+
MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt));
6948
ThreadInVMfromJava transition(jt);
7049
JfrThreadLocal::set_vthread_epoch(jt, vthread_tid, ThreadIdAccess::current_epoch());
7150
return JfrJavaEventWriter::event_writer(jt);
@@ -74,12 +53,11 @@ void* JfrIntrinsicSupport::write_checkpoint(JavaThread* jt) {
7453
void* JfrIntrinsicSupport::return_lease(JavaThread* jt) {
7554
DEBUG_ONLY(assert_precondition(jt);)
7655
MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt));
77-
ThreadStateTransition::transition_from_java(jt, _thread_in_native);
56+
ThreadInVMfromJava transition(jt);
7857
assert(jt->jfr_thread_local()->has_java_event_writer(), "invariant");
7958
assert(jt->jfr_thread_local()->shelved_buffer() != nullptr, "invariant");
8059
JfrJavaEventWriter::flush(jt->jfr_thread_local()->java_event_writer(), 0, 0, jt);
8160
assert(jt->jfr_thread_local()->shelved_buffer() == nullptr, "invariant");
82-
ThreadStateTransition::transition_from_native(jt, _thread_in_Java);
8361
return nullptr;
8462
}
8563

src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ bool JfrJavaEventWriter::initialize() {
118118
}
119119

120120
void JfrJavaEventWriter::flush(jobject writer, jint used, jint requested, JavaThread* jt) {
121-
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
121+
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
122122
assert(writer != nullptr, "invariant");
123123
JfrBuffer* const current = jt->jfr_thread_local()->java_buffer();
124124
assert(current != nullptr, "invariant");
@@ -130,9 +130,6 @@ void JfrJavaEventWriter::flush(jobject writer, jint used, jint requested, JavaTh
130130
const bool is_valid = buffer->free_size() >= (size_t)(used + requested);
131131
u1* const new_current_position = is_valid ? buffer->pos() + used : buffer->pos();
132132
assert(start_pos_offset != invalid_offset, "invariant");
133-
// can safepoint here
134-
MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt));
135-
ThreadInVMfromNative transition(jt);
136133
oop const w = JNIHandles::resolve_non_null(writer);
137134
assert(w != nullptr, "invariant");
138135
w->long_field_put(start_pos_offset, (jlong)buffer->pos());
@@ -147,11 +144,10 @@ void JfrJavaEventWriter::flush(jobject writer, jint used, jint requested, JavaTh
147144
}
148145
}
149146

150-
jlong JfrJavaEventWriter::commit(jlong next_position) {
147+
jlong JfrJavaEventWriter::commit(jlong next_position, JavaThread* jt) {
151148
assert(next_position != 0, "invariant");
152-
JavaThread* const jt = JavaThread::current();
153149
assert(jt != nullptr, "invariant");
154-
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
150+
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
155151
JfrThreadLocal* const tl = jt->jfr_thread_local();
156152
assert(tl != nullptr, "invariant");
157153
assert(tl->has_java_event_writer(), "invariant");
@@ -167,12 +163,11 @@ jlong JfrJavaEventWriter::commit(jlong next_position) {
167163
}
168164
// set_pos() has release semantics
169165
current->set_pos(next);
170-
if (!current->lease()) {
171-
return next_position;
166+
if (current->lease()) {
167+
flush(tl->java_event_writer(), 0, 0, jt);
168+
return 0; // signals that the buffer lease was returned.
172169
}
173-
assert(current->lease(), "invariant");
174-
flush(tl->java_event_writer(), 0, 0, jt);
175-
return 0; // signals that the buffer lease was returned.
170+
return next_position;
176171
}
177172

178173
class JfrJavaEventWriterNotificationClosure : public ThreadClosure {

src/hotspot/share/jfr/writers/jfrJavaEventWriter.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class JfrJavaEventWriter : AllStatic {
5050
static jobject event_writer(JavaThread* t);
5151
static jobject new_event_writer(TRAPS);
5252
static void flush(jobject writer, jint used, jint requested, JavaThread* jt);
53-
static jlong commit(jlong next_position);
53+
static jlong commit(jlong next_position, JavaThread* jt);
5454
};
5555

5656
#endif // SHARE_JFR_WRITERS_JFRJAVAEVENTWRITER_HPP

0 commit comments

Comments
 (0)