< prev index next >

src/share/vm/jfr/recorder/stringpool/jfrStringPool.cpp

Print this page
rev 9053 : 8220293: Deadlock in JFR string pool
Reviewed-by: rehn, egahlin

*** 1,7 **** /* ! * Copyright (c) 2016, 2018, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. --- 1,7 ---- /* ! * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.
*** 137,233 **** writer.inc_nof_strings(); } return current_epoch; } ! class StringPoolWriteOp { public: typedef JfrStringPoolBuffer Type; private: ! UnBufferedWriteToChunk<Type> _writer; Thread* _thread; size_t _strings_processed; public: ! StringPoolWriteOp(JfrChunkWriter& writer, Thread* thread) : _writer(writer), _thread(thread), _strings_processed(0) {} bool write(Type* buffer, const u1* data, size_t size) { ! buffer->acquire(_thread); // blocking const uint64_t nof_strings_used = buffer->string_count(); assert(nof_strings_used > 0, "invariant"); buffer->set_string_top(buffer->string_top() + nof_strings_used); // "size processed" for string pool buffers is the number of processed string elements _strings_processed += nof_strings_used; ! const bool ret = _writer.write(buffer, data, size); ! buffer->release(); ! return ret; } size_t processed() { return _strings_processed; } }; ! typedef StringPoolWriteOp WriteOperation; ! typedef ConcurrentWriteOp<WriteOperation> ConcurrentWriteOperation; ! ! size_t JfrStringPool::write() { ! Thread* const thread = Thread::current(); ! WriteOperation wo(_chunkwriter, thread); ! ConcurrentWriteOperation cwo(wo); ! assert(_free_list_mspace->is_full_empty(), "invariant"); ! process_free_list(cwo, _free_list_mspace); ! return wo.processed(); ! } ! typedef MutexedWriteOp<WriteOperation> MutexedWriteOperation; typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation; ! typedef CompositeOperation<MutexedWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation; ! size_t JfrStringPool::write_at_safepoint() { ! assert(SafepointSynchronize::is_at_safepoint(), "invariant"); Thread* const thread = Thread::current(); WriteOperation wo(_chunkwriter, thread); ! MutexedWriteOperation mwo(wo); StringPoolReleaseOperation spro(_free_list_mspace, thread, false); ! StringPoolWriteOperation spwo(&mwo, &spro); assert(_free_list_mspace->is_full_empty(), "invariant"); process_free_list(spwo, _free_list_mspace); return wo.processed(); } ! class StringPoolBufferDiscarder { ! private: ! Thread* _thread; ! size_t _processed; ! public: ! typedef JfrStringPoolBuffer Type; ! StringPoolBufferDiscarder() : _thread(Thread::current()), _processed(0) {} ! bool process(Type* buffer) { ! buffer->acquire(_thread); // serialized access ! const u1* const current_top = buffer->top(); ! const size_t unflushed_size = buffer->pos() - current_top; ! if (unflushed_size == 0) { ! assert(buffer->string_count() == 0, "invariant"); ! buffer->release(); ! return true; ! } ! buffer->set_top(current_top + unflushed_size); ! const uint64_t nof_strings_used = buffer->string_count(); ! buffer->set_string_top(buffer->string_top() + nof_strings_used); ! // "size processed" for string pool buffers is the number of string elements ! _processed += (size_t)nof_strings_used; ! buffer->release(); ! return true; ! } ! size_t processed() const { return _processed; } ! }; size_t JfrStringPool::clear() { ! StringPoolBufferDiscarder discard_operation; assert(_free_list_mspace->is_full_empty(), "invariant"); ! process_free_list(discard_operation, _free_list_mspace); return discard_operation.processed(); } void JfrStringPool::register_full(BufferPtr t, Thread* thread) { // nothing here at the moment assert(t->retired(), "invariant"); } void JfrStringPool::lock() { assert(!_lock->owned_by_self(), "invariant"); --- 137,216 ---- writer.inc_nof_strings(); } return current_epoch; } ! template <template <typename> class Operation> ! class StringPoolOp { public: typedef JfrStringPoolBuffer Type; private: ! Operation<Type> _op; Thread* _thread; size_t _strings_processed; public: ! StringPoolOp() : _op(), _thread(Thread::current()), _strings_processed(0) {} ! StringPoolOp(JfrChunkWriter& writer, Thread* thread) : _op(writer), _thread(thread), _strings_processed(0) {} bool write(Type* buffer, const u1* data, size_t size) { ! assert(buffer->acquired_by(_thread) || buffer->retired(), "invariant"); const uint64_t nof_strings_used = buffer->string_count(); assert(nof_strings_used > 0, "invariant"); buffer->set_string_top(buffer->string_top() + nof_strings_used); // "size processed" for string pool buffers is the number of processed string elements _strings_processed += nof_strings_used; ! return _op.write(buffer, data, size); } size_t processed() { return _strings_processed; } }; ! template <typename Type> ! class StringPoolDiscarderStub { ! public: ! bool write(Type* buffer, const u1* data, size_t size) { ! // stub only, discard happens at higher level ! return true; ! } ! }; ! typedef StringPoolOp<UnBufferedWriteToChunk> WriteOperation; ! typedef StringPoolOp<StringPoolDiscarderStub> DiscardOperation; ! typedef ExclusiveOp<WriteOperation> ExclusiveWriteOperation; ! typedef ExclusiveOp<DiscardOperation> ExclusiveDiscardOperation; typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation; ! typedef CompositeOperation<ExclusiveWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation; ! typedef CompositeOperation<ExclusiveDiscardOperation, StringPoolReleaseOperation> StringPoolDiscardOperation; ! size_t JfrStringPool::write() { Thread* const thread = Thread::current(); WriteOperation wo(_chunkwriter, thread); ! ExclusiveWriteOperation ewo(wo); StringPoolReleaseOperation spro(_free_list_mspace, thread, false); ! StringPoolWriteOperation spwo(&ewo, &spro); assert(_free_list_mspace->is_full_empty(), "invariant"); process_free_list(spwo, _free_list_mspace); return wo.processed(); } ! size_t JfrStringPool::write_at_safepoint() { ! assert(SafepointSynchronize::is_at_safepoint(), "invariant"); ! return write(); ! } size_t JfrStringPool::clear() { ! DiscardOperation discard_operation; ! ExclusiveDiscardOperation edo(discard_operation); ! StringPoolReleaseOperation spro(_free_list_mspace, Thread::current(), false); ! StringPoolDiscardOperation spdo(&edo, &spro); assert(_free_list_mspace->is_full_empty(), "invariant"); ! process_free_list(spdo, _free_list_mspace); return discard_operation.processed(); } void JfrStringPool::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"); } void JfrStringPool::lock() { assert(!_lock->owned_by_self(), "invariant");
< prev index next >