Skip to content

Commit 48997f5

Browse files
author
Markus Grönlund
committed
8326715: ZGC: RunThese24H fails with ExitCode 139 during shutdown
Reviewed-by: egahlin Backport-of: cdf22b1
1 parent 4e3bfc9 commit 48997f5

11 files changed

+312
-163
lines changed

src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp

Lines changed: 36 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
3737
#include "jfr/recorder/service/jfrOptionSet.hpp"
3838
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
39+
#include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp"
3940
#include "jfr/support/jfrKlassUnloading.hpp"
4041
#include "jfr/support/jfrMethodLookup.hpp"
4142
#include "jfr/utilities/jfrHashtable.hpp"
@@ -272,11 +273,30 @@ static void install_stack_traces(const ObjectSampler* sampler) {
272273
iterate_samples(installer);
273274
}
274275

276+
// Resets the blob write states from the previous epoch.
277+
static void reset_blob_write_state(const ObjectSampler* sampler, JavaThread* jt) {
278+
assert(sampler != nullptr, "invariant");
279+
const ObjectSample* sample = sampler->last_resolved();
280+
while (sample != nullptr) {
281+
if (sample->has_stacktrace()) {
282+
sample->stacktrace()->reset_write_state();
283+
}
284+
if (sample->has_thread()) {
285+
sample->thread()->reset_write_state();
286+
}
287+
if (sample->has_type_set()) {
288+
sample->type_set()->reset_write_state();
289+
}
290+
sample = sample->next();
291+
}
292+
}
293+
275294
void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler) {
276295
assert(sampler != nullptr, "invariant");
277296
assert(LeakProfiler::is_running(), "invariant");
278297
JavaThread* const thread = JavaThread::current();
279298
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread);)
299+
reset_blob_write_state(sampler, thread);
280300
if (!ObjectSampler::has_unresolved_entry()) {
281301
return;
282302
}
@@ -326,57 +346,49 @@ void ObjectSampleCheckpoint::write_stacktrace(const JfrStackTrace* trace, JfrChe
326346
}
327347
}
328348

329-
static void write_blob(const JfrBlobHandle& blob, JfrCheckpointWriter& writer, bool reset) {
330-
if (reset) {
331-
blob->reset_write_state();
332-
return;
333-
}
349+
static void write_blob(const JfrBlobHandle& blob, JfrCheckpointWriter& writer) {
334350
blob->exclusive_write(writer);
335351
}
336352

337-
static void write_type_set_blob(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
353+
static void write_type_set_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) {
338354
if (sample->has_type_set()) {
339-
write_blob(sample->type_set(), writer, reset);
355+
write_blob(sample->type_set(), writer);
340356
}
341357
}
342358

343-
static void write_thread_blob(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
359+
static void write_thread_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) {
344360
assert(sample->has_thread(), "invariant");
345361
if (sample->is_virtual_thread() || has_thread_exited(sample->thread_id())) {
346-
write_blob(sample->thread(), writer, reset);
362+
write_blob(sample->thread(), writer);
347363
}
348364
}
349365

350-
static void write_stacktrace_blob(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
366+
static void write_stacktrace_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) {
351367
if (sample->has_stacktrace()) {
352-
write_blob(sample->stacktrace(), writer, reset);
368+
write_blob(sample->stacktrace(), writer);
353369
}
354370
}
355371

356-
static void write_blobs(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
372+
static void write_blobs(const ObjectSample* sample, JfrCheckpointWriter& writer) {
357373
assert(sample != nullptr, "invariant");
358-
write_stacktrace_blob(sample, writer, reset);
359-
write_thread_blob(sample, writer, reset);
360-
write_type_set_blob(sample, writer, reset);
374+
write_stacktrace_blob(sample, writer);
375+
write_thread_blob(sample, writer);
376+
write_type_set_blob(sample, writer);
361377
}
362378

363379
class BlobWriter {
364380
private:
365381
const ObjectSampler* _sampler;
366382
JfrCheckpointWriter& _writer;
367383
const jlong _last_sweep;
368-
bool _reset;
369384
public:
370385
BlobWriter(const ObjectSampler* sampler, JfrCheckpointWriter& writer, jlong last_sweep) :
371-
_sampler(sampler), _writer(writer), _last_sweep(last_sweep), _reset(false) {}
386+
_sampler(sampler), _writer(writer), _last_sweep(last_sweep) {}
372387
void sample_do(ObjectSample* sample) {
373388
if (sample->is_alive_and_older_than(_last_sweep)) {
374-
write_blobs(sample, _writer, _reset);
389+
write_blobs(sample, _writer);
375390
}
376391
}
377-
void set_reset() {
378-
_reset = true;
379-
}
380392
};
381393

382394
static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thread* thread) {
@@ -385,9 +397,6 @@ static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thre
385397
JfrCheckpointWriter writer(thread, false);
386398
BlobWriter cbw(sampler, writer, last_sweep);
387399
iterate_samples(cbw, true);
388-
// reset blob write states
389-
cbw.set_reset();
390-
iterate_samples(cbw, true);
391400
}
392401

393402
void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) {
@@ -403,67 +412,17 @@ void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge
403412
}
404413
}
405414

406-
// A linked list of saved type set blobs for the epoch.
407-
// The link consist of a reference counted handle.
408-
static JfrBlobHandle saved_type_set_blobs;
409-
410-
static void release_state_for_previous_epoch() {
411-
// decrements the reference count and the list is reinitialized
412-
saved_type_set_blobs = JfrBlobHandle();
413-
}
414-
415-
class BlobInstaller {
416-
public:
417-
~BlobInstaller() {
418-
release_state_for_previous_epoch();
419-
}
420-
void sample_do(ObjectSample* sample) {
421-
if (!sample->is_dead()) {
422-
sample->set_type_set(saved_type_set_blobs);
423-
}
424-
}
425-
};
426-
427-
static void install_type_set_blobs() {
428-
if (saved_type_set_blobs.valid()) {
429-
BlobInstaller installer;
430-
iterate_samples(installer);
431-
}
432-
}
433-
434-
static void save_type_set_blob(JfrCheckpointWriter& writer) {
435-
assert(writer.has_data(), "invariant");
436-
const JfrBlobHandle blob = writer.copy();
437-
if (saved_type_set_blobs.valid()) {
438-
saved_type_set_blobs->set_next(blob);
439-
} else {
440-
saved_type_set_blobs = blob;
441-
}
442-
}
443-
444415
// This routine has exclusive access to the sampler instance on entry.
445-
void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
416+
void ObjectSampleCheckpoint::on_type_set(JavaThread* jt) {
446417
assert(LeakProfiler::is_running(), "invariant");
447418
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(JavaThread::current());)
448419
assert(ClassLoaderDataGraph_lock->owned_by_self(), "invariant");
449420
if (!ObjectSampler::has_unresolved_entry()) {
450421
return;
451422
}
452-
const ObjectSample* const last = ObjectSampler::sampler()->last();
423+
ObjectSample* const last = ObjectSampler::sampler()->last();
453424
assert(last != nullptr, "invariant");
454425
assert(last != ObjectSampler::sampler()->last_resolved(), "invariant");
455-
if (writer.has_data()) {
456-
save_type_set_blob(writer);
457-
}
458-
install_type_set_blobs();
426+
JfrReferenceCountedStorage::install(last, ObjectSampler::sampler()->last_resolved());
459427
ObjectSampler::sampler()->set_last_resolved(last);
460428
}
461-
462-
// This routine does NOT have exclusive access to the sampler instance on entry.
463-
void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) {
464-
assert(LeakProfiler::is_running(), "invariant");
465-
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
466-
if (writer.has_data() && ObjectSampler::has_unresolved_entry()) {
467-
save_type_set_blob(writer);
468-
}
469-
}

src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2024, 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
@@ -50,8 +50,7 @@ class ObjectSampleCheckpoint : AllStatic {
5050
static void write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread);
5151
static void clear();
5252
public:
53-
static void on_type_set(JfrCheckpointWriter& writer);
54-
static void on_type_set_unload(JfrCheckpointWriter& writer);
53+
static void on_type_set(JavaThread* jt);
5554
static void on_thread_exit(traceid tid);
5655
static void on_rotation(const ObjectSampler* sampler);
5756
};

src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2024, 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
@@ -233,7 +233,7 @@ class ObjectSample : public JfrCHeapObj {
233233
return _type_set.valid();
234234
}
235235

236-
void set_type_set(const JfrBlobHandle& ref) {
236+
void install_type_set(const JfrBlobHandle& ref) {
237237
if (_type_set != ref) {
238238
if (_type_set.valid()) {
239239
_type_set->set_next(ref);

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

Lines changed: 14 additions & 14 deletions
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, 2024, 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
@@ -37,6 +37,7 @@
3737
#include "jfr/recorder/service/jfrOptionSet.hpp"
3838
#include "jfr/recorder/storage/jfrEpochStorage.inline.hpp"
3939
#include "jfr/recorder/storage/jfrMemorySpace.inline.hpp"
40+
#include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp"
4041
#include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
4142
#include "jfr/recorder/stringpool/jfrStringPool.hpp"
4243
#include "jfr/support/jfrDeprecationManager.hpp"
@@ -589,12 +590,14 @@ void JfrCheckpointManager::clear_type_set() {
589590
MutexLocker module_lock(Module_lock);
590591
JfrTypeSet::clear(&writer, &leakp_writer);
591592
}
592-
JfrDeprecationManager::on_type_set(leakp_writer, nullptr, thread);
593-
// We placed a blob in the Deprecated subsystem by moving the information
594-
// from the leakp writer. For the real writer, the data will not be
595-
// committed, because the JFR system is yet to be started.
596-
// Therefore, the writer is cancelled before its destructor is run,
597-
// to avoid writing unnecessary information into the checkpoint system.
593+
JfrAddRefCountedBlob add_blob(leakp_writer);
594+
JfrDeprecationManager::on_type_set(nullptr, thread);
595+
// We installed a blob in the JfrReferenceCountedStorage subsystem
596+
// by moving the information from the leakp writer.
597+
// For the real writer, the data will not be committed,
598+
// because the JFR system is yet to be started.
599+
// Therefore, we cancel the writer before its destructor is run
600+
// to avoid writing invalid information into the checkpoint system.
598601
writer.cancel();
599602
}
600603

@@ -613,11 +616,11 @@ void JfrCheckpointManager::write_type_set() {
613616
MutexLocker module_lock(thread, Module_lock);
614617
JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
615618
}
619+
JfrAddRefCountedBlob add_blob(leakp_writer);
616620
if (LeakProfiler::is_running()) {
617-
ObjectSampleCheckpoint::on_type_set(leakp_writer);
621+
ObjectSampleCheckpoint::on_type_set(thread);
618622
}
619-
// Place this call after ObjectSampleCheckpoint::on_type_set.
620-
JfrDeprecationManager::on_type_set(leakp_writer, _chunkwriter, thread);
623+
JfrDeprecationManager::on_type_set(_chunkwriter, thread);
621624
}
622625
write();
623626
}
@@ -626,10 +629,7 @@ void JfrCheckpointManager::on_unloading_classes() {
626629
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
627630
JfrCheckpointWriter writer(Thread::current());
628631
JfrTypeSet::on_unloading_classes(&writer);
629-
if (LeakProfiler::is_running()) {
630-
ObjectSampleCheckpoint::on_type_set_unload(writer);
631-
}
632-
JfrDeprecationManager::on_type_set_unload(writer);
632+
JfrAddRefCountedBlob add_blob(writer, false /* move */, false /* reset */);
633633
}
634634

635635
static size_t flush_type_set(Thread* thread) {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ struct JfrCheckpointContext {
5454
};
5555

5656
class JfrCheckpointWriter : public JfrCheckpointWriterBase {
57+
friend class JfrAddRefCountedBlob;
5758
friend class JfrCheckpointManager;
5859
friend class JfrDeprecationManager;
5960
friend class JfrSerializerRegistration;
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#include "precompiled.hpp"
26+
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
27+
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
28+
#include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp"
29+
#include "jfr/support/jfrDeprecationManager.hpp"
30+
31+
// Currently only two subsystems use type set blobs. Save a blob only if either has an unresolved entry.
32+
static inline bool save_blob_predicate() {
33+
return JfrDeprecationManager::has_unresolved_entry() || ObjectSampler::has_unresolved_entry();
34+
}
35+
36+
JfrAddRefCountedBlob::JfrAddRefCountedBlob(JfrCheckpointWriter& writer, bool move /* true */, bool reset /* true */) : _reset(reset) {
37+
if (writer.has_data()) {
38+
if (save_blob_predicate()) {
39+
JfrReferenceCountedStorage::save_blob(writer, move);
40+
} else if (move) {
41+
writer.cancel();
42+
}
43+
}
44+
DEBUG_ONLY(if (reset) JfrReferenceCountedStorage::set_scope();)
45+
}
46+
47+
JfrAddRefCountedBlob::~JfrAddRefCountedBlob() {
48+
if (_reset) {
49+
JfrReferenceCountedStorage::reset();
50+
}
51+
}
52+
53+
JfrBlobHandle JfrReferenceCountedStorage::_type_sets = JfrBlobHandle();
54+
DEBUG_ONLY(bool JfrReferenceCountedStorage::_scope = false;)
55+
56+
void JfrReferenceCountedStorage::save_blob(JfrCheckpointWriter& writer, bool move /* false */) {
57+
assert(writer.has_data(), "invariant");
58+
const JfrBlobHandle blob = move ? writer.move() : writer.copy();
59+
if (_type_sets.valid()) {
60+
_type_sets->set_next(blob);
61+
return;
62+
}
63+
_type_sets = blob;
64+
}
65+
66+
void JfrReferenceCountedStorage::reset() {
67+
assert(_scope, "invariant");
68+
if (_type_sets.valid()) {
69+
_type_sets = JfrBlobHandle();
70+
}
71+
DEBUG_ONLY(_scope = false;)
72+
}
73+
74+
#ifdef ASSERT
75+
void JfrReferenceCountedStorage::set_scope() {
76+
assert(!_scope, "invariant");
77+
_scope = true;
78+
}
79+
#endif

0 commit comments

Comments
 (0)