< 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 >