< prev index next >
src/os/linux/vm/os_linux.cpp
Print this page
rev 12363 : 8169373: Work around linux NPTL stack guard error.
Summary: Also skip libc guard page for compiler thread, merge similar code on linux platforms, and streamline libc guard page handling on linuxs390, linuxppc, aixppc.
Reviewed-by: dholmes, dcubed, kvn
*** 721,735 ****
// init thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
! // calculate stack size if it's not specified by caller
size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size);
pthread_attr_setstacksize(&attr, stack_size);
! // glibc guard page
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
ThreadState state;
{
--- 721,742 ----
// init thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
! // Calculate stack size if it's not specified by caller.
size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size);
+ // In the Linux NPTL pthread implementation the guard size mechanism
+ // is not implemented properly. The posix standard requires adding
+ // the size of the guard pages to the stack size, instead Linux
+ // takes the space out of 'stacksize'. Thus we adapt the requested
+ // stack_size by the size of the guard pages to mimick proper
+ // behaviour.
+ stack_size = align_size_up(stack_size + os::Linux::default_guard_size(thr_type), vm_page_size());
pthread_attr_setstacksize(&attr, stack_size);
! // Configure glibc guard page.
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
ThreadState state;
{
*** 2838,2847 ****
--- 2845,2861 ----
}
}
return false;
}
+ size_t os::Linux::default_guard_size(os::ThreadType thr_type) {
+ // Creating guard page is very expensive. Java thread has HotSpot
+ // guard pages, only enable glibc guard page for non-Java threads.
+ // (Remember: compiler thread is a Java thread, too!)
+ return ((thr_type == java_thread || thr_type == compiler_thread) ? 0 : page_size());
+ }
+
// rebuild_cpu_to_node_map() constructs a table mapping cpud id to node id.
// The table is later used in get_node_by_cpu().
void os::Linux::rebuild_cpu_to_node_map() {
const size_t NCPUS = 32768; // Since the buffer size computation is very obscure
// in libnuma (possible values are starting from 16,
*** 6070,6079 ****
--- 6084,6188 ----
yes = false;
}
return yes;
}
+
+ // Java/Compiler thread:
+ //
+ // Low memory addresses
+ // P0 +------------------------+
+ // | |\ Java thread created by VM does not have glibc
+ // | glibc guard page | - guard page, attached Java thread usually has
+ // | |/ 1 glibc guard page.
+ // P1 +------------------------+ Thread::stack_base() - Thread::stack_size()
+ // | |\
+ // | HotSpot Guard Pages | - red, yellow and reserved pages
+ // | |/
+ // +------------------------+ JavaThread::stack_reserved_zone_base()
+ // | |\
+ // | Normal Stack | -
+ // | |/
+ // P2 +------------------------+ Thread::stack_base()
+ //
+ // Non-Java thread:
+ //
+ // Low memory addresses
+ // P0 +------------------------+
+ // | |\
+ // | glibc guard page | - usually 1 page
+ // | |/
+ // P1 +------------------------+ Thread::stack_base() - Thread::stack_size()
+ // | |\
+ // | Normal Stack | -
+ // | |/
+ // P2 +------------------------+ Thread::stack_base()
+ //
+ // ** P1 (aka bottom) and size (P2 = P1 - size) are the address and stack size
+ // returned from pthread_attr_getstack().
+ // ** Due to NPTL implementation error, linux takes the glibc guard page out
+ // of the stack size given in pthread_attr. We work around this for
+ // threads created by the VM. (We adapt bottom to be P1 and size accordingly.)
+ //
+ #ifndef ZERO
+ static void current_stack_region(address * bottom, size_t * size) {
+ if (os::Linux::is_initial_thread()) {
+ // initial thread needs special handling because pthread_getattr_np()
+ // may return bogus value.
+ *bottom = os::Linux::initial_thread_stack_bottom();
+ *size = os::Linux::initial_thread_stack_size();
+ } else {
+ pthread_attr_t attr;
+
+ int rslt = pthread_getattr_np(pthread_self(), &attr);
+
+ // JVM needs to know exact stack location, abort if it fails
+ if (rslt != 0) {
+ if (rslt == ENOMEM) {
+ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np");
+ } else {
+ fatal("pthread_getattr_np failed with error = %d", rslt);
+ }
+ }
+
+ if (pthread_attr_getstack(&attr, (void **)bottom, size) != 0) {
+ fatal("Cannot locate current stack attributes!");
+ }
+
+ // Work around NPTL stack guard error.
+ size_t guard_size = 0;
+ rslt = pthread_attr_getguardsize(&attr, &guard_size);
+ if (rslt != 0) {
+ fatal("pthread_attr_getguardsize failed with error = %d", rslt);
+ }
+ *bottom += guard_size;
+ *size -= guard_size;
+
+ pthread_attr_destroy(&attr);
+
+ }
+ assert(os::current_stack_pointer() >= *bottom &&
+ os::current_stack_pointer() < *bottom + *size, "just checking");
+ }
+
+ address os::current_stack_base() {
+ address bottom;
+ size_t size;
+ current_stack_region(&bottom, &size);
+ return (bottom + size);
+ }
+
+ size_t os::current_stack_size() {
+ // This stack size includes the usable stack and HotSpot guard pages
+ // (for the threads that have Hotspot guard pages).
+ address bottom;
+ size_t size;
+ current_stack_region(&bottom, &size);
+ return size;
+ }
+ #endif
+
static inline struct timespec get_mtime(const char* filename) {
struct stat st;
int ret = os::stat(filename, &st);
assert(ret == 0, "failed to stat() file '%s': %s", filename, strerror(errno));
return st.st_mtim;
< prev index next >