Merge
This commit is contained in:
commit
1344f54bde
@ -2213,7 +2213,7 @@ void os::jvm_path(char *buf, jint buflen) {
|
||||
if (rp == NULL)
|
||||
return;
|
||||
|
||||
if (strcmp(Arguments::sun_java_launcher(), "gamma") == 0) {
|
||||
if (Arguments::created_by_gamma_launcher()) {
|
||||
// Support for the gamma launcher. Typical value for buf is
|
||||
// "<JAVA_HOME>/jre/lib/<arch>/<vmtype>/libjvm.so". If "/jre/lib/" appears at
|
||||
// the right place in the string, then assume we are installed in a JDK and
|
||||
|
@ -59,3 +59,12 @@ void os::check_or_create_dump(void* exceptionRecord, void* contextRecord, char*
|
||||
VMError::report_coredump_status(buffer, success);
|
||||
}
|
||||
|
||||
bool os::is_debugger_attached() {
|
||||
// not implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
void os::wait_for_keypress_at_exit(void) {
|
||||
// don't do anything on posix platforms
|
||||
return;
|
||||
}
|
||||
|
@ -2511,7 +2511,7 @@ void os::jvm_path(char *buf, jint buflen) {
|
||||
assert(ret != 0, "cannot locate libjvm");
|
||||
realpath((char *)dlinfo.dli_fname, buf);
|
||||
|
||||
if (strcmp(Arguments::sun_java_launcher(), "gamma") == 0) {
|
||||
if (Arguments::created_by_gamma_launcher()) {
|
||||
// Support for the gamma launcher. Typical value for buf is
|
||||
// "<JAVA_HOME>/jre/lib/<arch>/<vmtype>/libjvm.so". If "/jre/lib/" appears at
|
||||
// the right place in the string, then assume we are installed in a JDK and
|
||||
|
@ -1788,7 +1788,7 @@ void os::jvm_path(char *buf, jint buflen) {
|
||||
}
|
||||
|
||||
buf[0] = '\0';
|
||||
if (strcmp(Arguments::sun_java_launcher(), "gamma") == 0) {
|
||||
if (Arguments::created_by_gamma_launcher()) {
|
||||
// Support for the gamma launcher. Check for an
|
||||
// JAVA_HOME environment variable
|
||||
// and fix up the path so it looks like
|
||||
@ -3418,6 +3418,19 @@ void os::win32::setmode_streams() {
|
||||
}
|
||||
|
||||
|
||||
bool os::is_debugger_attached() {
|
||||
return IsDebuggerPresent() ? true : false;
|
||||
}
|
||||
|
||||
|
||||
void os::wait_for_keypress_at_exit(void) {
|
||||
if (PauseAtExit) {
|
||||
fprintf(stderr, "Press any key to continue...\n");
|
||||
fgetc(stdin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int os::message_box(const char* title, const char* message) {
|
||||
int result = MessageBox(NULL, message, title,
|
||||
MB_YESNO | MB_ICONERROR | MB_SYSTEMMODAL | MB_DEFAULT_DESKTOP_ONLY);
|
||||
|
@ -1805,6 +1805,10 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, const jmethodID metho
|
||||
|
||||
void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
// In theory everyone coming thru here is in_vm but we need to be certain
|
||||
// because a callee will do a vm->native transition
|
||||
ThreadInVMfromUnknown __tiv;
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_DYNAMIC_CODE_GENERATED,
|
||||
("JVMTI [%s] method dynamic code generated event triggered",
|
||||
JvmtiTrace::safe_get_thread_name(thread)));
|
||||
@ -1826,19 +1830,18 @@ void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const v
|
||||
}
|
||||
|
||||
void JvmtiExport::post_dynamic_code_generated(const char *name, const void *code_begin, const void *code_end) {
|
||||
// In theory everyone coming thru here is in_vm but we need to be certain
|
||||
// because a callee will do a vm->native transition
|
||||
ThreadInVMfromUnknown __tiv;
|
||||
jvmtiPhase phase = JvmtiEnv::get_phase();
|
||||
if (phase == JVMTI_PHASE_PRIMORDIAL || phase == JVMTI_PHASE_START) {
|
||||
post_dynamic_code_generated_internal(name, code_begin, code_end);
|
||||
return;
|
||||
} else {
|
||||
// It may not be safe to post the event from this thread. Defer all
|
||||
// postings to the service thread so that it can perform them in a safe
|
||||
// context and in-order.
|
||||
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
JvmtiDeferredEvent event = JvmtiDeferredEvent::dynamic_code_generated_event(
|
||||
name, code_begin, code_end);
|
||||
JvmtiDeferredEventQueue::enqueue(event);
|
||||
}
|
||||
|
||||
// Blocks until everything now in the queue has been posted
|
||||
JvmtiDeferredEventQueue::flush_queue(Thread::current());
|
||||
|
||||
post_dynamic_code_generated_internal(name, code_begin, code_end);
|
||||
}
|
||||
|
||||
|
||||
|
@ -140,12 +140,12 @@ class JvmtiExport : public AllStatic {
|
||||
char sig_type, jvalue *value);
|
||||
|
||||
|
||||
private:
|
||||
// posts a DynamicCodeGenerated event (internal/private implementation).
|
||||
// The public post_dynamic_code_generated* functions make use of the
|
||||
// internal implementation.
|
||||
// internal implementation. Also called from JvmtiDeferredEvent::post()
|
||||
static void post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) KERNEL_RETURN;
|
||||
|
||||
private:
|
||||
|
||||
// GenerateEvents support to allow posting of CompiledMethodLoad and
|
||||
// DynamicCodeGenerated events for a given environment.
|
||||
|
@ -918,7 +918,7 @@ void JvmtiSuspendControl::print() {
|
||||
JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event(
|
||||
nmethod* nm) {
|
||||
JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD);
|
||||
event.set_compiled_method_load(nm);
|
||||
event._event_data.compiled_method_load = nm;
|
||||
nmethodLocker::lock_nmethod(nm); // will be unlocked when posted
|
||||
return event;
|
||||
}
|
||||
@ -926,23 +926,39 @@ JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event(
|
||||
JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_unload_event(
|
||||
jmethodID id, const void* code) {
|
||||
JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_UNLOAD);
|
||||
event.set_compiled_method_unload(id, code);
|
||||
event._event_data.compiled_method_unload.method_id = id;
|
||||
event._event_data.compiled_method_unload.code_begin = code;
|
||||
return event;
|
||||
}
|
||||
JvmtiDeferredEvent JvmtiDeferredEvent::dynamic_code_generated_event(
|
||||
const char* name, const void* code_begin, const void* code_end) {
|
||||
JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_DYNAMIC_CODE_GENERATED);
|
||||
event._event_data.dynamic_code_generated.name = name;
|
||||
event._event_data.dynamic_code_generated.code_begin = code_begin;
|
||||
event._event_data.dynamic_code_generated.code_end = code_end;
|
||||
return event;
|
||||
}
|
||||
|
||||
void JvmtiDeferredEvent::post() {
|
||||
assert(ServiceThread::is_service_thread(Thread::current()),
|
||||
"Service thread must post enqueued events");
|
||||
switch(_type) {
|
||||
case TYPE_COMPILED_METHOD_LOAD:
|
||||
JvmtiExport::post_compiled_method_load(compiled_method_load());
|
||||
nmethodLocker::unlock_nmethod(compiled_method_load());
|
||||
case TYPE_COMPILED_METHOD_LOAD: {
|
||||
nmethod* nm = _event_data.compiled_method_load;
|
||||
JvmtiExport::post_compiled_method_load(nm);
|
||||
nmethodLocker::unlock_nmethod(nm);
|
||||
break;
|
||||
}
|
||||
case TYPE_COMPILED_METHOD_UNLOAD:
|
||||
JvmtiExport::post_compiled_method_unload(
|
||||
compiled_method_unload_method_id(),
|
||||
compiled_method_unload_code_begin());
|
||||
_event_data.compiled_method_unload.method_id,
|
||||
_event_data.compiled_method_unload.code_begin);
|
||||
break;
|
||||
case TYPE_FLUSH:
|
||||
JvmtiDeferredEventQueue::flush_complete(flush_state_addr());
|
||||
case TYPE_DYNAMIC_CODE_GENERATED:
|
||||
JvmtiExport::post_dynamic_code_generated_internal(
|
||||
_event_data.dynamic_code_generated.name,
|
||||
_event_data.dynamic_code_generated.code_begin,
|
||||
_event_data.dynamic_code_generated.code_end);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
@ -1065,54 +1081,4 @@ void JvmtiDeferredEventQueue::process_pending_events() {
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
// Random - used for debugging
|
||||
FLUSHING = 0x50403020,
|
||||
FLUSHED = 0x09080706
|
||||
};
|
||||
|
||||
void JvmtiDeferredEventQueue::flush_queue(Thread* thread) {
|
||||
|
||||
volatile int flush_state = FLUSHING;
|
||||
|
||||
JvmtiDeferredEvent flush(JvmtiDeferredEvent::TYPE_FLUSH);
|
||||
flush.set_flush_state_addr((int*)&flush_state);
|
||||
|
||||
if (ServiceThread::is_service_thread(thread)) {
|
||||
// If we are the service thread we have to post all preceding events
|
||||
// Use the flush event as a token to indicate when we can stop
|
||||
JvmtiDeferredEvent event;
|
||||
{
|
||||
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
enqueue(flush);
|
||||
event = dequeue();
|
||||
}
|
||||
while (!event.is_flush_event() ||
|
||||
event.flush_state_addr() != &flush_state) {
|
||||
event.post();
|
||||
{
|
||||
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
event = dequeue();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Wake up the service thread so it will process events. When it gets
|
||||
// to the flush event it will set 'flush_complete' and notify us.
|
||||
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
enqueue(flush);
|
||||
while (flush_state != FLUSHED) {
|
||||
assert(flush_state == FLUSHING || flush_state == FLUSHED,
|
||||
"only valid values for this");
|
||||
Service_lock->wait(Mutex::_no_safepoint_check_flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JvmtiDeferredEventQueue::flush_complete(int* state_addr) {
|
||||
assert(state_addr != NULL && *state_addr == FLUSHING, "must be");
|
||||
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
*state_addr = FLUSHED;
|
||||
Service_lock->notify_all();
|
||||
}
|
||||
|
||||
#endif // ndef KERNEL
|
||||
|
@ -451,7 +451,7 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC {
|
||||
TYPE_NONE,
|
||||
TYPE_COMPILED_METHOD_LOAD,
|
||||
TYPE_COMPILED_METHOD_UNLOAD,
|
||||
TYPE_FLUSH // pseudo-event used to implement flush_queue()
|
||||
TYPE_DYNAMIC_CODE_GENERATED
|
||||
} Type;
|
||||
|
||||
Type _type;
|
||||
@ -461,49 +461,15 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC {
|
||||
jmethodID method_id;
|
||||
const void* code_begin;
|
||||
} compiled_method_unload;
|
||||
int* flush_state_addr;
|
||||
struct {
|
||||
const char* name;
|
||||
const void* code_begin;
|
||||
const void* code_end;
|
||||
} dynamic_code_generated;
|
||||
} _event_data;
|
||||
|
||||
JvmtiDeferredEvent(Type t) : _type(t) {}
|
||||
|
||||
void set_compiled_method_load(nmethod* nm) {
|
||||
assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be");
|
||||
_event_data.compiled_method_load = nm;
|
||||
}
|
||||
|
||||
nmethod* compiled_method_load() const {
|
||||
assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be");
|
||||
return _event_data.compiled_method_load;
|
||||
}
|
||||
|
||||
void set_compiled_method_unload(jmethodID id, const void* code) {
|
||||
assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be");
|
||||
_event_data.compiled_method_unload.method_id = id;
|
||||
_event_data.compiled_method_unload.code_begin = code;
|
||||
}
|
||||
|
||||
jmethodID compiled_method_unload_method_id() const {
|
||||
assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be");
|
||||
return _event_data.compiled_method_unload.method_id;
|
||||
}
|
||||
|
||||
const void* compiled_method_unload_code_begin() const {
|
||||
assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be");
|
||||
return _event_data.compiled_method_unload.code_begin;
|
||||
}
|
||||
|
||||
bool is_flush_event() const { return _type == TYPE_FLUSH; }
|
||||
|
||||
int* flush_state_addr() const {
|
||||
assert(is_flush_event(), "must be");
|
||||
return _event_data.flush_state_addr;
|
||||
}
|
||||
|
||||
void set_flush_state_addr(int* flag) {
|
||||
assert(is_flush_event(), "must be");
|
||||
_event_data.flush_state_addr = flag;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
JvmtiDeferredEvent() : _type(TYPE_NONE) {}
|
||||
@ -513,6 +479,9 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC {
|
||||
KERNEL_RETURN_(JvmtiDeferredEvent());
|
||||
static JvmtiDeferredEvent compiled_method_unload_event(
|
||||
jmethodID id, const void* code) KERNEL_RETURN_(JvmtiDeferredEvent());
|
||||
static JvmtiDeferredEvent dynamic_code_generated_event(
|
||||
const char* name, const void* begin, const void* end)
|
||||
KERNEL_RETURN_(JvmtiDeferredEvent());
|
||||
|
||||
// Actually posts the event.
|
||||
void post() KERNEL_RETURN;
|
||||
@ -548,25 +517,12 @@ class JvmtiDeferredEventQueue : AllStatic {
|
||||
// Transfers events from the _pending_list to the _queue.
|
||||
static void process_pending_events() KERNEL_RETURN;
|
||||
|
||||
static void flush_complete(int* flush_state) KERNEL_RETURN;
|
||||
|
||||
public:
|
||||
// Must be holding Service_lock when calling these
|
||||
static bool has_events() KERNEL_RETURN_(false);
|
||||
static void enqueue(const JvmtiDeferredEvent& event) KERNEL_RETURN;
|
||||
static JvmtiDeferredEvent dequeue() KERNEL_RETURN_(JvmtiDeferredEvent());
|
||||
|
||||
// This call blocks until all events enqueued prior to this call
|
||||
// have been posted. The Service_lock is acquired and waited upon.
|
||||
//
|
||||
// Implemented by creating a "flush" event and placing it in the queue.
|
||||
// When the flush event is "posted" it will call flush_complete(), which
|
||||
// will release the caller.
|
||||
//
|
||||
// Can be called by any thread (maybe even the service thread itself).
|
||||
// Not necessary for the caller to be a JavaThread.
|
||||
static void flush_queue(Thread* current) KERNEL_RETURN;
|
||||
|
||||
// Used to enqueue events without using a lock, for times (such as during
|
||||
// safepoint) when we can't or don't want to lock the Service_lock.
|
||||
//
|
||||
|
@ -78,6 +78,7 @@ bool Arguments::_xdebug_mode = false;
|
||||
const char* Arguments::_java_vendor_url_bug = DEFAULT_VENDOR_URL_BUG;
|
||||
const char* Arguments::_sun_java_launcher = DEFAULT_JAVA_LAUNCHER;
|
||||
int Arguments::_sun_java_launcher_pid = -1;
|
||||
bool Arguments::_created_by_gamma_launcher = false;
|
||||
|
||||
// These parameters are reset in method parse_vm_init_args(JavaVMInitArgs*)
|
||||
bool Arguments::_AlwaysCompileLoopMethods = AlwaysCompileLoopMethods;
|
||||
@ -1656,6 +1657,9 @@ void Arguments::process_java_compiler_argument(char* arg) {
|
||||
|
||||
void Arguments::process_java_launcher_argument(const char* launcher, void* extra_info) {
|
||||
_sun_java_launcher = strdup(launcher);
|
||||
if (strcmp("gamma", _sun_java_launcher) == 0) {
|
||||
_created_by_gamma_launcher = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Arguments::created_by_java_launcher() {
|
||||
@ -1663,6 +1667,10 @@ bool Arguments::created_by_java_launcher() {
|
||||
return strcmp(DEFAULT_JAVA_LAUNCHER, _sun_java_launcher) != 0;
|
||||
}
|
||||
|
||||
bool Arguments::created_by_gamma_launcher() {
|
||||
return _created_by_gamma_launcher;
|
||||
}
|
||||
|
||||
//===========================================================================================================
|
||||
// Parsing of main arguments
|
||||
|
||||
@ -3155,6 +3163,16 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
|
||||
}
|
||||
}
|
||||
|
||||
// set PauseAtExit if the gamma launcher was used and a debugger is attached
|
||||
// but only if not already set on the commandline
|
||||
if (Arguments::created_by_gamma_launcher() && os::is_debugger_attached()) {
|
||||
bool set = false;
|
||||
CommandLineFlags::wasSetOnCmdline("PauseAtExit", &set);
|
||||
if (!set) {
|
||||
FLAG_SET_DEFAULT(PauseAtExit, true);
|
||||
}
|
||||
}
|
||||
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -257,6 +257,9 @@ class Arguments : AllStatic {
|
||||
// sun.java.launcher.pid, private property
|
||||
static int _sun_java_launcher_pid;
|
||||
|
||||
// was this VM created by the gamma launcher
|
||||
static bool _created_by_gamma_launcher;
|
||||
|
||||
// Option flags
|
||||
static bool _has_profile;
|
||||
static bool _has_alloc_profile;
|
||||
@ -444,6 +447,8 @@ class Arguments : AllStatic {
|
||||
static const char* sun_java_launcher() { return _sun_java_launcher; }
|
||||
// Was VM created by a Java launcher?
|
||||
static bool created_by_java_launcher();
|
||||
// Was VM created by the gamma Java launcher?
|
||||
static bool created_by_gamma_launcher();
|
||||
// -Dsun.java.launcher.pid
|
||||
static int sun_java_launcher_pid() { return _sun_java_launcher_pid; }
|
||||
|
||||
|
@ -3733,6 +3733,9 @@ class CommandLineFlags {
|
||||
"The file to create and for whose removal to await when pausing " \
|
||||
"at startup. (default: ./vm.paused.<pid>)") \
|
||||
\
|
||||
diagnostic(bool, PauseAtExit, false, \
|
||||
"Pause and wait for keypress on exit if a debugger is attached") \
|
||||
\
|
||||
product(bool, ExtendedDTraceProbes, false, \
|
||||
"Enable performance-impacting dtrace probes") \
|
||||
\
|
||||
|
@ -551,6 +551,7 @@ void notify_vm_shutdown() {
|
||||
|
||||
void vm_direct_exit(int code) {
|
||||
notify_vm_shutdown();
|
||||
os::wait_for_keypress_at_exit();
|
||||
::exit(code);
|
||||
}
|
||||
|
||||
@ -577,11 +578,13 @@ void vm_perform_shutdown_actions() {
|
||||
void vm_shutdown()
|
||||
{
|
||||
vm_perform_shutdown_actions();
|
||||
os::wait_for_keypress_at_exit();
|
||||
os::shutdown();
|
||||
}
|
||||
|
||||
void vm_abort(bool dump_core) {
|
||||
vm_perform_shutdown_actions();
|
||||
os::wait_for_keypress_at_exit();
|
||||
os::abort(dump_core);
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
@ -492,6 +492,12 @@ class os: AllStatic {
|
||||
static void print_location(outputStream* st, intptr_t x, bool verbose = false);
|
||||
static size_t lasterror(char *buf, size_t len);
|
||||
|
||||
// Determines whether the calling process is being debugged by a user-mode debugger.
|
||||
static bool is_debugger_attached();
|
||||
|
||||
// wait for a key press if PauseAtExit is set
|
||||
static void wait_for_keypress_at_exit(void);
|
||||
|
||||
// The following two functions are used by fatal error handler to trace
|
||||
// native (C) frames. They are not part of frame.hpp/frame.cpp because
|
||||
// frame.hpp/cpp assume thread is JavaThread, and also because different
|
||||
|
@ -3644,6 +3644,7 @@ bool Threads::destroy_vm() {
|
||||
if (ShowMessageBoxOnError && is_error_reported()) {
|
||||
os::infinite_sleep();
|
||||
}
|
||||
os::wait_for_keypress_at_exit();
|
||||
|
||||
if (JDK_Version::is_jdk12x_version()) {
|
||||
// We are the last thread running, so check if finalizers should be run.
|
||||
|
@ -802,7 +802,7 @@ void VMError::report_and_die() {
|
||||
first_error_tid = mytid;
|
||||
set_error_reported();
|
||||
|
||||
if (ShowMessageBoxOnError) {
|
||||
if (ShowMessageBoxOnError || PauseAtExit) {
|
||||
show_message_box(buffer, sizeof(buffer));
|
||||
|
||||
// User has asked JVM to abort. Reset ShowMessageBoxOnError so the
|
||||
|
Loading…
Reference in New Issue
Block a user