8182984: [aix] Make stack traces independent on successful vm initialization
authorstuefe
Wed, 28 Jun 2017 16:12:54 +0200
changeset 46576 0b817584e8a9
parent 46575 d6fb8a7a7843
child 46579 5940af25f37e
child 46580 130fde4acb34
8182984: [aix] Make stack traces independent on successful vm initialization Reviewed-by: simonis, mdoerr, clanger
hotspot/src/os/aix/vm/os_aix.cpp
hotspot/src/os/aix/vm/porting_aix.cpp
hotspot/src/os/aix/vm/porting_aix.hpp
--- a/hotspot/src/os/aix/vm/os_aix.cpp	Wed Jun 28 14:15:56 2017 +0200
+++ b/hotspot/src/os/aix/vm/os_aix.cpp	Wed Jun 28 16:12:54 2017 +0200
@@ -130,8 +130,6 @@
 #define ERROR_MP_VMGETINFO_FAILED                    102
 #define ERROR_MP_VMGETINFO_CLAIMS_NO_SUPPORT_FOR_64K 103
 
-// Query dimensions of the stack of the calling thread.
-static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size);
 static address resolve_function_descriptor_to_code_pointer(address p);
 
 static void vmembk_print_on(outputStream* os);
@@ -764,11 +762,8 @@
   // find out my own stack dimensions
   {
     // actually, this should do exactly the same as thread->record_stack_base_and_size...
-    address base = 0;
-    size_t size = 0;
-    query_stack_dimensions(&base, &size);
-    thread->set_stack_base(base);
-    thread->set_stack_size(size);
+    thread->set_stack_base(os::current_stack_base());
+    thread->set_stack_size(os::current_stack_size());
   }
 
   const pthread_t pthread_id = ::pthread_self();
@@ -4297,91 +4292,28 @@
 /////////////////////////////////////////////////////////////////////////////
 // thread stack
 
-// Function to query the current stack size using pthread_getthrds_np.
-static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size) {
-
-  // Information about this api can be found (a) in the pthread.h header and
-  // (b) in http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/pthread_getthrds_np.htm
-  //
-  // The use of this API to find out the current stack is kind of undefined.
-  // But after a lot of tries and asking IBM about it, I concluded that it is safe
-  // enough for cases where I let the pthread library create its stacks. For cases
-  // where I create an own stack and pass this to pthread_create, it seems not to
-  // work (the returned stack size in that case is 0).
-
-  pthread_t tid = pthread_self();
-  struct __pthrdsinfo pinfo;
-  char dummy[1]; // Just needed to satisfy pthread_getthrds_np.
-  int dummy_size = sizeof(dummy);
-
-  memset(&pinfo, 0, sizeof(pinfo));
-
-  const int rc = pthread_getthrds_np(&tid, PTHRDSINFO_QUERY_ALL, &pinfo,
-                                     sizeof(pinfo), dummy, &dummy_size);
-
-  if (rc != 0) {
-    trcVerbose("pthread_getthrds_np failed (%d)", rc);
-    return false;
-  }
-  guarantee0(pinfo.__pi_stackend);
-
-  // The following may happen when invoking pthread_getthrds_np on a pthread
-  // running on a user provided stack (when handing down a stack to pthread
-  // create, see pthread_attr_setstackaddr).
-  // Not sure what to do then.
-
-  guarantee0(pinfo.__pi_stacksize);
-
-  // Note: we get three values from pthread_getthrds_np:
-  //       __pi_stackaddr, __pi_stacksize, __pi_stackend
-  //
-  // high addr    ---------------------
-  //
-  //    |         pthread internal data, like ~2K
-  //    |
-  //    |         ---------------------   __pi_stackend   (usually not page aligned, (xxxxF890))
-  //    |
-  //    |
-  //    |
-  //    |
-  //    |
-  //    |
-  //    |          ---------------------   (__pi_stackend - __pi_stacksize)
-  //    |
-  //    |          padding to align the following AIX guard pages, if enabled.
-  //    |
-  //    V          ---------------------   __pi_stackaddr
-  //
-  // low addr      AIX guard pages, if enabled (AIXTHREAD_GUARDPAGES > 0)
-  //
-
-  address stack_base = (address)(pinfo.__pi_stackend);
-  address stack_low_addr = (address)align_ptr_up(pinfo.__pi_stackaddr,
-    os::vm_page_size());
-  size_t stack_size = stack_base - stack_low_addr;
-
-  if (p_stack_base) {
-    *p_stack_base = stack_base;
-  }
-
-  if (p_stack_size) {
-    *p_stack_size = stack_size;
-  }
-
-  return true;
-}
-
 // Get the current stack base from the OS (actually, the pthread library).
+// Note: usually not page aligned.
 address os::current_stack_base() {
-  address p;
-  query_stack_dimensions(&p, 0);
-  return p;
+  AixMisc::stackbounds_t bounds;
+  bool rc = AixMisc::query_stack_bounds_for_current_thread(&bounds);
+  guarantee(rc, "Unable to retrieve stack bounds.");
+  return bounds.base;
 }
 
 // Get the current stack size from the OS (actually, the pthread library).
+// Returned size is such that (base - size) is always aligned to page size.
 size_t os::current_stack_size() {
-  size_t s;
-  query_stack_dimensions(0, &s);
+  AixMisc::stackbounds_t bounds;
+  bool rc = AixMisc::query_stack_bounds_for_current_thread(&bounds);
+  guarantee(rc, "Unable to retrieve stack bounds.");
+  // Align the returned stack size such that the stack low address
+  // is aligned to page size (Note: base is usually not and we do not care).
+  // We need to do this because caller code will assume stack low address is
+  // page aligned and will place guard pages without checking.
+  address low = bounds.base - bounds.size;
+  address low_aligned = (address)align_ptr_up(low, os::vm_page_size());
+  size_t s = bounds.base - low_aligned;
   return s;
 }
 
--- a/hotspot/src/os/aix/vm/porting_aix.cpp	Wed Jun 28 14:15:56 2017 +0200
+++ b/hotspot/src/os/aix/vm/porting_aix.cpp	Wed Jun 28 16:12:54 2017 +0200
@@ -35,6 +35,7 @@
 
 #include <demangle.h>
 #include <sys/debug.h>
+#include <pthread.h>
 #include <ucontext.h>
 
 //////////////////////////////////
@@ -680,13 +681,14 @@
   // retrieve it from the OS.
   stackptr_t stack_base = NULL;
   size_t stack_size = NULL;
-  Thread* const thread = Thread::current_or_null_safe();
-  if (thread) {
-    stack_base = (stackptr_t) thread->stack_base();
-    stack_size = thread->stack_size();
-  } else {
-    stack_base = (stackptr_t) os::current_stack_base();
-    stack_size = os::current_stack_size();
+  {
+    AixMisc::stackbounds_t stackbounds;
+    if (!AixMisc::query_stack_bounds_for_current_thread(&stackbounds)) {
+      st->print_cr("Cannot retrieve stack bounds.");
+      return;
+    }
+    stack_base = (stackptr_t)stackbounds.base;
+    stack_size = stackbounds.size;
   }
 
   st->print_cr("------ current frame:");
@@ -809,5 +811,73 @@
 }
 
 
+bool AixMisc::query_stack_bounds_for_current_thread(stackbounds_t* out) {
+
+  // Information about this api can be found (a) in the pthread.h header and
+  // (b) in http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/pthread_getthrds_np.htm
+  //
+  // The use of this API to find out the current stack is kind of undefined.
+  // But after a lot of tries and asking IBM about it, I concluded that it is safe
+  // enough for cases where I let the pthread library create its stacks. For cases
+  // where I create an own stack and pass this to pthread_create, it seems not to
+  // work (the returned stack size in that case is 0).
+
+  pthread_t tid = pthread_self();
+  struct __pthrdsinfo pinfo;
+  char dummy[1]; // Just needed to satisfy pthread_getthrds_np.
+  int dummy_size = sizeof(dummy);
+
+  memset(&pinfo, 0, sizeof(pinfo));
+
+  const int rc = pthread_getthrds_np(&tid, PTHRDSINFO_QUERY_ALL, &pinfo,
+                                     sizeof(pinfo), dummy, &dummy_size);
+
+  if (rc != 0) {
+    fprintf(stderr, "pthread_getthrds_np failed (%d)\n", rc);
+    fflush(stdout);
+    return false;
+  }
+
+  // The following may happen when invoking pthread_getthrds_np on a pthread
+  // running on a user provided stack (when handing down a stack to pthread
+  // create, see pthread_attr_setstackaddr).
+  // Not sure what to do then.
+  if (pinfo.__pi_stackend == NULL || pinfo.__pi_stackaddr == NULL) {
+    fprintf(stderr, "pthread_getthrds_np - invalid values\n");
+    fflush(stdout);
+    return false;
+  }
+
+  // Note: we get three values from pthread_getthrds_np:
+  //       __pi_stackaddr, __pi_stacksize, __pi_stackend
+  //
+  // high addr    ---------------------                                                           base, high
+  //
+  //    |         pthread internal data, like ~2K
+  //    |
+  //    |         ---------------------   __pi_stackend   (usually not page aligned, (xxxxF890))
+  //    |
+  //    |
+  //    |
+  //    |
+  //    |
+  //    |
+  //    |          ---------------------   (__pi_stackend - __pi_stacksize)
+  //    |
+  //    |          padding to align the following AIX guard pages, if enabled.
+  //    |
+  //    V          ---------------------   __pi_stackaddr                                        low, base - size
+  //
+  // low addr      AIX guard pages, if enabled (AIXTHREAD_GUARDPAGES > 0)
+  //
+
+  out->base = (address)pinfo.__pi_stackend;
+  address low = (address)pinfo.__pi_stackaddr;
+  out->size = out->base - low;
+  return true;
+
+}
 
 
+
+
--- a/hotspot/src/os/aix/vm/porting_aix.hpp	Wed Jun 28 14:15:56 2017 +0200
+++ b/hotspot/src/os/aix/vm/porting_aix.hpp	Wed Jun 28 16:12:54 2017 +0200
@@ -87,11 +87,25 @@
 
 class AixNativeCallstack {
  public:
+  // This function can be used independently from os::init();
   static void print_callstack_for_context(outputStream* st, const ucontext_t* uc,
                                           bool demangle,
                                           char* buf, size_t buf_size);
 };
 
+class AixMisc {
+ public:
+  struct stackbounds_t {
+    address base; // high address (stack grows down)
+    size_t size;
+  };
+
+  // Invokes pthread_getthrds_np() and returns its values. Note: values are
+  // not aligned to stack page sizes.
+  // This function can be used independently from os::init();
+  static bool query_stack_bounds_for_current_thread(stackbounds_t* out);
+
+};
 
 #endif // OS_AIX_VM_PORTING_AIX_HPP