Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions src/hotspot/share/memory/arena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,26 @@
// It is used very early in the vm initialization, in allocation
// code and other areas. For many calls, the current thread has not
// been created so we cannot use Mutex.
static PlatformMutex* GlobalChunkPoolMutex = nullptr;
static DeferredStatic<PlatformMutex> GlobalChunkPoolMutex;

void Arena::initialize_chunk_pool() {
GlobalChunkPoolMutex = new PlatformMutex();
GlobalChunkPoolMutex.initialize();
}

ChunkPoolLocker::ChunkPoolLocker() {
assert(GlobalChunkPoolMutex != nullptr, "must be initialized");
GlobalChunkPoolMutex->lock();
ChunkPoolLocker::ChunkPoolLocker(LockStrategy ls) {
if (ls == LockStrategy::Lock) {
GlobalChunkPoolMutex->lock();
_locked = true;
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible enhancement: explicitly check for Try and then ShouldNotReachHere in the else case. I'm not sure if this is necessary for a bandaid fix like this, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose I could add it. The enum only has two choices so it seems like overkill though.

assert(ls == LockStrategy::Try, "must be");
_locked = GlobalChunkPoolMutex->try_lock();
}
};

ChunkPoolLocker::~ChunkPoolLocker() {
GlobalChunkPoolMutex->unlock();
if (_locked) {
GlobalChunkPoolMutex->unlock();
}
};

// Pre-defined default chunk sizes must be arena-aligned, see Chunk::operator new()
Expand Down
5 changes: 4 additions & 1 deletion src/hotspot/share/memory/arena.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
#define ARENA_ALIGN(x) (align_up((x), ARENA_AMALLOC_ALIGNMENT))

class ChunkPoolLocker : public StackObj {
bool _locked;
public:
ChunkPoolLocker();
enum class LockStrategy { Lock, Try };

ChunkPoolLocker(LockStrategy ls = LockStrategy::Lock);
~ChunkPoolLocker();
};

Expand Down
6 changes: 5 additions & 1 deletion src/hotspot/share/nmt/mallocTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ void MallocMemorySnapshot::copy_to(MallocMemorySnapshot* s) {
// Use lock to make sure that mtChunks don't get deallocated while the
// copy is going on, because their size is adjusted using this
// buffer in make_adjustment().
ChunkPoolLocker lock;
ChunkPoolLocker::LockStrategy ls = ChunkPoolLocker::LockStrategy::Lock;
if (VMError::is_error_reported() && VMError::is_error_reported_in_current_thread()) {
ls = ChunkPoolLocker::LockStrategy::Try;
}
Comment on lines +68 to +71
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking more, we could simply always do this check in the constructor and do away with the "strategy" flag altogether. Arguably this would be reasonable behaviour for every Mutexlocker (though it may slow things down a little).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a version that did this but Johan was worried about global behavior so wanted to limit it to just NMT reporting on error to be safe.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. Worth having a discussion whether all "lockers" should adopt this error reporting behaviour.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah. Not sure about that for this lock or in general. Right now it's ad-hoc.

ChunkPoolLocker cpl(ls);
s->_all_mallocs = _all_mallocs;
size_t total_size = 0;
size_t total_count = 0;
Expand Down
7 changes: 6 additions & 1 deletion src/hotspot/share/nmt/nmtUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "nmt/nmtUsage.hpp"
#include "nmt/threadStackTracker.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/vmError.hpp"

// Enabled all options for snapshot.
const NMTUsageOptions NMTUsage::OptionsAll = { true, true, true };
Expand Down Expand Up @@ -58,7 +59,11 @@ void NMTUsage::update_malloc_usage() {
// Lock needed to keep values in sync, total area size
// is deducted from mtChunk in the end to give correct values.
{
ChunkPoolLocker lock;
ChunkPoolLocker::LockStrategy ls = ChunkPoolLocker::LockStrategy::Lock;
if (VMError::is_error_reported() && VMError::is_error_reported_in_current_thread()) {
ls = ChunkPoolLocker::LockStrategy::Try;
}
ChunkPoolLocker cpl(ls);
ms = MallocMemorySummary::as_snapshot();
}

Expand Down
16 changes: 16 additions & 0 deletions test/hotspot/gtest/nmt/test_nmt_buffer_overflow_detection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

#include "memory/allocation.hpp"
#include "memory/arena.hpp"
#include "nmt/memTracker.hpp"
#include "runtime/os.hpp"
#include "sanitizers/address.hpp"
Expand Down Expand Up @@ -142,6 +143,21 @@ DEFINE_TEST(test_corruption_on_realloc_growing, COMMON_NMT_HEAP_CORRUPTION_MESSA
static void test_corruption_on_realloc_shrinking() { test_corruption_on_realloc(0x11, 0x10); }
DEFINE_TEST(test_corruption_on_realloc_shrinking, COMMON_NMT_HEAP_CORRUPTION_MESSAGE_PREFIX);

static void test_chunkpool_lock() {
if (!MemTracker::enabled()) {
tty->print_cr("Skipped");
return;
}
PrintNMTStatistics = true;
{
ChunkPoolLocker cpl;
char* mem = (char*)os::malloc(100, mtTest);
memset(mem - 16, 0, 100 + 16 + 2);
os::free(mem);
}
}
DEFINE_TEST(test_chunkpool_lock, COMMON_NMT_HEAP_CORRUPTION_MESSAGE_PREFIX);

///////

// realloc is the trickiest of the bunch. Test that realloc works and correctly takes over
Expand Down