8191369: NMT: Enhance thread stack tracking

More precise thread stack tracking on Linux and Windows

Reviewed-by: coleenp, adinn, minqi
This commit is contained in:
Zhengyu Gu 2018-03-01 16:35:36 -05:00
parent d7765d9002
commit 354249f51e
8 changed files with 209 additions and 28 deletions

View file

@ -3053,10 +3053,12 @@ bool os::pd_uncommit_memory(char* addr, size_t size) {
return res != (uintptr_t) MAP_FAILED;
}
static address get_stack_commited_bottom(address bottom, size_t size) {
address nbot = bottom;
address ntop = bottom + size;
// If there is no page mapped/committed, top (bottom + size) is returned
static address get_stack_mapped_bottom(address bottom,
size_t size,
bool committed_only /* must have backing pages */) {
// address used to test if the page is mapped/committed
address test_addr = bottom + size;
size_t page_sz = os::vm_page_size();
unsigned pages = size / page_sz;
@ -3068,39 +3070,40 @@ static address get_stack_commited_bottom(address bottom, size_t size) {
while (imin < imax) {
imid = (imax + imin) / 2;
nbot = ntop - (imid * page_sz);
test_addr = bottom + (imid * page_sz);
// Use a trick with mincore to check whether the page is mapped or not.
// mincore sets vec to 1 if page resides in memory and to 0 if page
// is swapped output but if page we are asking for is unmapped
// it returns -1,ENOMEM
mincore_return_value = mincore(nbot, page_sz, vec);
mincore_return_value = mincore(test_addr, page_sz, vec);
if (mincore_return_value == -1) {
// Page is not mapped go up
// to find first mapped page
if (errno != EAGAIN) {
assert(errno == ENOMEM, "Unexpected mincore errno");
imax = imid;
if (mincore_return_value == -1 || (committed_only && (vec[0] & 0x01) == 0)) {
// Page is not mapped/committed go up
// to find first mapped/committed page
if ((mincore_return_value == -1 && errno != EAGAIN)
|| (committed_only && (vec[0] & 0x01) == 0)) {
assert(mincore_return_value != -1 || errno == ENOMEM, "Unexpected mincore errno");
imin = imid + 1;
}
} else {
// Page is mapped go down
// to find first not mapped page
imin = imid + 1;
// mapped/committed, go down
imax= imid;
}
}
nbot = nbot + page_sz;
// Adjust stack bottom one page up if last checked page is not mapped/committed
if (mincore_return_value == -1 || (committed_only && (vec[0] & 0x01) == 0)) {
assert(mincore_return_value != -1 || (errno != EAGAIN && errno != ENOMEM),
"Should not get to here");
// Adjust stack bottom one page up if last checked page is not mapped
if (mincore_return_value == -1) {
nbot = nbot + page_sz;
test_addr = test_addr + page_sz;
}
return nbot;
return test_addr;
}
// Linux uses a growable mapping for the stack, and if the mapping for
// the stack guard pages is not removed when we detach a thread the
// stack cannot grow beyond the pages where the stack guard was
@ -3137,9 +3140,9 @@ bool os::pd_create_stack_guard_pages(char* addr, size_t size) {
if (mincore((address)stack_extent, os::vm_page_size(), vec) == -1) {
// Fallback to slow path on all errors, including EAGAIN
stack_extent = (uintptr_t) get_stack_commited_bottom(
os::Linux::initial_thread_stack_bottom(),
(size_t)addr - stack_extent);
stack_extent = (uintptr_t) get_stack_mapped_bottom(os::Linux::initial_thread_stack_bottom(),
(size_t)addr - stack_extent,
false /* committed_only */);
}
if (stack_extent < (uintptr_t)addr) {
@ -3166,6 +3169,11 @@ bool os::remove_stack_guard_pages(char* addr, size_t size) {
return os::uncommit_memory(addr, size);
}
size_t os::committed_stack_size(address bottom, size_t size) {
address bot = get_stack_mapped_bottom(bottom, size, true /* committed_only */);
return size_t(bottom + size - bot);
}
// If 'fixed' is true, anon_mmap() will attempt to reserve anonymous memory
// at 'requested_addr'. If there are existing memory mappings at the same
// location, however, they will be overwritten. If 'fixed' is false,