--- old/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp 2019-05-03 13:36:50.534310100 +0200 +++ new/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp 2019-05-03 13:36:49.233318400 +0200 @@ -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 @@ -136,6 +136,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"); } --- old/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp 2019-05-03 13:37:01.736232800 +0200 +++ new/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp 2019-05-03 13:37:00.397238200 +0200 @@ -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 @@ -136,6 +136,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"); @@ -153,10 +161,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) { @@ -183,7 +187,6 @@ set_concurrent_top(start()); } -// flags enum FLAG { RETIRED = 1, TRANSIENT = 2, --- old/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp 2019-05-03 13:37:12.702176100 +0200 +++ new/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp 2019-05-03 13:37:11.446181400 +0200 @@ -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 { --- old/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp 2019-05-03 13:37:23.588150300 +0200 +++ new/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp 2019-05-03 13:37:22.191129000 +0200 @@ -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; } --- old/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp 2019-05-03 13:37:34.457090700 +0200 +++ new/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp 2019-05-03 13:37:33.182101600 +0200 @@ -339,9 +339,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); @@ -376,8 +376,8 @@ } } assert(buffer->empty(), "invariant"); + assert(buffer->identity() != NULL, "invariant"); control().increment_dead(); - buffer->release(); buffer->set_retired(); } @@ -738,13 +738,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); } --- old/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp 2019-05-03 13:37:45.331026400 +0200 +++ new/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp 2019-05-03 13:37:43.995030500 +0200 @@ -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 : public 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 --- old/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp 2019-05-03 13:37:56.576976300 +0200 +++ new/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp 2019-05-03 13:37:55.188962600 +0200 @@ -26,6 +26,7 @@ #define SHARE_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"); --- old/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp 2019-05-03 13:38:07.582924700 +0200 +++ new/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp 2019-05-03 13:38:06.178907500 +0200 @@ -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 @@ -140,93 +140,76 @@ return current_epoch; } -class StringPoolWriteOp { +template