Skip to content

8341491: Reserve and commit memory operations should be protected by NMT lock #24084

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
10 changes: 10 additions & 0 deletions src/hotspot/share/runtime/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2197,6 +2197,11 @@ void os::commit_memory_or_exit(char* addr, size_t size, size_t alignment_hint,
MemTracker::record_virtual_memory_commit((address)addr, size, CALLER_PC);
}

// The scope of NmtVirtualMemoryLocker covers both pd_uncommit_memory and record_virtual_memory_uncommit because
// these operations must happen atomically to avoid races causing NMT to fall out os sync with the OS reality.
// We do not have the same lock protection for pd_commit_memory and record_virtual_memory_commit.
// We assume that there is some external synchronization that prevents a region from being uncommitted
// before it is finished being committed.
bool os::uncommit_memory(char* addr, size_t bytes, bool executable) {
assert_nonempty_range(addr, bytes);
bool res;
Expand All @@ -2219,6 +2224,11 @@ bool os::uncommit_memory(char* addr, size_t bytes, bool executable) {
return res;
}

// The scope of NmtVirtualMemoryLocker covers both pd_release_memory and record_virtual_memory_release because
// these operations must happen atomically to avoid races causing NMT to fall out os sync with the OS reality.
// We do not have the same lock protection for pd_reserve_memory and record_virtual_memory_reserve.
// We assume that there is some external synchronization that prevents a region from being released
// before it is finished being reserved.
bool os::release_memory(char* addr, size_t bytes) {
assert_nonempty_range(addr, bytes);
bool res;
Expand Down
68 changes: 68 additions & 0 deletions test/hotspot/gtest/runtime/test_os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "runtime/os.inline.hpp"
#include "runtime/thread.hpp"
#include "runtime/threads.hpp"
#include "testutils.hpp"
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
Expand Down Expand Up @@ -1113,3 +1114,70 @@ TEST_VM(os, free_without_uncommit) {
os::release_memory(base, size);
}
#endif

TEST_VM(os, commit_memory_or_exit) {
const size_t page_sz = os::vm_page_size();
const size_t size = 16 * page_sz;
const char* letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

char* base = os::reserve_memory(size, false, mtTest);
ASSERT_NOT_NULL(base);
os::commit_memory_or_exit(base, size, false, "Commit failed.");
strcpy(base, letters);
ASSERT_TRUE(os::uncommit_memory(base, size, false));
os::commit_memory_or_exit(base, size, page_sz, false, "Commit with alignment hint failed.");
strcpy(base, letters);
ASSERT_TRUE(os::uncommit_memory(base, size, false));
EXPECT_TRUE(os::release_memory(base, size));
}

#if !defined(_AIX)

TEST_VM(os, map_memory_to_file) {
const char* letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const size_t size = strlen(letters) +1;

int fd = os::open("map_memory_to_file.txt", O_RDWR | O_CREAT, 0666);
EXPECT_TRUE(fd > 0);
EXPECT_TRUE(os::write(fd, letters, size));

char* result = os::map_memory_to_file(size, fd, mtTest);
ASSERT_NOT_NULL(result);
EXPECT_EQ(strcmp(letters, result), 0);
EXPECT_TRUE(os::unmap_memory(result, size));
::close(fd);
}

TEST_VM(os, map_unmap_memory) {
const char* letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char* path = "map_unmap_memory.txt";
const size_t size = strlen(letters) + 1;
int fd = os::open(path, O_RDWR | O_CREAT, 0666);
EXPECT_TRUE(fd > 0);
EXPECT_TRUE(os::write(fd, letters, size));
::close(fd);

fd = os::open(path, O_RDONLY, 0666);
char* result = os::map_memory(fd, path, 0, nullptr, size, true, false, mtTest);
ASSERT_NOT_NULL(result);
EXPECT_EQ(strcmp(letters, result), 0);
EXPECT_TRUE(os::unmap_memory(result, size));
::close(fd);
}

TEST_VM(os, map_memory_to_file_aligned) {
const char* letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const size_t size = strlen(letters) + 1;

int fd = os::open("map_memory_to_file.txt", O_RDWR | O_CREAT, 0666);
EXPECT_TRUE(fd > 0);
EXPECT_TRUE(os::write(fd, letters, size));

char* result = os::map_memory_to_file_aligned(os::vm_allocation_granularity(), os::vm_allocation_granularity(), fd, mtTest);
ASSERT_NOT_NULL(result);
EXPECT_EQ(strcmp(letters, result), 0);
EXPECT_TRUE(os::unmap_memory(result, os::vm_allocation_granularity()));
::close(fd);
}

#endif // !defined(_AIX)