Linux current_stack_region()
Gary Benson
gbenson at redhat.com
Mon Mar 10 08:06:35 PDT 2008
Hi all,
Recently I've been investigating some stack-related failures on ppc,
and trying to figure out how to make the stack region code work on
ia64.
The first thing I discovered is that the current linux code is wrong
when there are guard pages. The comment above current_stack_region
in os_linux_{i486,amd64,x86}.cpp puts the guard page outside the
region reported by pthread_attr_getstack(), which is not the case.
It needs to use pthread_attr_getguardsize() and trim that many bytes
from the bottom of the region reported by pthread_attr_getstack().
I started modifying current_stack_region to do just that, but its
comments contain warnings that pthread_getattr_np() returns bogus
values for initial threads. os::Linux::capture_initial_stack()
has more such warnings, though neither mentions exactly _what_ was
bogus. Does anyone know? Without a working pthread_getattr_np()
you can't use pthread_attr_getguardsize(), and without that it's
not possible to implement current_stack_region() in the form it's
currently defined.
I spoke with our glibc maintainer and he assured me that
pthread_getattr_np() returns good values for all threads, albeit more
slowly for the initial thread. I rewrote current_stack_region() to
use it.
I attached what I wrote. Does it look ok?
Cheers,
Gary
--
http://gbenson.net/
-------------- next part --------------
static void current_stack_region(address *bottom, size_t *size)
{
pthread_attr_t attr;
int res = pthread_getattr_np(pthread_self(), &attr);
if (res != 0) {
if (res == ENOMEM) {
vm_exit_out_of_memory(0, "pthread_getattr_np");
}
else {
fatal1("pthread_getattr_np failed with errno = %d", res);
}
}
address stack_bottom;
size_t stack_bytes;
res = pthread_attr_getstack(&attr, (void **) &stack_bottom, &stack_bytes);
if (res != 0) {
fatal1("pthread_attr_getstack failed with errno = %d", res);
}
address stack_top = stack_bottom + stack_bytes;
// The block of memory returned by pthread_attr_getstack() includes
// guard pages where present. We need to trim these off.
size_t page_bytes = os::Linux::page_size();
assert(((intptr_t) stack_bottom & (page_bytes - 1)) == 0, "unaligned stack");
size_t guard_bytes;
res = pthread_attr_getguardsize(&attr, &guard_bytes);
if (res != 0) {
fatal1("pthread_attr_getguardsize failed with errno = %d", res);
}
int guard_pages = align_size_up(guard_bytes, page_bytes) / page_bytes;
assert(guard_bytes == guard_pages * page_bytes, "unaligned guard");
#ifdef IA64
// IA64 has two stacks sharing the same area of memory, a normal
// stack growing downwards and a register stack growing upwards.
// Guard pages, if present, are in the centre. This code splits
// the stack in two even without guard pages, though in theory
// there's nothing to stop us allocating more to the normal stack
// or more to the register stack if one or the other were found
// to grow faster.
int total_pages = align_size_down(stack_bytes, page_bytes) / page_bytes;
stack_bottom += (total_pages - guard_pages) / 2 * page_bytes;
#endif // IA64
stack_bottom += guard_bytes;
pthread_attr_destroy(&attr);
// The initial thread has a growable stack, and the size reported
// by pthread_attr_getstack is the maximum size it could possibly
// be given what currently mapped. This can be huge, so we cap it.
if (os::Linux::is_initial_thread()) {
stack_bytes = stack_top - stack_bottom;
if (stack_bytes > JavaThread::stack_size_at_create())
stack_bytes = JavaThread::stack_size_at_create();
stack_bottom = stack_top - stack_bytes;
}
assert(os::current_stack_pointer() >= stack_bottom, "should do");
assert(os::current_stack_pointer() < stack_top, "should do");
*bottom = stack_bottom;
*size = stack_top - stack_bottom;
}
More information about the hotspot-dev
mailing list