--- a/hotspot/src/os/aix/vm/os_aix.cpp Sat Dec 05 07:16:52 2015 +0100
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Mon Nov 16 10:58:14 2015 +0100
@@ -36,6 +36,7 @@
#include "compiler/compileBroker.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm_aix.h"
+#include "libo4.hpp"
#include "libperfstat_aix.hpp"
#include "loadlib_aix.hpp"
#include "memory/allocation.inline.hpp"
@@ -108,25 +109,14 @@
#include <sys/vminfo.h>
#include <sys/wait.h>
-// If RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling
-// getrusage() is prepared to handle the associated failure.
-#ifndef RUSAGE_THREAD
-#define RUSAGE_THREAD (1) /* only the calling thread */
-#endif
-
-// PPC port
-static const uintx Use64KPagesThreshold = 1*M;
-static const uintx MaxExpectedDataSegmentSize = SIZE_4G*2;
-
-// Add missing declarations (should be in procinfo.h but isn't until AIX 6.1).
+// Missing prototypes for various system APIs.
+extern "C"
+int mread_real_time(timebasestruct_t *t, size_t size_of_timebasestruct_t);
+
#if !defined(_AIXVERSION_610)
-extern "C" {
- int getthrds64(pid_t ProcessIdentifier,
- struct thrdentry64* ThreadBuffer,
- int ThreadSize,
- tid64_t* IndexPointer,
- int Count);
-}
+extern "C" int getthrds64(pid_t, struct thrdentry64*, int, tid64_t*, int);
+extern "C" int getprocs64(procentry64*, int, fdsinfo*, int, pid_t*, int);
+extern "C" int getargs (procsinfo*, int, char*, int);
#endif
#define MAX_PATH (2 * K)
@@ -150,18 +140,9 @@
typedef unsigned long stackslot_t;
typedef stackslot_t* stackptr_t;
-// Excerpts from systemcfg.h definitions newer than AIX 5.3.
-#ifndef PV_7
-#define PV_7 0x200000 /* Power PC 7 */
-#define PV_7_Compat 0x208000 /* Power PC 7 */
-#endif
-#ifndef PV_8
-#define PV_8 0x300000 /* Power PC 8 */
-#define PV_8_Compat 0x308000 /* Power PC 8 */
-#endif
-
// 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);
// Function to check a given stack pointer against given stack limits.
inline bool is_valid_stackpointer(stackptr_t sp, stackptr_t stack_base, size_t stack_size) {
@@ -185,7 +166,7 @@
if (((uintptr_t)p) & 0x3) {
return false;
}
- if (!LoadedLibraries::find_for_text_address(p, NULL)) {
+ if (LoadedLibraries::find_for_text_address(p, NULL) == NULL) {
return false;
}
return true;
@@ -203,31 +184,44 @@
CHECK_STACK_PTR(sp, stack_base, stack_size); \
}
+static void vmembk_print_on(outputStream* os);
+
////////////////////////////////////////////////////////////////////////////////
// global variables (for a description see os_aix.hpp)
julong os::Aix::_physical_memory = 0;
+
pthread_t os::Aix::_main_thread = ((pthread_t)0);
int os::Aix::_page_size = -1;
+
+// -1 = uninitialized, 0 if AIX, 1 if OS/400 pase
int os::Aix::_on_pase = -1;
+
+// -1 = uninitialized, otherwise os version in the form 0xMMmm - MM:major, mm:minor
+// E.g. 0x0601 for AIX 6.1 or 0x0504 for OS/400 V5R4
int os::Aix::_os_version = -1;
+
int os::Aix::_stack_page_size = -1;
+
+// -1 = uninitialized, 0 - no, 1 - yes
int os::Aix::_xpg_sus_mode = -1;
+
+// -1 = uninitialized, 0 - no, 1 - yes
int os::Aix::_extshm = -1;
-int os::Aix::_logical_cpus = -1;
////////////////////////////////////////////////////////////////////////////////
// local variables
-static int g_multipage_error = -1; // error analysis for multipage initialization
static jlong initial_time_count = 0;
static int clock_tics_per_sec = 100;
static sigset_t check_signal_done; // For diagnostics to print a message once (see run_periodic_checks)
static bool check_signals = true;
-static pid_t _initial_pid = 0;
static int SR_signum = SIGUSR2; // Signal used to suspend/resume a thread (must be > SIGSEGV, see 4355769)
static sigset_t SR_sigset;
+// Process break recorded at startup.
+static address g_brk_at_startup = NULL;
+
// This describes the state of multipage support of the underlying
// OS. Note that this is of no interest to the outsize world and
// therefore should not be defined in AIX class.
@@ -278,8 +272,9 @@
// a specific wish address, e.g. to place the heap in a
// compressed-oops-friendly way.
static bool is_close_to_brk(address a) {
- address a1 = (address) sbrk(0);
- if (a >= a1 && a < (a1 + MaxExpectedDataSegmentSize)) {
+ assert0(g_brk_at_startup != NULL);
+ if (a >= g_brk_at_startup &&
+ a < (g_brk_at_startup + MaxExpectedDataSegmentSize)) {
return true;
}
return false;
@@ -290,11 +285,15 @@
}
julong os::Aix::available_memory() {
+ // Avoid expensive API call here, as returned value will always be null.
+ if (os::Aix::on_pase()) {
+ return 0x0LL;
+ }
os::Aix::meminfo_t mi;
if (os::Aix::get_meminfo(&mi)) {
return mi.real_free;
} else {
- return 0xFFFFFFFFFFFFFFFFLL;
+ return ULONG_MAX;
}
}
@@ -332,7 +331,7 @@
for (int i = 0; i < numFullDisclaimsNeeded; i ++) {
if (::disclaim(p, maxDisclaimSize, DISCLAIM_ZEROMEM) != 0) {
- trc("Cannot disclaim %p - %p (errno %d)\n", p, p + maxDisclaimSize, errno);
+ trcVerbose("Cannot disclaim %p - %p (errno %d)\n", p, p + maxDisclaimSize, errno);
return false;
}
p += maxDisclaimSize;
@@ -340,7 +339,7 @@
if (lastDisclaimSize > 0) {
if (::disclaim(p, lastDisclaimSize, DISCLAIM_ZEROMEM) != 0) {
- trc("Cannot disclaim %p - %p (errno %d)\n", p, p + lastDisclaimSize, errno);
+ trcVerbose("Cannot disclaim %p - %p (errno %d)\n", p, p + lastDisclaimSize, errno);
return false;
}
}
@@ -357,25 +356,30 @@
#error Add appropriate cpu_arch setting
#endif
+// Wrap the function "vmgetinfo" which is not available on older OS releases.
+static int checked_vmgetinfo(void *out, int command, int arg) {
+ if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) {
+ guarantee(false, "cannot call vmgetinfo on AS/400 older than V6R1");
+ }
+ return ::vmgetinfo(out, command, arg);
+}
// Given an address, returns the size of the page backing that address.
size_t os::Aix::query_pagesize(void* addr) {
+ if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) {
+ // AS/400 older than V6R1: no vmgetinfo here, default to 4K
+ return SIZE_4K;
+ }
+
vm_page_info pi;
pi.addr = (uint64_t)addr;
- if (::vmgetinfo(&pi, VM_PAGE_INFO, sizeof(pi)) == 0) {
+ if (checked_vmgetinfo(&pi, VM_PAGE_INFO, sizeof(pi)) == 0) {
return pi.pagesize;
} else {
- fprintf(stderr, "vmgetinfo failed to retrieve page size for address %p (errno %d).\n", addr, errno);
assert(false, "vmgetinfo failed to retrieve page size");
return SIZE_4K;
}
-
-}
-
-// Returns the kernel thread id of the currently running thread.
-pid_t os::Aix::gettid() {
- return (pid_t) thread_self();
}
void os::Aix::initialize_system_info() {
@@ -387,7 +391,6 @@
// Retrieve total physical storage.
os::Aix::meminfo_t mi;
if (!os::Aix::get_meminfo(&mi)) {
- fprintf(stderr, "os::Aix::get_meminfo failed.\n"); fflush(stderr);
assert(false, "os::Aix::get_meminfo failed.");
}
_physical_memory = (julong) mi.real_total;
@@ -400,7 +403,6 @@
case SIZE_64K: return "64K";
case SIZE_16M: return "16M";
case SIZE_16G: return "16G";
- case -1: return "not set";
default:
assert(false, "surprise");
return "??";
@@ -431,6 +433,8 @@
}
// Query default shm page size (LDR_CNTRL SHMPSIZE).
+ // Note that this is pure curiosity. We do not rely on default page size but set
+ // our own page size after allocated.
{
const int shmid = ::shmget(IPC_PRIVATE, 1, IPC_CREAT | S_IRUSR | S_IWUSR);
guarantee(shmid != -1, "shmget failed");
@@ -447,26 +451,26 @@
// number of reasons so we may just as well guarantee it here.
guarantee0(!os::Aix::is_primordial_thread());
- // Query pthread stack page size.
+ // Query pthread stack page size. Should be the same as data page size because
+ // pthread stacks are allocated from C-Heap.
{
int dummy = 0;
g_multipage_support.pthr_stack_pagesize = os::Aix::query_pagesize(&dummy);
}
// Query default text page size (LDR_CNTRL TEXTPSIZE).
- /* PPC port: so far unused.
{
address any_function =
- (address) resolve_function_descriptor_to_code_pointer((address)describe_pagesize);
+ resolve_function_descriptor_to_code_pointer((address)describe_pagesize);
g_multipage_support.textpsize = os::Aix::query_pagesize(any_function);
}
- */
// Now probe for support of 64K pages and 16M pages.
// Before OS/400 V6R1, there is no support for pages other than 4K.
if (os::Aix::on_pase_V5R4_or_older()) {
- Unimplemented();
+ trcVerbose("OS/400 < V6R1 - no large page support.");
+ g_multipage_support.error = ERROR_MP_OS_TOO_OLD;
goto query_multipage_support_end;
}
@@ -474,10 +478,10 @@
{
const int MAX_PAGE_SIZES = 4;
psize_t sizes[MAX_PAGE_SIZES];
- const int num_psizes = ::vmgetinfo(sizes, VMINFO_GETPSIZES, MAX_PAGE_SIZES);
+ const int num_psizes = checked_vmgetinfo(sizes, VMINFO_GETPSIZES, MAX_PAGE_SIZES);
if (num_psizes == -1) {
- trc("vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)\n", errno);
- trc("disabling multipage support.\n");
+ trcVerbose("vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)", errno);
+ trcVerbose("disabling multipage support.");
g_multipage_support.error = ERROR_MP_VMGETINFO_FAILED;
goto query_multipage_support_end;
}
@@ -505,8 +509,8 @@
if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) {
const int en = errno;
::shmctl(shmid, IPC_RMID, NULL); // As early as possible!
- // PPC port trcVerbose("shmctl(SHM_PAGESIZE) failed with %s",
- // PPC port MiscUtils::describe_errno(en));
+ trcVerbose("shmctl(SHM_PAGESIZE) failed with errno=%n",
+ errno);
} else {
// Attach and double check pageisze.
void* p = ::shmat(shmid, NULL, 0);
@@ -532,35 +536,35 @@
query_multipage_support_end:
- trcVerbose("base page size (sysconf _SC_PAGESIZE): %s\n",
+ trcVerbose("base page size (sysconf _SC_PAGESIZE): %s",
describe_pagesize(g_multipage_support.pagesize));
- trcVerbose("Data page size (C-Heap, bss, etc): %s\n",
+ trcVerbose("Data page size (C-Heap, bss, etc): %s",
describe_pagesize(g_multipage_support.datapsize));
- trcVerbose("Text page size: %s\n",
+ trcVerbose("Text page size: %s",
describe_pagesize(g_multipage_support.textpsize));
- trcVerbose("Thread stack page size (pthread): %s\n",
+ trcVerbose("Thread stack page size (pthread): %s",
describe_pagesize(g_multipage_support.pthr_stack_pagesize));
- trcVerbose("Default shared memory page size: %s\n",
+ trcVerbose("Default shared memory page size: %s",
describe_pagesize(g_multipage_support.shmpsize));
- trcVerbose("Can use 64K pages dynamically with shared meory: %s\n",
+ trcVerbose("Can use 64K pages dynamically with shared meory: %s",
(g_multipage_support.can_use_64K_pages ? "yes" :"no"));
- trcVerbose("Can use 16M pages dynamically with shared memory: %s\n",
+ trcVerbose("Can use 16M pages dynamically with shared memory: %s",
(g_multipage_support.can_use_16M_pages ? "yes" :"no"));
- trcVerbose("Multipage error details: %d\n",
+ trcVerbose("Multipage error details: %d",
g_multipage_support.error);
// sanity checks
assert0(g_multipage_support.pagesize == SIZE_4K);
assert0(g_multipage_support.datapsize == SIZE_4K || g_multipage_support.datapsize == SIZE_64K);
- // PPC port: so far unused.assert0(g_multipage_support.textpsize == SIZE_4K || g_multipage_support.textpsize == SIZE_64K);
+ assert0(g_multipage_support.textpsize == SIZE_4K || g_multipage_support.textpsize == SIZE_64K);
assert0(g_multipage_support.pthr_stack_pagesize == g_multipage_support.datapsize);
assert0(g_multipage_support.shmpsize == SIZE_4K || g_multipage_support.shmpsize == SIZE_64K);
-} // end os::Aix::query_multipage_support()
+}
void os::init_system_properties_values() {
-#define DEFAULT_LIBPATH "/usr/lib:/lib"
+#define DEFAULT_LIBPATH "/lib:/usr/lib"
#define EXTENSIONS_DIR "/lib/ext"
// Buffer that fits several sprintfs.
@@ -578,7 +582,10 @@
// Found the full path to libjvm.so.
// Now cut the path to <java_home>/jre if we can.
- *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
+ pslash = strrchr(buf, '/');
+ if (pslash != NULL) {
+ *pslash = '\0'; // Get rid of /libjvm.so.
+ }
pslash = strrchr(buf, '/');
if (pslash != NULL) {
*pslash = '\0'; // Get rid of /{client|server|hotspot}.
@@ -753,8 +760,21 @@
memset(pmi, 0, sizeof(meminfo_t));
if (os::Aix::on_pase()) {
-
- Unimplemented();
+ // On PASE, use the libo4 porting library.
+
+ unsigned long long virt_total = 0;
+ unsigned long long real_total = 0;
+ unsigned long long real_free = 0;
+ unsigned long long pgsp_total = 0;
+ unsigned long long pgsp_free = 0;
+ if (libo4::get_memory_info(&virt_total, &real_total, &real_free, &pgsp_total, &pgsp_free)) {
+ pmi->virt_total = virt_total;
+ pmi->real_total = real_total;
+ pmi->real_free = real_free;
+ pmi->pgsp_total = pgsp_total;
+ pmi->pgsp_free = pgsp_free;
+ return true;
+ }
return false;
} else {
@@ -770,7 +790,7 @@
memset (&psmt, '\0', sizeof(psmt));
const int rc = libperfstat::perfstat_memory_total(NULL, &psmt, sizeof(psmt), 1);
if (rc == -1) {
- fprintf(stderr, "perfstat_memory_total() failed (errno=%d)\n", errno);
+ trcVerbose("perfstat_memory_total() failed (errno=%d)", errno);
assert(0, "perfstat_memory_total() failed");
return false;
}
@@ -798,81 +818,6 @@
}
} // end os::Aix::get_meminfo
-// Retrieve global cpu information.
-// Returns false if something went wrong;
-// the content of pci is undefined in this case.
-bool os::Aix::get_cpuinfo(cpuinfo_t* pci) {
- assert(pci, "get_cpuinfo: invalid parameter");
- memset(pci, 0, sizeof(cpuinfo_t));
-
- perfstat_cpu_total_t psct;
- memset (&psct, '\0', sizeof(psct));
-
- if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t), 1)) {
- fprintf(stderr, "perfstat_cpu_total() failed (errno=%d)\n", errno);
- assert(0, "perfstat_cpu_total() failed");
- return false;
- }
-
- // global cpu information
- strcpy (pci->description, psct.description);
- pci->processorHZ = psct.processorHZ;
- pci->ncpus = psct.ncpus;
- os::Aix::_logical_cpus = psct.ncpus;
- for (int i = 0; i < 3; i++) {
- pci->loadavg[i] = (double) psct.loadavg[i] / (1 << SBITS);
- }
-
- // get the processor version from _system_configuration
- switch (_system_configuration.version) {
- case PV_8:
- strcpy(pci->version, "Power PC 8");
- break;
- case PV_7:
- strcpy(pci->version, "Power PC 7");
- break;
- case PV_6_1:
- strcpy(pci->version, "Power PC 6 DD1.x");
- break;
- case PV_6:
- strcpy(pci->version, "Power PC 6");
- break;
- case PV_5:
- strcpy(pci->version, "Power PC 5");
- break;
- case PV_5_2:
- strcpy(pci->version, "Power PC 5_2");
- break;
- case PV_5_3:
- strcpy(pci->version, "Power PC 5_3");
- break;
- case PV_5_Compat:
- strcpy(pci->version, "PV_5_Compat");
- break;
- case PV_6_Compat:
- strcpy(pci->version, "PV_6_Compat");
- break;
- case PV_7_Compat:
- strcpy(pci->version, "PV_7_Compat");
- break;
- case PV_8_Compat:
- strcpy(pci->version, "PV_8_Compat");
- break;
- default:
- strcpy(pci->version, "unknown");
- }
-
- return true;
-
-} //end os::Aix::get_cpuinfo
-
-//////////////////////////////////////////////////////////////////////////////
-// detecting pthread library
-
-void os::Aix::libpthread_init() {
- return;
-}
-
//////////////////////////////////////////////////////////////////////////////
// create new thread
@@ -889,6 +834,26 @@
thread->set_stack_size(size);
}
+ const pthread_t pthread_id = ::pthread_self();
+ const tid_t kernel_thread_id = ::thread_self();
+
+ trcVerbose("newborn Thread : pthread-id %u, ktid " UINT64_FORMAT
+ ", stack %p ... %p, stacksize 0x%IX (%IB)",
+ pthread_id, kernel_thread_id,
+ thread->stack_base() - thread->stack_size(),
+ thread->stack_base(),
+ thread->stack_size(),
+ thread->stack_size());
+
+ // Normally, pthread stacks on AIX live in the data segment (are allocated with malloc()
+ // by the pthread library). In rare cases, this may not be the case, e.g. when third-party
+ // tools hook pthread_create(). In this case, we may run into problems establishing
+ // guard pages on those stacks, because the stacks may reside in memory which is not
+ // protectable (shmated).
+ if (thread->stack_base() > ::sbrk(0)) {
+ trcVerbose("Thread " UINT64_FORMAT ": stack not in data segment.", (uint64_t) pthread_id);
+ }
+
// Do some sanity checks.
CHECK_CURRENT_STACK_PTR(thread->stack_base(), thread->stack_size());
@@ -906,28 +871,31 @@
OSThread* osthread = thread->osthread();
- // thread_id is kernel thread id (similar to Solaris LWP id)
- osthread->set_thread_id(os::Aix::gettid());
-
- // initialize signal mask for this thread
+ // Thread_id is pthread id.
+ osthread->set_thread_id(pthread_id);
+
+ // .. but keep kernel thread id too for diagnostics
+ osthread->set_kernel_thread_id(kernel_thread_id);
+
+ // Initialize signal mask for this thread.
os::Aix::hotspot_sigmask(thread);
- // initialize floating point control register
+ // Initialize floating point control register.
os::Aix::init_thread_fpu_state();
assert(osthread->get_state() == RUNNABLE, "invalid os thread state");
- // call one more level start routine
+ // Call one more level start routine.
thread->run();
+ trcVerbose("Thread finished : pthread-id %u, ktid " UINT64_FORMAT ".",
+ pthread_id, kernel_thread_id);
+
return 0;
}
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
- // We want the whole function to be synchronized.
- ThreadCritical cs;
-
assert(thread->osthread() == NULL, "caller responsible");
// Allocate the OSThread object
@@ -992,8 +960,14 @@
pthread_attr_destroy(&attr);
if (ret == 0) {
- // PPC port traceOsMisc(("Created New Thread : pthread-id %u", tid));
+ trcVerbose("Created New Thread : pthread-id %u", tid);
} else {
+ if (os::Aix::on_pase()) {
+ // QIBM_MULTI_THREADED=Y is needed when the launcher is started on iSeries
+ // using QSH. Otherwise pthread_create fails with errno=11.
+ trcVerbose("(Please make sure you set the environment variable "
+ "QIBM_MULTI_THREADED=Y before running this program.)");
+ }
if (PrintMiscellaneous && (Verbose || WizardMode)) {
perror("pthread_create()");
}
@@ -1003,8 +977,8 @@
return false;
}
- // Store pthread info into the OSThread
- osthread->set_pthread_id(tid);
+ // OSThread::thread_id is the pthread id.
+ osthread->set_thread_id(tid);
return true;
}
@@ -1030,9 +1004,21 @@
return false;
}
- // Store pthread info into the OSThread
- osthread->set_thread_id(os::Aix::gettid());
- osthread->set_pthread_id(::pthread_self());
+ const pthread_t pthread_id = ::pthread_self();
+ const tid_t kernel_thread_id = ::thread_self();
+
+ trcVerbose("attaching Thread : pthread-id %u, ktid " UINT64_FORMAT ", stack %p ... %p, stacksize 0x%IX (%IB)",
+ pthread_id, kernel_thread_id,
+ thread->stack_base() - thread->stack_size(),
+ thread->stack_base(),
+ thread->stack_size(),
+ thread->stack_size());
+
+ // OSThread::thread_id is the pthread id.
+ osthread->set_thread_id(pthread_id);
+
+ // .. but keep kernel thread id too for diagnostics
+ osthread->set_kernel_thread_id(kernel_thread_id);
// initialize floating point control register
os::Aix::init_thread_fpu_state();
@@ -1126,17 +1112,15 @@
nanos = jlong(time.tv_usec) * 1000;
}
-
-// We need to manually declare mread_real_time,
-// because IBM didn't provide a prototype in time.h.
-// (they probably only ever tested in C, not C++)
-extern "C"
-int mread_real_time(timebasestruct_t *t, size_t size_of_timebasestruct_t);
-
jlong os::javaTimeNanos() {
if (os::Aix::on_pase()) {
- Unimplemented();
- return 0;
+
+ timeval time;
+ int status = gettimeofday(&time, NULL);
+ assert(status != -1, "PASE error at gettimeofday()");
+ jlong usecs = jlong((unsigned long long) time.tv_sec * (1000 * 1000) + time.tv_usec);
+ return 1000 * usecs;
+
} else {
// On AIX use the precision of processors real time clock
// or time base registers.
@@ -1265,22 +1249,12 @@
return n;
}
-intx os::current_thread_id() { return (intx)pthread_self(); }
+intx os::current_thread_id() {
+ return (intx)pthread_self();
+}
int os::current_process_id() {
-
- // This implementation returns a unique pid, the pid of the
- // launcher thread that starts the vm 'process'.
-
- // Under POSIX, getpid() returns the same pid as the
- // launcher thread rather than a unique pid per thread.
- // Use gettid() if you want the old pre NPTL behaviour.
-
- // if you are looking for the result of a call to getpid() that
- // returns a unique pid for the calling thread, then look at the
- // OSThread::thread_id() method in osThread_linux.hpp file
-
- return (int)(_initial_pid ? _initial_pid : getpid());
+ return getpid();
}
// DLL functions
@@ -1317,6 +1291,9 @@
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
+ if (pelements == NULL) {
+ return false;
+ }
for (int i = 0; i < n; i++) {
// Really shouldn't be NULL, but check can't hurt
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
@@ -1554,62 +1531,98 @@
os::loadavg(loadavg, 3);
st->print("%0.02f %0.02f %0.02f", loadavg[0], loadavg[1], loadavg[2]);
st->cr();
+
+ // print wpar info
+ libperfstat::wparinfo_t wi;
+ if (libperfstat::get_wparinfo(&wi)) {
+ st->print_cr("wpar info");
+ st->print_cr("name: %s", wi.name);
+ st->print_cr("id: %d", wi.wpar_id);
+ st->print_cr("type: %s", (wi.app_wpar ? "application" : "system"));
+ }
+
+ // print partition info
+ libperfstat::partitioninfo_t pi;
+ if (libperfstat::get_partitioninfo(&pi)) {
+ st->print_cr("partition info");
+ st->print_cr(" name: %s", pi.name);
+ }
+
}
void os::print_memory_info(outputStream* st) {
st->print_cr("Memory:");
- st->print_cr(" default page size: %s", describe_pagesize(os::vm_page_size()));
- st->print_cr(" default stack page size: %s", describe_pagesize(os::vm_page_size()));
+ st->print_cr(" Base page size (sysconf _SC_PAGESIZE): %s",
+ describe_pagesize(g_multipage_support.pagesize));
+ st->print_cr(" Data page size (C-Heap, bss, etc): %s",
+ describe_pagesize(g_multipage_support.datapsize));
+ st->print_cr(" Text page size: %s",
+ describe_pagesize(g_multipage_support.textpsize));
+ st->print_cr(" Thread stack page size (pthread): %s",
+ describe_pagesize(g_multipage_support.pthr_stack_pagesize));
st->print_cr(" Default shared memory page size: %s",
describe_pagesize(g_multipage_support.shmpsize));
st->print_cr(" Can use 64K pages dynamically with shared meory: %s",
(g_multipage_support.can_use_64K_pages ? "yes" :"no"));
st->print_cr(" Can use 16M pages dynamically with shared memory: %s",
(g_multipage_support.can_use_16M_pages ? "yes" :"no"));
- if (g_multipage_error != 0) {
- st->print_cr(" multipage error: %d", g_multipage_error);
- }
+ st->print_cr(" Multipage error: %d",
+ g_multipage_support.error);
+ st->cr();
+ st->print_cr(" os::vm_page_size: %s", describe_pagesize(os::vm_page_size()));
+ // not used in OpenJDK st->print_cr(" os::stack_page_size: %s", describe_pagesize(os::stack_page_size()));
// print out LDR_CNTRL because it affects the default page sizes
const char* const ldr_cntrl = ::getenv("LDR_CNTRL");
st->print_cr(" LDR_CNTRL=%s.", ldr_cntrl ? ldr_cntrl : "<unset>");
+ // Print out EXTSHM because it is an unsupported setting.
const char* const extshm = ::getenv("EXTSHM");
st->print_cr(" EXTSHM=%s.", extshm ? extshm : "<unset>");
if ( (strcmp(extshm, "on") == 0) || (strcmp(extshm, "ON") == 0) ) {
st->print_cr(" *** Unsupported! Please remove EXTSHM from your environment! ***");
}
- // Call os::Aix::get_meminfo() to retrieve memory statistics.
+ // Print out AIXTHREAD_GUARDPAGES because it affects the size of pthread stacks.
+ const char* const aixthread_guardpages = ::getenv("AIXTHREAD_GUARDPAGES");
+ st->print_cr(" AIXTHREAD_GUARDPAGES=%s.",
+ aixthread_guardpages ? aixthread_guardpages : "<unset>");
+
os::Aix::meminfo_t mi;
if (os::Aix::get_meminfo(&mi)) {
char buffer[256];
if (os::Aix::on_aix()) {
- jio_snprintf(buffer, sizeof(buffer),
- " physical total : %llu\n"
- " physical free : %llu\n"
- " swap total : %llu\n"
- " swap free : %llu\n",
- mi.real_total,
- mi.real_free,
- mi.pgsp_total,
- mi.pgsp_free);
+ st->print_cr("physical total : " SIZE_FORMAT, mi.real_total);
+ st->print_cr("physical free : " SIZE_FORMAT, mi.real_free);
+ st->print_cr("swap total : " SIZE_FORMAT, mi.pgsp_total);
+ st->print_cr("swap free : " SIZE_FORMAT, mi.pgsp_free);
} else {
- Unimplemented();
+ // PASE - Numbers are result of QWCRSSTS; they mean:
+ // real_total: Sum of all system pools
+ // real_free: always 0
+ // pgsp_total: we take the size of the system ASP
+ // pgsp_free: size of system ASP times percentage of system ASP unused
+ st->print_cr("physical total : " SIZE_FORMAT, mi.real_total);
+ st->print_cr("system asp total : " SIZE_FORMAT, mi.pgsp_total);
+ st->print_cr("%% system asp used : " SIZE_FORMAT,
+ mi.pgsp_total ? (100.0f * (mi.pgsp_total - mi.pgsp_free) / mi.pgsp_total) : -1.0f);
}
st->print_raw(buffer);
- } else {
- st->print_cr(" (no more information available)");
- }
+ }
+ st->cr();
+
+ // Print segments allocated with os::reserve_memory.
+ st->print_cr("internal virtual memory regions used by vm:");
+ vmembk_print_on(st);
}
// Get a string for the cpuinfo that is a summary of the cpu type
void os::get_summary_cpu_info(char* buf, size_t buflen) {
// This looks good
- os::Aix::cpuinfo_t ci;
- if (os::Aix::get_cpuinfo(&ci)) {
+ libperfstat::cpuinfo_t ci;
+ if (libperfstat::get_cpuinfo(&ci)) {
strncpy(buf, ci.version, buflen);
} else {
strncpy(buf, "AIX", buflen);
@@ -1617,10 +1630,15 @@
}
void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
+ st->print("CPU:");
+ st->print("total %d", os::processor_count());
+ // It's not safe to query number of active processors after crash.
+ // st->print("(active %d)", os::active_processor_count());
+ st->print(" %s", VM_Version::cpu_features());
+ st->cr();
}
void os::print_siginfo(outputStream* st, void* siginfo) {
- // Use common posix version.
os::Posix::print_siginfo_brief(st, (const siginfo_t*) siginfo);
st->cr();
}
@@ -1759,21 +1777,75 @@
// a counter for each possible signal value
static volatile jint pending_signals[NSIG+1] = { 0 };
-// Linux(POSIX) specific hand shaking semaphore.
+// Wrapper functions for: sem_init(), sem_post(), sem_wait()
+// On AIX, we use sem_init(), sem_post(), sem_wait()
+// On Pase, we need to use msem_lock() and msem_unlock(), because Posix Semaphores
+// do not seem to work at all on PASE (unimplemented, will cause SIGILL).
+// Note that just using msem_.. APIs for both PASE and AIX is not an option either, as
+// on AIX, msem_..() calls are suspected of causing problems.
static sem_t sig_sem;
+static msemaphore* p_sig_msem = 0;
+
+static void local_sem_init() {
+ if (os::Aix::on_aix()) {
+ int rc = ::sem_init(&sig_sem, 0, 0);
+ guarantee(rc != -1, "sem_init failed");
+ } else {
+ // Memory semaphores must live in shared mem.
+ guarantee0(p_sig_msem == NULL);
+ p_sig_msem = (msemaphore*)os::reserve_memory(sizeof(msemaphore), NULL);
+ guarantee(p_sig_msem, "Cannot allocate memory for memory semaphore");
+ guarantee(::msem_init(p_sig_msem, 0) == p_sig_msem, "msem_init failed");
+ }
+}
+
+static void local_sem_post() {
+ static bool warn_only_once = false;
+ if (os::Aix::on_aix()) {
+ int rc = ::sem_post(&sig_sem);
+ if (rc == -1 && !warn_only_once) {
+ trcVerbose("sem_post failed (errno = %d, %s)", errno, strerror(errno));
+ warn_only_once = true;
+ }
+ } else {
+ guarantee0(p_sig_msem != NULL);
+ int rc = ::msem_unlock(p_sig_msem, 0);
+ if (rc == -1 && !warn_only_once) {
+ trcVerbose("msem_unlock failed (errno = %d, %s)", errno, strerror(errno));
+ warn_only_once = true;
+ }
+ }
+}
+
+static void local_sem_wait() {
+ static bool warn_only_once = false;
+ if (os::Aix::on_aix()) {
+ int rc = ::sem_wait(&sig_sem);
+ if (rc == -1 && !warn_only_once) {
+ trcVerbose("sem_wait failed (errno = %d, %s)", errno, strerror(errno));
+ warn_only_once = true;
+ }
+ } else {
+ guarantee0(p_sig_msem != NULL); // must init before use
+ int rc = ::msem_lock(p_sig_msem, 0);
+ if (rc == -1 && !warn_only_once) {
+ trcVerbose("msem_lock failed (errno = %d, %s)", errno, strerror(errno));
+ warn_only_once = true;
+ }
+ }
+}
void os::signal_init_pd() {
// Initialize signal structures
::memset((void*)pending_signals, 0, sizeof(pending_signals));
// Initialize signal semaphore
- int rc = ::sem_init(&sig_sem, 0, 0);
- guarantee(rc != -1, "sem_init failed");
+ local_sem_init();
}
void os::signal_notify(int sig) {
Atomic::inc(&pending_signals[sig]);
- ::sem_post(&sig_sem);
+ local_sem_post();
}
static int check_pending_signals(bool wait) {
@@ -1796,7 +1868,7 @@
thread->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
- ::sem_wait(&sig_sem);
+ local_sem_wait();
// were we externally suspended while we were waiting?
threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
@@ -1807,7 +1879,8 @@
// while suspended because that would surprise the thread that
// suspended us.
//
- ::sem_post(&sig_sem);
+
+ local_sem_post();
thread->java_suspend_self();
}
@@ -1858,14 +1931,14 @@
// also check that range is fully page aligned to the page size if the block.
void assert_is_valid_subrange(char* p, size_t s) const {
if (!contains_range(p, s)) {
- fprintf(stderr, "[" PTR_FORMAT " - " PTR_FORMAT "] is not a sub "
- "range of [" PTR_FORMAT " - " PTR_FORMAT "].\n",
- p, p + s - 1, addr, addr + size - 1);
+ trcVerbose("[" PTR_FORMAT " - " PTR_FORMAT "] is not a sub "
+ "range of [" PTR_FORMAT " - " PTR_FORMAT "].",
+ p, p + s, addr, addr + size);
guarantee0(false);
}
if (!is_aligned_to(p, pagesize) || !is_aligned_to(p + s, pagesize)) {
- fprintf(stderr, "range [" PTR_FORMAT " - " PTR_FORMAT "] is not"
- " aligned to pagesize (%s)\n", p, p + s);
+ trcVerbose("range [" PTR_FORMAT " - " PTR_FORMAT "] is not"
+ " aligned to pagesize (%lu)", p, p + s, (unsigned long) pagesize);
guarantee0(false);
}
}
@@ -1962,7 +2035,7 @@
// Reserve the shared segment.
int shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | S_IRUSR | S_IWUSR);
if (shmid == -1) {
- trc("shmget(.., " UINTX_FORMAT ", ..) failed (errno: %d).", size, errno);
+ trcVerbose("shmget(.., " UINTX_FORMAT ", ..) failed (errno: %d).", size, errno);
return NULL;
}
@@ -1991,7 +2064,7 @@
// (A) Right after shmat and before handing shmat errors delete the shm segment.
if (::shmctl(shmid, IPC_RMID, NULL) == -1) {
- trc("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno);
+ trcVerbose("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno);
assert(false, "failed to remove shared memory segment!");
}
@@ -2056,6 +2129,8 @@
return true;
}
+//////////////////////////////// mmap-based routines /////////////////////////////////
+
// Reserve memory via mmap.
// If <requested_addr> is given, an attempt is made to attach at the given address.
// Failing that, memory is allocated at any address.
@@ -2201,9 +2276,6 @@
return rc;
}
-// End: shared memory bookkeeping
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
int os::vm_page_size() {
// Seems redundant as all get out.
assert(os::Aix::page_size() != -1, "must call os::init");
@@ -2245,11 +2317,18 @@
size, os::vm_page_size());
vmembk_t* const vmi = vmembk_find(addr);
- assert0(vmi);
+ guarantee0(vmi);
vmi->assert_is_valid_subrange(addr, size);
trcVerbose("commit_memory [" PTR_FORMAT " - " PTR_FORMAT "].", addr, addr + size - 1);
+ if (UseExplicitCommit) {
+ // AIX commits memory on touch. So, touch all pages to be committed.
+ for (char* p = addr; p < (addr + size); p += SIZE_4K) {
+ *p = '\0';
+ }
+ }
+
return true;
}
@@ -2274,7 +2353,7 @@
// Dynamically do different things for mmap/shmat.
const vmembk_t* const vmi = vmembk_find(addr);
- assert0(vmi);
+ guarantee0(vmi);
vmi->assert_is_valid_subrange(addr, size);
if (vmi->type == VMEM_SHMATED) {
@@ -2372,7 +2451,7 @@
// Dynamically do different things for mmap/shmat.
vmembk_t* const vmi = vmembk_find(addr);
- assert0(vmi);
+ guarantee0(vmi);
// Always round to os::vm_page_size(), which may be larger than 4K.
size = align_size_up(size, os::vm_page_size());
@@ -2448,11 +2527,31 @@
} else {
rc = read_protected;
}
+
+ if (!rc) {
+ if (os::Aix::on_pase()) {
+ // There is an issue on older PASE systems where mprotect() will return success but the
+ // memory will not be protected.
+ // This has nothing to do with the problem of using mproect() on SPEC1170 incompatible
+ // machines; we only see it rarely, when using mprotect() to protect the guard page of
+ // a stack. It is an OS error.
+ //
+ // A valid strategy is just to try again. This usually works. :-/
+
+ ::usleep(1000);
+ if (::mprotect(addr, size, prot) == 0) {
+ const bool read_protected_2 =
+ (SafeFetch32((int*)addr, 0x12345678) == 0x12345678 &&
+ SafeFetch32((int*)addr, 0x76543210) == 0x76543210) ? true : false;
+ rc = true;
+ }
+ }
+ }
}
}
- if (!rc) {
- assert(false, "mprotect failed.");
- }
+
+ assert(rc == true, "mprotect failed.");
+
return rc;
}
@@ -2489,10 +2588,11 @@
}
char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) {
- // "exec" is passed in but not used. Creating the shared image for
- // the code cache doesn't have an SHM_X executable permission to check.
- Unimplemented();
- return 0;
+ // reserve_memory_special() is used to allocate large paged memory. On AIX, we implement
+ // 64k paged memory reservation using the normal memory allocation paths (os::reserve_memory()),
+ // so this is not needed.
+ assert(false, "should not be called on AIX");
+ return NULL;
}
bool os::release_memory_special(char* base, size_t bytes) {
@@ -2944,7 +3044,9 @@
// getting raised while being blocked.
unblock_program_error_signals();
+ int orig_errno = errno; // Preserve errno value over signal handler.
JVM_handle_aix_signal(sig, info, uc, true);
+ errno = orig_errno;
}
// This boolean allows users to forward their own non-matching signals
@@ -3066,7 +3168,6 @@
void* oldhand = oldAct.sa_sigaction
? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
: CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
- // Renamed 'signalHandler' to avoid collision with other shared libs.
if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) &&
oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) &&
oldhand != CAST_FROM_FN_PTR(void*, (sa_sigaction_t)javaSignalHandler)) {
@@ -3090,7 +3191,6 @@
sigAct.sa_handler = SIG_DFL;
sigAct.sa_flags = SA_RESTART;
} else {
- // Renamed 'signalHandler' to avoid collision with other shared libs.
sigAct.sa_sigaction = javaSignalHandler;
sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
}
@@ -3282,7 +3382,7 @@
struct sigaction act;
if (os_sigaction == NULL) {
// only trust the default sigaction, in case it has been interposed
- os_sigaction = (os_sigaction_t)dlsym(RTLD_DEFAULT, "sigaction");
+ os_sigaction = CAST_TO_FN_PTR(os_sigaction_t, dlsym(RTLD_DEFAULT, "sigaction"));
if (os_sigaction == NULL) return;
}
@@ -3299,7 +3399,6 @@
case SIGPIPE:
case SIGILL:
case SIGXFSZ:
- // Renamed 'signalHandler' to avoid collision with other shared libs.
jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)javaSignalHandler);
break;
@@ -3357,6 +3456,10 @@
// (Shared memory boundary is supposed to be a 256M aligned.)
assert(SHMLBA == ((uint64_t)0x10000000ULL)/*256M*/, "unexpected");
+ // Record process break at startup.
+ g_brk_at_startup = (address) ::sbrk(0);
+ assert(g_brk_at_startup != (address) -1, "sbrk failed");
+
// First off, we need to know whether we run on AIX or PASE, and
// the OS level we run on.
os::Aix::initialize_os_info();
@@ -3364,7 +3467,7 @@
// Scan environment (SPEC1170 behaviour, etc).
os::Aix::scan_environment();
- // Check which pages are supported by AIX.
+ // Probe multipage support.
query_multipage_support();
// Act like we only have one page size by eliminating corner cases which
@@ -3417,9 +3520,9 @@
}
} else {
// datapsize = 64k. Data segment, thread stacks are 64k paged.
- // This normally means that we can allocate 64k pages dynamically.
- // (There is one special case where this may be false: EXTSHM=on.
- // but we decided to not support that mode).
+ // This normally means that we can allocate 64k pages dynamically.
+ // (There is one special case where this may be false: EXTSHM=on.
+ // but we decided to not support that mode).
assert0(g_multipage_support.can_use_64K_pages);
Aix::_page_size = SIZE_64K;
trcVerbose("64K page mode");
@@ -3435,7 +3538,7 @@
_page_sizes[0] = 0;
// debug trace
- trcVerbose("os::vm_page_size %s\n", describe_pagesize(os::vm_page_size()));
+ trcVerbose("os::vm_page_size %s", describe_pagesize(os::vm_page_size()));
// Next, we need to initialize libo4 and libperfstat libraries.
if (os::Aix::on_pase()) {
@@ -3453,8 +3556,6 @@
// need libperfstat etc.
os::Aix::initialize_system_info();
- _initial_pid = getpid();
-
clock_tics_per_sec = sysconf(_SC_CLK_TCK);
init_random(1234567);
@@ -3479,11 +3580,21 @@
// This is called _after_ the global arguments have been parsed.
jint os::init_2(void) {
+ if (os::Aix::on_pase()) {
+ trcVerbose("Running on PASE.");
+ } else {
+ trcVerbose("Running on AIX (not PASE).");
+ }
+
trcVerbose("processor count: %d", os::_processor_count);
trcVerbose("physical memory: %lu", Aix::_physical_memory);
// Initially build up the loaded dll map.
LoadedLibraries::reload();
+ if (Verbose) {
+ trcVerbose("Loaded Libraries: ");
+ LoadedLibraries::print(tty);
+ }
const int page_size = Aix::page_size();
const int map_size = page_size;
@@ -3521,10 +3632,8 @@
map_size, prot,
flags | MAP_FIXED,
-1, 0);
- if (Verbose) {
- fprintf(stderr, "SafePoint Polling Page address: %p (wish) => %p\n",
- address_wishes[i], map_address + (ssize_t)page_size);
- }
+ trcVerbose("SafePoint Polling Page address: %p (wish) => %p",
+ address_wishes[i], map_address + (ssize_t)page_size);
if (map_address + (ssize_t)page_size == address_wishes[i]) {
// Map succeeded and map_address is at wished address, exit loop.
@@ -3551,11 +3660,9 @@
guarantee(mem_serialize_page != NULL, "mmap Failed for memory serialize page");
os::set_memory_serialize_page(mem_serialize_page);
-#ifndef PRODUCT
- if (Verbose && PrintMiscellaneous) {
- tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page);
- }
-#endif
+ trcVerbose("Memory Serialize Page address: %p - %p, size %IX (%IB)",
+ mem_serialize_page, mem_serialize_page + Aix::page_size(),
+ Aix::page_size(), Aix::page_size());
}
// initialize suspend/resume support - must do this before signal_sets_init()
@@ -3592,7 +3699,10 @@
// Note that this can be 0, if no default stacksize was set.
JavaThread::set_stack_size_at_create(round_to(threadStackSizeInBytes, vm_page_size()));
- Aix::libpthread_init();
+ if (UseNUMA) {
+ UseNUMA = false;
+ warning("NUMA optimizations are not available on this OS.");
+ }
if (MaxFDLimit) {
// Set the number of file descriptors to max. print out error
@@ -3614,7 +3724,7 @@
if (PerfAllowAtExitRegistration) {
// Only register atexit functions if PerfAllowAtExitRegistration is set.
- // Atexit functions can be delayed until process exit time, which
+ // At exit functions can be delayed until process exit time, which
// can be problematic for embedded VM situations. Embedded VMs should
// call DestroyJavaVM() to assure that VM resources are released.
@@ -3714,16 +3824,6 @@
////////////////////////////////////////////////////////////////////////////////
// debug support
-static address same_page(address x, address y) {
- intptr_t page_bits = -os::vm_page_size();
- if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits))
- return x;
- else if (x > y)
- return (address)(intptr_t(y) | ~page_bits) + 1;
- else
- return (address)(intptr_t(y) & page_bits);
-}
-
bool os::find(address addr, outputStream* st) {
st->print(PTR_FORMAT ": ", addr);
@@ -4087,24 +4187,28 @@
// For now just return the system wide load average (no processor sets).
int os::loadavg(double values[], int nelem) {
- // Implemented using libperfstat on AIX.
-
guarantee(nelem >= 0 && nelem <= 3, "argument error");
guarantee(values, "argument error");
if (os::Aix::on_pase()) {
- Unimplemented();
- return -1;
+
+ // AS/400 PASE: use libo4 porting library
+ double v[3] = { 0.0, 0.0, 0.0 };
+
+ if (libo4::get_load_avg(v, v + 1, v + 2)) {
+ for (int i = 0; i < nelem; i ++) {
+ values[i] = v[i];
+ }
+ return nelem;
+ } else {
+ return -1;
+ }
+
} else {
+
// AIX: use libperfstat
- //
- // See also:
- // http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/perfstat_cputot.htm
- // /usr/include/libperfstat.h:
-
- // Use the already AIX version independent get_cpuinfo.
- os::Aix::cpuinfo_t ci;
- if (os::Aix::get_cpuinfo(&ci)) {
+ libperfstat::cpuinfo_t ci;
+ if (libperfstat::get_cpuinfo(&ci)) {
for (int i = 0; i < nelem; i++) {
values[i] = ci.loadavg[i];
}
@@ -4131,8 +4235,7 @@
(void)::poll(NULL, 0, 100);
}
} else {
- jio_fprintf(stderr,
- "Could not open pause file '%s', continuing immediately.\n", filename);
+ trcVerbose("Could not open pause file '%s', continuing immediately.", filename);
}
}
@@ -4154,7 +4257,7 @@
memset(&uts, 0, sizeof(uts));
strcpy(uts.sysname, "?");
if (::uname(&uts) == -1) {
- trc("uname failed (%d)", errno);
+ trcVerbose("uname failed (%d)", errno);
guarantee(0, "Could not determine whether we run on AIX or PASE");
} else {
trcVerbose("uname says: sysname \"%s\" version \"%s\" release \"%s\" "
@@ -4166,15 +4269,22 @@
assert(minor > 0, "invalid OS release");
_os_version = (major << 8) | minor;
if (strcmp(uts.sysname, "OS400") == 0) {
- Unimplemented();
+ // We run on AS/400 PASE. We do not support versions older than V5R4M0.
+ _on_pase = 1;
+ if (_os_version < 0x0504) {
+ trcVerbose("OS/400 releases older than V5R4M0 not supported.");
+ assert(false, "OS/400 release too old.");
+ } else {
+ trcVerbose("We run on OS/400 (pase) V%dR%d", major, minor);
+ }
} else if (strcmp(uts.sysname, "AIX") == 0) {
// We run on AIX. We do not support versions older than AIX 5.3.
_on_pase = 0;
if (_os_version < 0x0503) {
- trc("AIX release older than AIX 5.3 not supported.");
+ trcVerbose("AIX release older than AIX 5.3 not supported.");
assert(false, "AIX release too old.");
} else {
- trcVerbose("We run on AIX %d.%d\n", major, minor);
+ trcVerbose("We run on AIX %d.%d", major, minor);
}
} else {
assert(false, "unknown OS");
@@ -4200,12 +4310,17 @@
// This switch was needed on AIX 32bit, but on AIX 64bit the general
// recommendation is (in OSS notes) to switch it off.
p = ::getenv("EXTSHM");
- if (Verbose) {
- fprintf(stderr, "EXTSHM=%s.\n", p ? p : "<unset>");
- }
+ trcVerbose("EXTSHM=%s.", p ? p : "<unset>");
if (p && strcasecmp(p, "ON") == 0) {
- fprintf(stderr, "Unsupported setting: EXTSHM=ON. Large Page support will be disabled.\n");
_extshm = 1;
+ trcVerbose("*** Unsupported mode! Please remove EXTSHM from your environment! ***");
+ if (!AllowExtshm) {
+ // We allow under certain conditions the user to continue. However, we want this
+ // to be a fatal error by default. On certain AIX systems, leaving EXTSHM=ON means
+ // that the VM is not able to allocate 64k pages for the heap.
+ // We do not want to run with reduced performance.
+ vm_exit_during_initialization("EXTSHM is ON. Please remove EXTSHM from your environment.");
+ }
} else {
_extshm = 0;
}
@@ -4222,7 +4337,7 @@
trcVerbose("XPG_SUS_ENV=%s.", p ? p : "<unset>");
if (p && strcmp(p, "ON") == 0) {
_xpg_sus_mode = 1;
- trc("Unsupported setting: XPG_SUS_ENV=ON");
+ trcVerbose("Unsupported setting: XPG_SUS_ENV=ON");
// This is not supported. Worst of all, it changes behaviour of mmap MAP_FIXED to
// clobber address ranges. If we ever want to support that, we have to do some
// testing first.
@@ -4231,35 +4346,46 @@
_xpg_sus_mode = 0;
}
- // Switch off AIX internal (pthread) guard pages. This has
- // immediate effect for any pthread_create calls which follow.
+ if (os::Aix::on_pase()) {
+ p = ::getenv("QIBM_MULTI_THREADED");
+ trcVerbose("QIBM_MULTI_THREADED=%s.", p ? p : "<unset>");
+ }
+
+ p = ::getenv("LDR_CNTRL");
+ trcVerbose("LDR_CNTRL=%s.", p ? p : "<unset>");
+ if (os::Aix::on_pase() && os::Aix::os_version() == 0x0701) {
+ if (p && ::strstr(p, "TEXTPSIZE")) {
+ trcVerbose("*** WARNING - LDR_CNTRL contains TEXTPSIZE. "
+ "you may experience hangs or crashes on OS/400 V7R1.");
+ }
+ }
+
p = ::getenv("AIXTHREAD_GUARDPAGES");
trcVerbose("AIXTHREAD_GUARDPAGES=%s.", p ? p : "<unset>");
- rc = ::putenv("AIXTHREAD_GUARDPAGES=0");
- guarantee(rc == 0, "");
} // end: os::Aix::scan_environment()
-// PASE: initialize the libo4 library (AS400 PASE porting library).
+// PASE: initialize the libo4 library (PASE porting library).
void os::Aix::initialize_libo4() {
- Unimplemented();
-}
-
-// AIX: initialize the libperfstat library (we load this dynamically
-// because it is only available on AIX.
+ guarantee(os::Aix::on_pase(), "OS/400 only.");
+ if (!libo4::init()) {
+ trcVerbose("libo4 initialization failed.");
+ assert(false, "libo4 initialization failed");
+ } else {
+ trcVerbose("libo4 initialized.");
+ }
+}
+
+// AIX: initialize the libperfstat library.
void os::Aix::initialize_libperfstat() {
-
assert(os::Aix::on_aix(), "AIX only");
-
if (!libperfstat::init()) {
- trc("libperfstat initialization failed.");
+ trcVerbose("libperfstat initialization failed.");
assert(false, "libperfstat initialization failed");
} else {
- if (Verbose) {
- fprintf(stderr, "libperfstat initialized.\n");
- }
- }
-} // end: os::Aix::initialize_libperfstat
+ trcVerbose("libperfstat initialized.");
+ }
+}
/////////////////////////////////////////////////////////////////////////////
// thread stack
@@ -4296,10 +4422,11 @@
}
guarantee0(pinfo.__pi_stackend);
- // The following can 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 here - I feel inclined to forbid this use case completely.
+ // 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:
@@ -4326,7 +4453,8 @@
//
address stack_base = (address)(pinfo.__pi_stackend);
- address stack_low_addr = (address)align_ptr_up(pinfo.__pi_stackaddr, os::vm_page_size());
+ 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) {