--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Tue May 21 13:06:52 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Tue May 21 20:53:27 2019 +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");
}
--- a/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp Tue May 21 13:06:52 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp Tue May 21 20:53:27 2019 +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,
--- a/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp Tue May 21 13:06:52 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp Tue May 21 20:53:27 2019 +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 {
--- a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp Tue May 21 13:06:52 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp Tue May 21 20:53:27 2019 +0200
@@ -346,19 +346,19 @@
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;
}
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp Tue May 21 13:06:52 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp Tue May 21 20:53:27 2019 +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);
}
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp Tue May 21 13:06:52 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp Tue May 21 20:53:27 2019 +0200
@@ -92,7 +92,6 @@
size_t processed() const { return ConcurrentWriteOp<Operation>::processed(); }
};
-
template <typename Operation>
class MutexedWriteOp {
private:
@@ -104,6 +103,15 @@
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
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp Tue May 21 13:06:52 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.inline.hpp Tue May 21 20:53:27 2019 +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 <typename T>
inline bool UnBufferedWriteToChunk<T>::write(T* t, const u1* data, size_t size) {
@@ -75,6 +76,28 @@
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");
--- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp Tue May 21 13:06:52 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp Tue May 21 20:53:27 2019 +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 <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;
+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);
- 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);
+ 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");
}
--- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.cpp Tue May 21 13:06:52 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.cpp Tue May 21 20:53:27 2019 +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
@@ -29,11 +29,9 @@
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::increment(uint64_t value) {
- assert(acquired_by_self() || retired(), "invariant");
+ assert(acquired_by_self(), "invariant");
++_string_count_pos;
}