提交 c993be01 编写于 作者: A apetushkov

8220293: Deadlock in JFR string pool

Reviewed-by: rehn, egahlin
上级 f1429fec
/*
* 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_service_thread(const Thread* thread) {
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");
}
......
/*
* 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 @@ void JfrBuffer::clear_identity() {
_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 @@ static bool validate_this(const JfrBuffer* const t, size_t size) {
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 @@ void JfrBuffer::concurrent_move_and_reinitialize(JfrBuffer* const to, size_t siz
set_concurrent_top(start());
}
// flags
enum FLAG {
RETIRED = 1,
TRANSIENT = 2,
......
......@@ -57,7 +57,6 @@ class JfrBuffer {
u4 _size;
const u1* stable_top() const;
void clear_flags();
public:
JfrBuffer();
......@@ -150,6 +149,8 @@ class JfrBuffer {
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 @@ class JfrBuffer {
bool retired() const;
void set_retired();
void clear_retired();
debug_only(bool acquired_by_self() const;)
};
class JfrAgeNode : public JfrBuffer {
......
......@@ -346,19 +346,19 @@ inline void process_free_list(Processor& processor, Mspace* mspace, jfr_iter_dir
template <typename Mspace>
inline bool ReleaseOp<Mspace>::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;
}
......
......@@ -340,9 +340,9 @@ static bool full_buffer_registration(BufferPtr buffer, JfrStorageAgeMspace* age_
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 @@ void JfrStorage::release(BufferPtr buffer, Thread* thread) {
}
}
assert(buffer->empty(), "invariant");
assert(buffer->identity() != NULL, "invariant");
control().increment_dead();
buffer->release();
buffer->set_retired();
}
......@@ -733,13 +733,14 @@ public:
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);
}
......
......@@ -92,7 +92,6 @@ class ConcurrentWriteOpExcludeRetired : private ConcurrentWriteOp<Operation> {
size_t processed() const { return ConcurrentWriteOp<Operation>::processed(); }
};
template <typename Operation>
class MutexedWriteOp {
private:
......@@ -104,6 +103,15 @@ class MutexedWriteOp {
size_t processed() const { return _operation.processed(); }
};
template <typename Operation>
class ExclusiveOp : private MutexedWriteOp<Operation> {
public:
typedef typename Operation::Type Type;
ExclusiveOp(Operation& operation) : MutexedWriteOp<Operation>(operation) {}
bool process(Type* t);
size_t processed() const { return MutexedWriteOp<Operation>::processed(); }
};
enum jfr_operation_mode {
mutexed = 1,
concurrent
......
......@@ -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 <typename T>
inline bool UnBufferedWriteToChunk<T>::write(T* t, const u1* data, size_t size) {
......@@ -75,6 +76,28 @@ inline bool MutexedWriteOp<Operation>::process(typename Operation::Type* t) {
return result;
}
template <typename Type>
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 <typename Operation>
inline bool ExclusiveOp<Operation>::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<Operation>::process(t);
}
template <typename Operation>
inline bool DiscardOp<Operation>::process(typename Operation::Type* t) {
assert(t != NULL, "invariant");
......
/*
* 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 @@ bool JfrStringPool::add(bool epoch, jlong id, jstring string, JavaThread* jt) {
return current_epoch;
}
class StringPoolWriteOp {
template <template <typename> class Operation>
class StringPoolOp {
public:
typedef JfrStringPoolBuffer Type;
private:
UnBufferedWriteToChunk<Type> _writer;
Operation<Type> _op;
Thread* _thread;
size_t _strings_processed;
public:
StringPoolWriteOp(JfrChunkWriter& writer, Thread* thread) : _writer(writer), _thread(thread), _strings_processed(0) {}
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) {
buffer->acquire(_thread); // blocking
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;
const bool ret = _writer.write(buffer, data, size);
buffer->release();
return ret;
return _op.write(buffer, data, size);
}
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();
}
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 MutexedWriteOp<WriteOperation> MutexedWriteOperation;
typedef StringPoolOp<UnBufferedWriteToChunk> WriteOperation;
typedef StringPoolOp<StringPoolDiscarderStub> DiscardOperation;
typedef ExclusiveOp<WriteOperation> ExclusiveWriteOperation;
typedef ExclusiveOp<DiscardOperation> ExclusiveDiscardOperation;
typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation;
typedef CompositeOperation<MutexedWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation;
typedef CompositeOperation<ExclusiveWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation;
typedef CompositeOperation<ExclusiveDiscardOperation, StringPoolReleaseOperation> StringPoolDiscardOperation;
size_t JfrStringPool::write_at_safepoint() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
size_t JfrStringPool::write() {
Thread* const thread = Thread::current();
WriteOperation wo(_chunkwriter, thread);
MutexedWriteOperation mwo(wo);
ExclusiveWriteOperation ewo(wo);
StringPoolReleaseOperation spro(_free_list_mspace, thread, false);
StringPoolWriteOperation spwo(&mwo, &spro);
StringPoolWriteOperation spwo(&ewo, &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::write_at_safepoint() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
return write();
}
size_t JfrStringPool::clear() {
StringPoolBufferDiscarder discard_operation;
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(discard_operation, _free_list_mspace);
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");
}
......
/*
* 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
......@@ -29,11 +29,9 @@ JfrStringPoolBuffer::JfrStringPoolBuffer() : JfrBuffer(), _string_count_pos(0),
void JfrStringPoolBuffer::reinitialize() {
assert(acquired_by_self() || retired(), "invariant");
concurrent_top();
set_pos((start()));
set_string_pos(0);
set_string_top(0);
set_concurrent_top(start());
JfrBuffer::reinitialize();
}
uint64_t JfrStringPoolBuffer::string_pos() const {
......@@ -57,7 +55,7 @@ void JfrStringPoolBuffer::set_string_pos(uint64_t value) {
}
void JfrStringPoolBuffer::increment(uint64_t value) {
assert(acquired_by_self() || retired(), "invariant");
assert(acquired_by_self(), "invariant");
++_string_count_pos;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
新手
引导
客服 返回
顶部