--- a/hotspot/src/os/linux/vm/os_linux.cpp Mon Dec 12 21:56:45 2016 -0800
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Tue Nov 08 16:30:36 2016 +0100
@@ -716,11 +716,18 @@
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- // calculate stack size if it's not specified by caller
+ // 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);
- // glibc guard page
+ // Configure glibc guard page.
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
ThreadState state;
@@ -2833,6 +2840,13 @@
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() {
@@ -6065,6 +6079,101 @@
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);