# HG changeset patch # User apetushkov # Date 1592383385 -10800 # Node ID d2c2cd90513e48822648ff16016aa76577eb7ab1 # Parent b273df69fbfe590b91909972f5cd7262f733646b 8220293: Deadlock in JFR string pool Reviewed-by: rehn, egahlin diff -r b273df69fbfe -r d2c2cd90513e src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp --- a/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Mon Jun 15 20:21:56 2020 +0100 +++ b/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Wed Jun 17 11:43:05 2020 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -135,6 +135,8 @@ void JfrCheckpointManager::register_full(BufferPtr t, Thread* thread) { // nothing here at the moment + assert(t != NULL, "invariant"); + assert(t->acquired_by(thread), "invariant"); assert(t->retired(), "invariant"); } diff -r b273df69fbfe -r d2c2cd90513e src/share/vm/jfr/recorder/storage/jfrBuffer.cpp --- a/src/share/vm/jfr/recorder/storage/jfrBuffer.cpp Mon Jun 15 20:21:56 2020 +0100 +++ b/src/share/vm/jfr/recorder/storage/jfrBuffer.cpp Wed Jun 17 11:43:05 2020 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, 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 @@ -137,6 +137,14 @@ _identity = NULL; } +bool JfrBuffer::acquired_by(const void* id) const { + return identity() == id; +} + +bool JfrBuffer::acquired_by_self() const { + return acquired_by(Thread::current()); +} + #ifdef ASSERT static bool validate_to(const JfrBuffer* const to, size_t size) { assert(to != NULL, "invariant"); @@ -154,10 +162,6 @@ assert(t->top() + size <= t->pos(), "invariant"); return true; } - -bool JfrBuffer::acquired_by_self() const { - return identity() == Thread::current(); -} #endif // ASSERT void JfrBuffer::move(JfrBuffer* const to, size_t size) { @@ -184,7 +188,6 @@ set_concurrent_top(start()); } -// flags enum FLAG { RETIRED = 1, TRANSIENT = 2, diff -r b273df69fbfe -r d2c2cd90513e src/share/vm/jfr/recorder/storage/jfrBuffer.hpp --- a/src/share/vm/jfr/recorder/storage/jfrBuffer.hpp Mon Jun 15 20:21:56 2020 +0100 +++ b/src/share/vm/jfr/recorder/storage/jfrBuffer.hpp Wed Jun 17 11:43:05 2020 +0300 @@ -57,7 +57,6 @@ u4 _size; const u1* stable_top() const; - void clear_flags(); public: JfrBuffer(); @@ -150,6 +149,8 @@ void acquire(const void* id); bool try_acquire(const void* id); + bool acquired_by(const void* id) const; + bool acquired_by_self() const; void release(); void move(JfrBuffer* const to, size_t size); @@ -166,8 +167,6 @@ bool retired() const; void set_retired(); void clear_retired(); - - debug_only(bool acquired_by_self() const;) }; class JfrAgeNode : public JfrBuffer { diff -r b273df69fbfe -r d2c2cd90513e src/share/vm/jfr/recorder/storage/jfrMemorySpace.inline.hpp --- a/src/share/vm/jfr/recorder/storage/jfrMemorySpace.inline.hpp Mon Jun 15 20:21:56 2020 +0100 +++ b/src/share/vm/jfr/recorder/storage/jfrMemorySpace.inline.hpp Wed Jun 17 11:43:05 2020 +0300 @@ -346,19 +346,19 @@ template inline bool ReleaseOp::process(typename Mspace::Type* t) { assert(t != NULL, "invariant"); - if (t->retired() || t->try_acquire(_thread)) { - if (t->transient()) { - if (_release_full) { - mspace_release_full_critical(t, _mspace); - } else { - mspace_release_free_critical(t, _mspace); - } - return true; + // assumes some means of exclusive access to t + if (t->transient()) { + if (_release_full) { + mspace_release_full_critical(t, _mspace); + } else { + mspace_release_free_critical(t, _mspace); } - t->reinitialize(); - assert(t->empty(), "invariant"); - t->release(); // publish + return true; } + t->reinitialize(); + assert(t->empty(), "invariant"); + assert(!t->retired(), "invariant"); + t->release(); // publish return true; } diff -r b273df69fbfe -r d2c2cd90513e src/share/vm/jfr/recorder/storage/jfrStorage.cpp --- a/src/share/vm/jfr/recorder/storage/jfrStorage.cpp Mon Jun 15 20:21:56 2020 +0100 +++ b/src/share/vm/jfr/recorder/storage/jfrStorage.cpp Wed Jun 17 11:43:05 2020 +0300 @@ -340,9 +340,9 @@ void JfrStorage::register_full(BufferPtr buffer, Thread* thread) { assert(buffer != NULL, "invariant"); assert(buffer->retired(), "invariant"); + assert(buffer->acquired_by(thread), "invariant"); if (!full_buffer_registration(buffer, _age_mspace, control(), thread)) { handle_registration_failure(buffer); - buffer->release(); } if (control().should_post_buffer_full_message()) { _post_box.post(MSG_FULLBUFFER); @@ -377,8 +377,8 @@ } } assert(buffer->empty(), "invariant"); + assert(buffer->identity() != NULL, "invariant"); control().increment_dead(); - buffer->release(); buffer->set_retired(); } @@ -733,13 +733,14 @@ Scavenger(JfrStorageControl& control, Mspace* mspace) : _control(control), _mspace(mspace), _count(0), _amount(0) {} bool process(Type* t) { if (t->retired()) { + assert(t->identity() != NULL, "invariant"); + assert(t->empty(), "invariant"); assert(!t->transient(), "invariant"); assert(!t->lease(), "invariant"); - assert(t->empty(), "invariant"); - assert(t->identity() == NULL, "invariant"); ++_count; _amount += t->total_size(); t->clear_retired(); + t->release(); _control.decrement_dead(); mspace_release_full_critical(t, _mspace); } diff -r b273df69fbfe -r d2c2cd90513e src/share/vm/jfr/recorder/storage/jfrStorageUtils.hpp --- a/src/share/vm/jfr/recorder/storage/jfrStorageUtils.hpp Mon Jun 15 20:21:56 2020 +0100 +++ b/src/share/vm/jfr/recorder/storage/jfrStorageUtils.hpp Wed Jun 17 11:43:05 2020 +0300 @@ -92,7 +92,6 @@ size_t processed() const { return ConcurrentWriteOp::processed(); } }; - template class MutexedWriteOp { private: @@ -104,6 +103,15 @@ size_t processed() const { return _operation.processed(); } }; +template +class ExclusiveOp : private MutexedWriteOp { + public: + typedef typename Operation::Type Type; + ExclusiveOp(Operation& operation) : MutexedWriteOp(operation) {} + bool process(Type* t); + size_t processed() const { return MutexedWriteOp::processed(); } +}; + enum jfr_operation_mode { mutexed = 1, concurrent diff -r b273df69fbfe -r d2c2cd90513e src/share/vm/jfr/recorder/storage/jfrStorageUtils.inline.hpp --- a/src/share/vm/jfr/recorder/storage/jfrStorageUtils.inline.hpp Mon Jun 15 20:21:56 2020 +0100 +++ b/src/share/vm/jfr/recorder/storage/jfrStorageUtils.inline.hpp Wed Jun 17 11:43:05 2020 +0300 @@ -26,6 +26,7 @@ #define SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP #include "jfr/recorder/storage/jfrStorageUtils.hpp" +#include "runtime/thread.inline.hpp" template inline bool UnBufferedWriteToChunk::write(T* t, const u1* data, size_t size) { @@ -75,6 +76,28 @@ return result; } +template +static void retired_sensitive_acquire(Type* t) { + assert(t != NULL, "invariant"); + if (t->retired()) { + return; + } + Thread* const thread = Thread::current(); + while (!t->try_acquire(thread)) { + if (t->retired()) { + return; + } + } +} + +template +inline bool ExclusiveOp::process(typename Operation::Type* t) { + retired_sensitive_acquire(t); + assert(t->acquired_by_self() || t->retired(), "invariant"); + // User is required to ensure proper release of the acquisition + return MutexedWriteOp::process(t); +} + template inline bool DiscardOp::process(typename Operation::Type* t) { assert(t != NULL, "invariant"); diff -r b273df69fbfe -r d2c2cd90513e src/share/vm/jfr/recorder/stringpool/jfrStringPool.cpp --- a/src/share/vm/jfr/recorder/stringpool/jfrStringPool.cpp Mon Jun 15 20:21:56 2020 +0100 +++ b/src/share/vm/jfr/recorder/stringpool/jfrStringPool.cpp Wed Jun 17 11:43:05 2020 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -139,93 +139,76 @@ return current_epoch; } -class StringPoolWriteOp { +template