8194258: PPC64 safepoint mechanism: Fix initialization on AIX and support SIGTRAP

Use mmap on AIX to allocate protected page. Use trap instructions for polling if UseSIGTRAP is enabled.

Reviewed-by: rehn, goetz
This commit is contained in:
Martin Doerr 2018-01-10 11:09:55 +01:00
parent 15ef7c04a2
commit 201a232a23
8 changed files with 87 additions and 30 deletions

@ -55,5 +55,9 @@ const bool CCallingConventionRequiresIntsAsLongs = true;
#define SUPPORT_RESERVED_STACK_AREA
#define THREAD_LOCAL_POLL
// If UseSIGTRAP is active, we only use the poll bit and no polling page.
// Otherwise, we fall back to usage of the polling page in nmethods.
// Define the condition to use this -XX flag.
#define USE_POLL_BIT_ONLY UseSIGTRAP
#endif // CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP

@ -30,6 +30,7 @@
#include "asm/macroAssembler.hpp"
#include "asm/codeBuffer.hpp"
#include "code/codeCache.hpp"
#include "runtime/safepointMechanism.hpp"
inline bool MacroAssembler::is_ld_largeoffset(address a) {
const int inst1 = *(int *)a;
@ -261,7 +262,12 @@ inline address MacroAssembler::last_calls_return_pc() {
// Read from the polling page, its address is already in a register.
inline void MacroAssembler::load_from_polling_page(Register polling_page_address, int offset) {
ld(R0, offset, polling_page_address);
if (SafepointMechanism::uses_thread_local_poll() && USE_POLL_BIT_ONLY) {
int encoding = SafepointMechanism::poll_bit();
tdi(traptoGreaterThanUnsigned | traptoEqual, polling_page_address, encoding);
} else {
ld(R0, offset, polling_page_address);
}
}
// Trap-instruction-based checks.

@ -31,6 +31,7 @@
#include "memory/allocation.hpp"
#include "runtime/icache.hpp"
#include "runtime/os.hpp"
#include "runtime/safepointMechanism.hpp"
// We have interfaces for the following instructions:
//
@ -93,6 +94,11 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC {
bool is_safepoint_poll() {
// Is the current instruction a POTENTIAL read access to the polling page?
// The current arguments of the instruction are not checked!
if (SafepointMechanism::uses_thread_local_poll() && USE_POLL_BIT_ONLY) {
int encoding = SafepointMechanism::poll_bit();
return MacroAssembler::is_tdi(long_at(0), Assembler::traptoGreaterThanUnsigned | Assembler::traptoEqual,
-1, encoding);
}
return MacroAssembler::is_load_from_polling_page(long_at(0), NULL);
}

@ -30,8 +30,18 @@
#include <sys/mman.h>
void SafepointMechanism::pd_initialize() {
// No special code needed if we can use SIGTRAP
if (ThreadLocalHandshakes && USE_POLL_BIT_ONLY) {
default_initialize();
return;
}
// Allocate one protected page
char* map_address = (char*)MAP_FAILED;
const size_t page_size = os::vm_page_size();
const int prot = PROT_READ;
const int flags = MAP_PRIVATE | MAP_ANONYMOUS;
// Use optimized addresses for the polling page,
// e.g. map it to a special 32-bit address.
if (OptimizePollingPageLocation) {
@ -57,14 +67,14 @@ void SafepointMechanism::pd_initialize() {
// Try to map with current address wish.
// AIX: AIX needs MAP_FIXED if we provide an address and mmap will
// fail if the address is already mapped.
map_address = (char*) ::mmap(address_wishes[i] - (ssize_t)page_size,
page_size, PROT_READ,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
map_address = (char*) ::mmap(address_wishes[i],
page_size, prot,
flags | MAP_FIXED,
-1, 0);
log_debug(os)("SafePoint Polling Page address: %p (wish) => %p",
address_wishes[i], map_address + (ssize_t)page_size);
log_debug(os)("SafePoint Polling Page address: %p (wish) => %p",
address_wishes[i], map_address);
if (map_address + (ssize_t)page_size == address_wishes[i]) {
if (map_address == address_wishes[i]) {
// Map succeeded and map_address is at wished address, exit loop.
break;
}
@ -78,8 +88,17 @@ void SafepointMechanism::pd_initialize() {
}
}
if (map_address == (char*)MAP_FAILED) {
map_address = os::reserve_memory(page_size, NULL, page_size);
map_address = (char*) ::mmap(NULL, page_size, prot, flags, -1, 0);
}
guarantee(map_address != (char*)MAP_FAILED, "SafepointMechanism::pd_initialize: failed to allocate polling page");
log_info(os)("SafePoint Polling address: " INTPTR_FORMAT, p2i(map_address));
os::set_polling_page((address)(map_address));
// Use same page for ThreadLocalHandshakes without SIGTRAP
if (ThreadLocalHandshakes) {
set_uses_thread_local_poll();
intptr_t bad_page_val = reinterpret_cast<intptr_t>(map_address);
_poll_armed_value = reinterpret_cast<void*>(bad_page_val | poll_bit());
_poll_disarmed_value = NULL; // Readable on AIX
}
}

@ -47,6 +47,7 @@
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/osThread.hpp"
#include "runtime/safepointMechanism.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
@ -374,9 +375,12 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
goto run_stub;
}
else if (sig == SIGSEGV && os::is_poll_address(addr)) {
else if ((SafepointMechanism::uses_thread_local_poll() && USE_POLL_BIT_ONLY)
? (sig == SIGTRAP && ((NativeInstruction*)pc)->is_safepoint_poll())
: (sig == SIGSEGV && os::is_poll_address(addr))) {
if (TraceTraps) {
tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (SIGSEGV)", pc);
tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (%s)", p2i(pc),
(SafepointMechanism::uses_thread_local_poll() && USE_POLL_BIT_ONLY) ? "SIGTRAP" : "SIGSEGV");
}
stub = SharedRuntime::get_poll_stub(pc);
goto run_stub;

@ -46,6 +46,7 @@
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/osThread.hpp"
#include "runtime/safepointMechanism.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
@ -382,7 +383,7 @@ JVM_handle_linux_signal(int sig,
stub = SharedRuntime::get_handle_wrong_method_stub();
}
else if (sig == SIGSEGV &&
else if (sig == ((SafepointMechanism::uses_thread_local_poll() && USE_POLL_BIT_ONLY) ? SIGTRAP : SIGSEGV) &&
// A linux-ppc64 kernel before 2.6.6 doesn't set si_addr on some segfaults
// in 64bit mode (cf. http://www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.6),
// especially when we try to read from the safepoint polling page. So the check
@ -393,7 +394,8 @@ JVM_handle_linux_signal(int sig,
((cb = CodeCache::find_blob(pc)) != NULL) &&
cb->is_compiled()) {
if (TraceTraps) {
tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (SIGSEGV)", p2i(pc));
tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (%s)", p2i(pc),
(SafepointMechanism::uses_thread_local_poll() && USE_POLL_BIT_ONLY) ? "SIGTRAP" : "SIGSEGV");
}
stub = SharedRuntime::get_poll_stub(pc);
}

@ -36,23 +36,39 @@ void* SafepointMechanism::_poll_disarmed_value;
void SafepointMechanism::default_initialize() {
if (ThreadLocalHandshakes) {
set_uses_thread_local_poll();
const size_t page_size = os::vm_page_size();
const size_t allocation_size = 2 * page_size;
char* polling_page = os::reserve_memory(allocation_size, NULL, page_size);
os::commit_memory_or_exit(polling_page, allocation_size, false, "Unable to commit Safepoint polling page");
char* bad_page = polling_page;
char* good_page = polling_page + page_size;
// Poll bit values
intptr_t poll_armed_value = poll_bit();
intptr_t poll_disarmed_value = 0;
os::protect_memory(bad_page, page_size, os::MEM_PROT_NONE);
os::protect_memory(good_page, page_size, os::MEM_PROT_READ);
#ifdef USE_POLL_BIT_ONLY
if (!USE_POLL_BIT_ONLY)
#endif
{
// Polling page
const size_t page_size = os::vm_page_size();
const size_t allocation_size = 2 * page_size;
char* polling_page = os::reserve_memory(allocation_size, NULL, page_size);
os::commit_memory_or_exit(polling_page, allocation_size, false, "Unable to commit Safepoint polling page");
log_info(os)("SafePoint Polling address, bad (protected) page:" INTPTR_FORMAT ", good (unprotected) page:" INTPTR_FORMAT, p2i(bad_page), p2i(good_page));
os::set_polling_page((address)(bad_page));
char* bad_page = polling_page;
char* good_page = polling_page + page_size;
intptr_t poll_page_val = reinterpret_cast<intptr_t>(bad_page);
_poll_armed_value = reinterpret_cast<void*>(poll_page_val | poll_bit());
_poll_disarmed_value = good_page;
os::protect_memory(bad_page, page_size, os::MEM_PROT_NONE);
os::protect_memory(good_page, page_size, os::MEM_PROT_READ);
log_info(os)("SafePoint Polling address, bad (protected) page:" INTPTR_FORMAT ", good (unprotected) page:" INTPTR_FORMAT, p2i(bad_page), p2i(good_page));
os::set_polling_page((address)(bad_page));
// Poll address values
intptr_t bad_page_val = reinterpret_cast<intptr_t>(bad_page),
good_page_val = reinterpret_cast<intptr_t>(good_page);
poll_armed_value |= bad_page_val;
poll_disarmed_value |= good_page_val;
}
_poll_armed_value = reinterpret_cast<void*>(poll_armed_value);
_poll_disarmed_value = reinterpret_cast<void*>(poll_disarmed_value);
} else {
const size_t page_size = os::vm_page_size();
char* polling_page = os::reserve_memory(page_size, NULL, page_size);

@ -40,10 +40,7 @@ import jdk.test.lib.process.OutputAnalyzer;
public class OsCpuLoggingTest {
static void analyzeOutputForOsLog(OutputAnalyzer output) throws Exception {
// Aix has it's own logging
if (!Platform.isAix()) {
output.shouldContain("SafePoint Polling address");
}
output.shouldContain("SafePoint Polling address");
output.shouldHaveExitValue(0);
}
@ -58,7 +55,10 @@ public class OsCpuLoggingTest {
OutputAnalyzer output = new OutputAnalyzer(pb.start());
analyzeOutputForOsCpuLog(output);
pb = ProcessTools.createJavaProcessBuilder("-Xlog:os", "-version");
// PPC64 only uses polling pages when UseSIGTRAP is off.
pb = (Platform.isPPC() && Platform.is64bit())
? ProcessTools.createJavaProcessBuilder("-Xlog:os", "-XX:-UseSIGTRAP", "-version")
: ProcessTools.createJavaProcessBuilder("-Xlog:os", "-version");
output = new OutputAnalyzer(pb.start());
analyzeOutputForOsLog(output);
}