Discussion:
JDK-8176828: jtools do not list VM process launched with the debugger option suspend=y
Gary Adams
2018-11-28 16:33:15 UTC
Permalink
I'd like to close JDK-8176828 as will not fix.
https://bugs.openjdk.java.net/browse/JDK-8176828

This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.

The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.

In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.

Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.

=====
src/hotspot/share/runtime/:
src/jdk.jdwp.agent/share/native/libjdwp/:

thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args, bool*
canTryAgain) {
...
thread.cpp:3610: create_vm_timer.start();
...
thread.cpp:3907: JvmtiExport::post_vm_initialized();
...
debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv *env,
jthread thread)
...
debugInit.c:103:static void initialize(JNIEnv *env, jthread thread,
EventIndex triggering_ei);
...
debugInit.c:732: (void)bagEnumerateOver(transports,
startTransport, &arg);
...
debugInit.c:751: transport_waitForConnection();
...
thread.cpp:3955: create_vm_timer.end();

====
src/hotspot/share/services/management.cpp:

203 void Management::record_vm_startup_time(jlong begin, jlong
duration) {
204 // if the performance counter is not initialized,
205 // then vm initialization failed; simply return.
206 if (_begin_vm_creation_time == NULL) return;
207
208 _begin_vm_creation_time->set_value(begin);
209 _end_vm_creation_time->set_value(begin + duration);
210 PerfMemory::set_accessible(true);
211 }
Chris Plummer
2018-11-28 18:11:31 UTC
Permalink
Hi Gary,

This seems reasonable. I just want clarification on one thing first.
Before JDK-8176828, it listed the suspend=y process, but could you do
anything with it? I'm assuming no, and therefore it makes sense not to
list it at all.

thanks,

Chris
Post by Gary Adams
I'd like to close JDK-8176828 as will not fix.
  https://bugs.openjdk.java.net/browse/JDK-8176828
This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.
The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.
In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.
Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.
=====
  thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args, bool*
canTryAgain) {
  ...
  thread.cpp:3610:  create_vm_timer.start();
  ...
  thread.cpp:3907:  JvmtiExport::post_vm_initialized();
  ...
    debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv *env,
jthread thread)
    ...
    debugInit.c:103:static void initialize(JNIEnv *env, jthread
thread, EventIndex triggering_ei);
    ...
    debugInit.c:732:    (void)bagEnumerateOver(transports,
startTransport, &arg);
    ...
    debugInit.c:751:    transport_waitForConnection();
  ...
  thread.cpp:3955:  create_vm_timer.end();
====
   203  void Management::record_vm_startup_time(jlong begin, jlong
duration) {
   204    // if the performance counter is not initialized,
   205    // then vm initialization failed; simply return.
   206    if (_begin_vm_creation_time == NULL) return;
   207
   208    _begin_vm_creation_time->set_value(begin);
   209    _end_vm_creation_time->set_value(begin + duration);
   210    PerfMemory::set_accessible(true);
   211  }
Chris Plummer
2018-11-28 19:29:26 UTC
Permalink
Sorry, meant to say "before JDK-8176533".

Chris
Post by Chris Plummer
Hi Gary,
This seems reasonable. I just want clarification on one thing first.
Before JDK-8176828, it listed the suspend=y process, but could you do
anything with it? I'm assuming no, and therefore it makes sense not to
list it at all.
thanks,
Chris
Post by Gary Adams
I'd like to close JDK-8176828 as will not fix.
  https://bugs.openjdk.java.net/browse/JDK-8176828
This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.
The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.
In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.
Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.
=====
  thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args, bool*
canTryAgain) {
  ...
  thread.cpp:3610:  create_vm_timer.start();
  ...
  thread.cpp:3907:  JvmtiExport::post_vm_initialized();
  ...
    debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv *env,
jthread thread)
    ...
    debugInit.c:103:static void initialize(JNIEnv *env, jthread
thread, EventIndex triggering_ei);
    ...
    debugInit.c:732:    (void)bagEnumerateOver(transports,
startTransport, &arg);
    ...
    debugInit.c:751:    transport_waitForConnection();
  ...
  thread.cpp:3955:  create_vm_timer.end();
====
   203  void Management::record_vm_startup_time(jlong begin, jlong
duration) {
   204    // if the performance counter is not initialized,
   205    // then vm initialization failed; simply return.
   206    if (_begin_vm_creation_time == NULL) return;
   207
   208    _begin_vm_creation_time->set_value(begin);
   209    _end_vm_creation_time->set_value(begin + duration);
   210    PerfMemory::set_accessible(true);
   211  }
Gary Adams
2018-11-28 19:52:52 UTC
Permalink
https://bugs.openjdk.java.net/browse/JDK-8156537
- Added a fix for module naming

https://bugs.openjdk.java.net/browse/JDK-8176533
- Fixed a regression from JDK-816537 that prevented "jcmd <pid> <cmd>"
from sending <cmd> to <pid>

https://bugs.openjdk.java.net/browse/JDK-8176828
- Requests that "jcmd -l" should list the <pid>
for the VM that has not completed initialization.
This is not a regression, because jdk8 jcmd did
not display the uninitialized VM either.

It appears you can send "jcmd <pid> <cmd>" to
the process that has not completed vm initialization.
Post by Chris Plummer
Sorry, meant to say "before JDK-8176533".
Chris
Post by Chris Plummer
Hi Gary,
This seems reasonable. I just want clarification on one thing first.
Before JDK-8176828, it listed the suspend=y process, but could you do
anything with it? I'm assuming no, and therefore it makes sense not
to list it at all.
thanks,
Chris
Post by Gary Adams
I'd like to close JDK-8176828 as will not fix.
https://bugs.openjdk.java.net/browse/JDK-8176828
This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.
The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.
In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.
Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.
=====
thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args,
bool* canTryAgain) {
...
thread.cpp:3610: create_vm_timer.start();
...
thread.cpp:3907: JvmtiExport::post_vm_initialized();
...
debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv *env,
jthread thread)
...
debugInit.c:103:static void initialize(JNIEnv *env, jthread
thread, EventIndex triggering_ei);
...
debugInit.c:732: (void)bagEnumerateOver(transports,
startTransport, &arg);
...
debugInit.c:751: transport_waitForConnection();
...
thread.cpp:3955: create_vm_timer.end();
====
203 void Management::record_vm_startup_time(jlong begin, jlong
duration) {
204 // if the performance counter is not initialized,
205 // then vm initialization failed; simply return.
206 if (_begin_vm_creation_time == NULL) return;
207
208 _begin_vm_creation_time->set_value(begin);
209 _end_vm_creation_time->set_value(begin + duration);
210 PerfMemory::set_accessible(true);
211 }
Chris Plummer
2018-11-28 21:12:29 UTC
Permalink
Post by Gary Adams
https://bugs.openjdk.java.net/browse/JDK-8156537
  - Added a fix for module naming
https://bugs.openjdk.java.net/browse/JDK-8176533
  - Fixed a regression from JDK-816537 that prevented "jcmd <pid> <cmd>"
     from sending <cmd> to <pid>
https://bugs.openjdk.java.net/browse/JDK-8176828
  - Requests that "jcmd -l" should list the <pid>
     for the VM that has not completed initialization.
     This is not a regression, because jdk8 jcmd did
     not display the uninitialized VM either.
It appears you can send "jcmd <pid> <cmd>" to
the process that has not completed vm initialization.
So what happens when you do this?

Chris
Post by Gary Adams
Post by Chris Plummer
Sorry, meant to say "before JDK-8176533".
Chris
Post by Chris Plummer
Hi Gary,
This seems reasonable. I just want clarification on one thing first.
Before JDK-8176828, it listed the suspend=y process, but could you
do anything with it? I'm assuming no, and therefore it makes sense
not to list it at all.
thanks,
Chris
Post by Gary Adams
I'd like to close JDK-8176828 as will not fix.
  https://bugs.openjdk.java.net/browse/JDK-8176828
This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.
The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.
In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.
Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.
=====
  thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args,
bool* canTryAgain) {
  ...
  thread.cpp:3610:  create_vm_timer.start();
  ...
  thread.cpp:3907:  JvmtiExport::post_vm_initialized();
  ...
    debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv *env,
jthread thread)
    ...
    debugInit.c:103:static void initialize(JNIEnv *env, jthread
thread, EventIndex triggering_ei);
    ...
    debugInit.c:732:    (void)bagEnumerateOver(transports,
startTransport, &arg);
    ...
    debugInit.c:751:    transport_waitForConnection();
  ...
  thread.cpp:3955:  create_vm_timer.end();
====
   203  void Management::record_vm_startup_time(jlong begin, jlong
duration) {
   204    // if the performance counter is not initialized,
   205    // then vm initialization failed; simply return.
   206    if (_begin_vm_creation_time == NULL) return;
   207
   208    _begin_vm_creation_time->set_value(begin);
   209    _end_vm_creation_time->set_value(begin + duration);
   210    PerfMemory::set_accessible(true);
   211  }
g***@oracle.com
2018-11-28 23:41:20 UTC
Permalink
Post by Chris Plummer
Post by Gary Adams
https://bugs.openjdk.java.net/browse/JDK-8156537
  - Added a fix for module naming
https://bugs.openjdk.java.net/browse/JDK-8176533
  - Fixed a regression from JDK-816537 that prevented "jcmd <pid> <cmd>"
     from sending <cmd> to <pid>
https://bugs.openjdk.java.net/browse/JDK-8176828
  - Requests that "jcmd -l" should list the <pid>
     for the VM that has not completed initialization.
     This is not a regression, because jdk8 jcmd did
     not display the uninitialized VM either.
It appears you can send "jcmd <pid> <cmd>" to
the process that has not completed vm initialization.
So what happens when you do this?
The commands work, albeit the vm thread is blocked waiting for the
debugger connection.
Post by Chris Plummer
Chris
Post by Gary Adams
Post by Chris Plummer
Sorry, meant to say "before JDK-8176533".
Chris
Post by Chris Plummer
Hi Gary,
This seems reasonable. I just want clarification on one thing
first. Before JDK-8176828, it listed the suspend=y process, but
could you do anything with it? I'm assuming no, and therefore it
makes sense not to list it at all.
thanks,
Chris
Post by Gary Adams
I'd like to close JDK-8176828 as will not fix.
  https://bugs.openjdk.java.net/browse/JDK-8176828
This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.
The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.
In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.
Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.
=====
  thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args,
bool* canTryAgain) {
  ...
  thread.cpp:3610:  create_vm_timer.start();
  ...
  thread.cpp:3907:  JvmtiExport::post_vm_initialized();
  ...
    debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv
*env, jthread thread)
    ...
    debugInit.c:103:static void initialize(JNIEnv *env, jthread
thread, EventIndex triggering_ei);
    ...
    debugInit.c:732:    (void)bagEnumerateOver(transports,
startTransport, &arg);
    ...
    debugInit.c:751:    transport_waitForConnection();
  ...
  thread.cpp:3955:  create_vm_timer.end();
====
   203  void Management::record_vm_startup_time(jlong begin, jlong
duration) {
   204    // if the performance counter is not initialized,
   205    // then vm initialization failed; simply return.
   206    if (_begin_vm_creation_time == NULL) return;
   207
   208    _begin_vm_creation_time->set_value(begin);
   209    _end_vm_creation_time->set_value(begin + duration);
   210    PerfMemory::set_accessible(true);
   211  }
David Holmes
2018-11-29 04:10:30 UTC
Permalink
I've been lurking on this ...
Post by g***@oracle.com
Post by Chris Plummer
Post by Gary Adams
https://bugs.openjdk.java.net/browse/JDK-8156537
  - Added a fix for module naming
https://bugs.openjdk.java.net/browse/JDK-8176533
  - Fixed a regression from JDK-816537 that prevented "jcmd <pid> <cmd>"
     from sending <cmd> to <pid>
https://bugs.openjdk.java.net/browse/JDK-8176828
  - Requests that "jcmd -l" should list the <pid>
     for the VM that has not completed initialization.
     This is not a regression, because jdk8 jcmd did
     not display the uninitialized VM either.
It appears you can send "jcmd <pid> <cmd>" to
the process that has not completed vm initialization.
So what happens when you do this?
The commands work, albeit the vm thread is blocked waiting for the
debugger connection.
Define "work". If the VM is partially initialized there is very little
that can be examined. If the VMThread is blocked on the debugger
connection then you can't do anything that requires a VM operation
(which includes safepoints - though at this stage if there are no
JavaThreads we're safe anyway).

Thanks,
David
Post by g***@oracle.com
Post by Chris Plummer
Chris
Post by Gary Adams
Post by Chris Plummer
Sorry, meant to say "before JDK-8176533".
Chris
Post by Chris Plummer
Hi Gary,
This seems reasonable. I just want clarification on one thing
first. Before JDK-8176828, it listed the suspend=y process, but
could you do anything with it? I'm assuming no, and therefore it
makes sense not to list it at all.
thanks,
Chris
Post by Gary Adams
I'd like to close JDK-8176828 as will not fix.
  https://bugs.openjdk.java.net/browse/JDK-8176828
This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.
The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.
In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.
Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.
=====
  thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args,
bool* canTryAgain) {
  ...
  thread.cpp:3610:  create_vm_timer.start();
  ...
  thread.cpp:3907:  JvmtiExport::post_vm_initialized();
  ...
    debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv
*env, jthread thread)
    ...
    debugInit.c:103:static void initialize(JNIEnv *env, jthread
thread, EventIndex triggering_ei);
    ...
    debugInit.c:732:    (void)bagEnumerateOver(transports,
startTransport, &arg);
    ...
    debugInit.c:751:    transport_waitForConnection();
  ...
  thread.cpp:3955:  create_vm_timer.end();
====
   203  void Management::record_vm_startup_time(jlong begin, jlong
duration) {
   204    // if the performance counter is not initialized,
   205    // then vm initialization failed; simply return.
   206    if (_begin_vm_creation_time == NULL) return;
   207
   208    _begin_vm_creation_time->set_value(begin);
   209    _end_vm_creation_time->set_value(begin + duration);
   210    PerfMemory::set_accessible(true);
   211  }
g***@oracle.com
2018-11-30 10:03:48 UTC
Permalink
It turns out that almost all the diagnostic commands provide
meaningful output even though the vm thread is not totally
initialized.

We could declare the perfmemory initialized a little earlier ...

diff --git a/src/hotspot/share/runtime/thread.cpp
b/src/hotspot/share/runtime/thread.cpp
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -3902,6 +3902,9 @@
   // may be attached late and JVMTI must track phases of VM execution
   JvmtiExport::enter_live_phase();

+  // Make perfmemory accessible
+  create_vm_timer.end();
+
   // Notify JVMTI agents that VM initialization is complete - nop if
no agents.
   JvmtiExport::post_vm_initialized();

@@ -3951,7 +3954,6 @@
     }
   }

-  create_vm_timer.end();
 #ifdef ASSERT
   _vm_complete = true;
 #endif

This would be the "jcmd -l" output when the post_vm_initialized()
would block on the "suspend=y" processing

23732 jdk.jcmd/sun.tools.jcmd.JCmd -l
22526 Unknown

... when the debugger attaches "jdb -attach 5900"

23771 jdk.jdi/com.sun.tools.example.debug.tty.TTY -attach 5900
23884 jdk.jcmd/sun.tools.jcmd.JCmd -l
22526 Unknown

... when the debugger starts with the "run" command

23922 jdk.jcmd/sun.tools.jcmd.JCmd -l
23771 jdk.jdi/com.sun.tools.example.debug.tty.TTY -attach 5900
22526 my

We could also pull out the perfmemory set accessible step
and set it explicitly.

...
Post by David Holmes
I've been lurking on this ...
Post by g***@oracle.com
Post by Chris Plummer
Post by Gary Adams
https://bugs.openjdk.java.net/browse/JDK-8156537
  - Added a fix for module naming
https://bugs.openjdk.java.net/browse/JDK-8176533
  - Fixed a regression from JDK-816537 that prevented "jcmd <pid> <cmd>"
     from sending <cmd> to <pid>
https://bugs.openjdk.java.net/browse/JDK-8176828
  - Requests that "jcmd -l" should list the <pid>
     for the VM that has not completed initialization.
     This is not a regression, because jdk8 jcmd did
     not display the uninitialized VM either.
It appears you can send "jcmd <pid> <cmd>" to
the process that has not completed vm initialization.
So what happens when you do this?
The commands work, albeit the vm thread is blocked waiting for the
debugger connection.
Define "work". If the VM is partially initialized there is very little
that can be examined. If the VMThread is blocked on the debugger
connection then you can't do anything that requires a VM operation
(which includes safepoints - though at this stage if there are no
JavaThreads we're safe anyway).
Thanks,
David
Post by g***@oracle.com
Post by Chris Plummer
Chris
Post by Gary Adams
Post by Chris Plummer
Sorry, meant to say "before JDK-8176533".
Chris
Post by Chris Plummer
Hi Gary,
This seems reasonable. I just want clarification on one thing
first. Before JDK-8176828, it listed the suspend=y process, but
could you do anything with it? I'm assuming no, and therefore it
makes sense not to list it at all.
thanks,
Chris
Post by Gary Adams
I'd like to close JDK-8176828 as will not fix.
  https://bugs.openjdk.java.net/browse/JDK-8176828
This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.
The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.
In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.
Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.
=====
  thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args,
bool* canTryAgain) {
  ...
  thread.cpp:3610:  create_vm_timer.start();
  ...
  thread.cpp:3907: JvmtiExport::post_vm_initialized();
  ...
    debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv
*env, jthread thread)
    ...
    debugInit.c:103:static void initialize(JNIEnv *env, jthread
thread, EventIndex triggering_ei);
    ...
    debugInit.c:732: (void)bagEnumerateOver(transports,
startTransport, &arg);
    ...
    debugInit.c:751:    transport_waitForConnection();
  ...
  thread.cpp:3955:  create_vm_timer.end();
====
   203  void Management::record_vm_startup_time(jlong begin,
jlong duration) {
   204    // if the performance counter is not initialized,
   205    // then vm initialization failed; simply return.
   206    if (_begin_vm_creation_time == NULL) return;
   207
   208 _begin_vm_creation_time->set_value(begin);
   209    _end_vm_creation_time->set_value(begin + duration);
   210    PerfMemory::set_accessible(true);
   211  }
Gary Adams
2018-11-30 12:38:08 UTC
Permalink
Here's a smaller change. I'll run through a bunch of serviceability
tests to make sure
this early accessible setting does not have any unexpected side effects..

diff --git a/src/hotspot/share/runtime/thread.cpp
b/src/hotspot/share/runtime/thread.cpp
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -3902,6 +3902,9 @@
// may be attached late and JVMTI must track phases of VM execution
JvmtiExport::enter_live_phase();

+ // Make perfmemory accessible
+ PerfMemory::set_accessible(true);
+
// Notify JVMTI agents that VM initialization is complete - nop if
no agents.
JvmtiExport::post_vm_initialized();
Post by g***@oracle.com
It turns out that almost all the diagnostic commands provide
meaningful output even though the vm thread is not totally
initialized.
We could declare the perfmemory initialized a little earlier ...
diff --git a/src/hotspot/share/runtime/thread.cpp
b/src/hotspot/share/runtime/thread.cpp
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -3902,6 +3902,9 @@
// may be attached late and JVMTI must track phases of VM execution
JvmtiExport::enter_live_phase();
+ // Make perfmemory accessible
+ create_vm_timer.end();
+
// Notify JVMTI agents that VM initialization is complete - nop if
no agents.
JvmtiExport::post_vm_initialized();
@@ -3951,7 +3954,6 @@
}
}
- create_vm_timer.end();
#ifdef ASSERT
_vm_complete = true;
#endif
This would be the "jcmd -l" output when the post_vm_initialized()
would block on the "suspend=y" processing
23732 jdk.jcmd/sun.tools.jcmd.JCmd -l
22526 Unknown
... when the debugger attaches "jdb -attach 5900"
23771 jdk.jdi/com.sun.tools.example.debug.tty.TTY -attach 5900
23884 jdk.jcmd/sun.tools.jcmd.JCmd -l
22526 Unknown
... when the debugger starts with the "run" command
23922 jdk.jcmd/sun.tools.jcmd.JCmd -l
23771 jdk.jdi/com.sun.tools.example.debug.tty.TTY -attach 5900
22526 my
We could also pull out the perfmemory set accessible step
and set it explicitly.
...
Post by David Holmes
I've been lurking on this ...
Post by g***@oracle.com
Post by Chris Plummer
Post by Gary Adams
https://bugs.openjdk.java.net/browse/JDK-8156537
- Added a fix for module naming
https://bugs.openjdk.java.net/browse/JDK-8176533
- Fixed a regression from JDK-816537 that prevented "jcmd <pid> <cmd>"
from sending <cmd> to <pid>
https://bugs.openjdk.java.net/browse/JDK-8176828
- Requests that "jcmd -l" should list the <pid>
for the VM that has not completed initialization.
This is not a regression, because jdk8 jcmd did
not display the uninitialized VM either.
It appears you can send "jcmd <pid> <cmd>" to
the process that has not completed vm initialization.
So what happens when you do this?
The commands work, albeit the vm thread is blocked waiting for the
debugger connection.
Define "work". If the VM is partially initialized there is very
little that can be examined. If the VMThread is blocked on the
debugger connection then you can't do anything that requires a VM
operation (which includes safepoints - though at this stage if there
are no JavaThreads we're safe anyway).
Thanks,
David
Post by g***@oracle.com
Post by Chris Plummer
Chris
Post by Gary Adams
Post by Chris Plummer
Sorry, meant to say "before JDK-8176533".
Chris
Post by Chris Plummer
Hi Gary,
This seems reasonable. I just want clarification on one thing
first. Before JDK-8176828, it listed the suspend=y process, but
could you do anything with it? I'm assuming no, and therefore it
makes sense not to list it at all.
thanks,
Chris
Post by Gary Adams
I'd like to close JDK-8176828 as will not fix.
https://bugs.openjdk.java.net/browse/JDK-8176828
This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.
The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.
In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.
Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.
=====
thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args,
bool* canTryAgain) {
...
thread.cpp:3610: create_vm_timer.start();
...
thread.cpp:3907: JvmtiExport::post_vm_initialized();
...
debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv
*env, jthread thread)
...
debugInit.c:103:static void initialize(JNIEnv *env, jthread
thread, EventIndex triggering_ei);
...
debugInit.c:732: (void)bagEnumerateOver(transports,
startTransport, &arg);
...
debugInit.c:751: transport_waitForConnection();
...
thread.cpp:3955: create_vm_timer.end();
====
203 void Management::record_vm_startup_time(jlong begin,
jlong duration) {
204 // if the performance counter is not initialized,
205 // then vm initialization failed; simply return.
206 if (_begin_vm_creation_time == NULL) return;
207
208 _begin_vm_creation_time->set_value(begin);
209 _end_vm_creation_time->set_value(begin + duration);
210 PerfMemory::set_accessible(true);
211 }
David Holmes
2018-12-04 04:06:51 UTC
Permalink
Hi Gary,

Somewhere in this I got the mistaken impression that it is the VMThread
that blocks waiting for the debugger to attach, but it is actually the
main thread executing create_vm. That simplifies things and addresses
the concern I had about jcmds that needed VM ops.

So IIUC the only reason we can't attach is because PerfMemory is not
"accessible" so the patch below addresses that by making it accessible
before the main thread would block. I've looked at the initialization
flow and moving the set_accessible call seems reasonable to me.

Thanks,
David
Post by Gary Adams
Here's a smaller change. I'll run through a bunch of serviceability
tests to make sure
this early accessible setting does not have any unexpected side effects..
diff --git a/src/hotspot/share/runtime/thread.cpp
b/src/hotspot/share/runtime/thread.cpp
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -3902,6 +3902,9 @@
   // may be attached late and JVMTI must track phases of VM execution
   JvmtiExport::enter_live_phase();
+  // Make perfmemory accessible
+  PerfMemory::set_accessible(true);
+
   // Notify JVMTI agents that VM initialization is complete - nop if
no agents.
   JvmtiExport::post_vm_initialized();
Post by g***@oracle.com
It turns out that almost all the diagnostic commands provide
meaningful output even though the vm thread is not totally
initialized.
We could declare the perfmemory initialized a little earlier ...
diff --git a/src/hotspot/share/runtime/thread.cpp
b/src/hotspot/share/runtime/thread.cpp
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -3902,6 +3902,9 @@
   // may be attached late and JVMTI must track phases of VM execution
   JvmtiExport::enter_live_phase();
+  // Make perfmemory accessible
+  create_vm_timer.end();
+
   // Notify JVMTI agents that VM initialization is complete - nop if
no agents.
   JvmtiExport::post_vm_initialized();
@@ -3951,7 +3954,6 @@
     }
   }
-  create_vm_timer.end();
 #ifdef ASSERT
   _vm_complete = true;
 #endif
This would be the "jcmd -l" output when the post_vm_initialized()
would block on the "suspend=y" processing
23732 jdk.jcmd/sun.tools.jcmd.JCmd -l
22526 Unknown
... when the debugger attaches "jdb -attach 5900"
23771 jdk.jdi/com.sun.tools.example.debug.tty.TTY -attach 5900
23884 jdk.jcmd/sun.tools.jcmd.JCmd -l
22526 Unknown
... when the debugger starts with the "run" command
23922 jdk.jcmd/sun.tools.jcmd.JCmd -l
23771 jdk.jdi/com.sun.tools.example.debug.tty.TTY -attach 5900
22526 my
We could also pull out the perfmemory set accessible step
and set it explicitly.
...
Post by David Holmes
I've been lurking on this ...
Post by g***@oracle.com
Post by Chris Plummer
Post by Gary Adams
https://bugs.openjdk.java.net/browse/JDK-8156537
  - Added a fix for module naming
https://bugs.openjdk.java.net/browse/JDK-8176533
  - Fixed a regression from JDK-816537 that prevented "jcmd <pid> <cmd>"
     from sending <cmd> to <pid>
https://bugs.openjdk.java.net/browse/JDK-8176828
  - Requests that "jcmd -l" should list the <pid>
     for the VM that has not completed initialization.
     This is not a regression, because jdk8 jcmd did
     not display the uninitialized VM either.
It appears you can send "jcmd <pid> <cmd>" to
the process that has not completed vm initialization.
So what happens when you do this?
The commands work, albeit the vm thread is blocked waiting for the
debugger connection.
Define "work". If the VM is partially initialized there is very
little that can be examined. If the VMThread is blocked on the
debugger connection then you can't do anything that requires a VM
operation (which includes safepoints - though at this stage if there
are no JavaThreads we're safe anyway).
Thanks,
David
Post by g***@oracle.com
Post by Chris Plummer
Chris
Post by Gary Adams
Post by Chris Plummer
Sorry, meant to say "before JDK-8176533".
Chris
Post by Chris Plummer
Hi Gary,
This seems reasonable. I just want clarification on one thing
first. Before JDK-8176828, it listed the suspend=y process, but
could you do anything with it? I'm assuming no, and therefore it
makes sense not to list it at all.
thanks,
Chris
Post by Gary Adams
I'd like to close JDK-8176828 as will not fix.
  https://bugs.openjdk.java.net/browse/JDK-8176828
This bug was originally thought to be associated with
a regression fix in JDK-8176533, but I believe there
is simply a misunderstanding of how the "suspend=y"
behavior is supported for the jdwp agent library.
The "suspend=y" setting is designed to maximize the number
of events that can been seen by an attaching debugger.
This calls for the process to be waiting for the debugger connection
before the VM has been completely initialized.
In particular, the thread.cpp create_vm() function causes the
debugInit.c initialize() function to start the transport connection
and wait for an external debugger to attach. Once the dt_socket connection
is established the create_vm() function will complete. It is the
processing of the create_vm_timer.end() that results in the
management.cpp record_vm_startup_time() and the
PerfMemory::set_accessible(true) to be set.
Without the accessible field being set an external program can not use
the PerfMemory. That is why "jcmd -l" passes over processes which
do not have an initialized VM running.
=====
  thread.cpp:3587:jint Threads::create_vm(JavaVMInitArgs* args,
bool* canTryAgain) {
  ...
  thread.cpp:3610:  create_vm_timer.start();
  ...
  thread.cpp:3907: JvmtiExport::post_vm_initialized();
  ...
    debugInit.c:432:cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv
*env, jthread thread)
    ...
    debugInit.c:103:static void initialize(JNIEnv *env, jthread
thread, EventIndex triggering_ei);
    ...
    debugInit.c:732: (void)bagEnumerateOver(transports,
startTransport, &arg);
    ...
    debugInit.c:751:    transport_waitForConnection();
  ...
  thread.cpp:3955:  create_vm_timer.end();
====
   203  void Management::record_vm_startup_time(jlong begin,
jlong duration) {
   204    // if the performance counter is not initialized,
   205    // then vm initialization failed; simply return.
   206    if (_begin_vm_creation_time == NULL) return;
   207
   208 _begin_vm_creation_time->set_value(begin);
   209    _end_vm_creation_time->set_value(begin + duration);
   210    PerfMemory::set_accessible(true);
   211  }
Loading...