On 7/2/20 7:14 PM, Yasumasa Suenaga wrote:
Hi Dan,
Thanks for your comment!
On 2020/07/03 7:16, Daniel D. Daugherty wrote:
On 7/2/20 5:19 AM, Yasumasa Suenaga wrote:
Hi David,
I upload new webrev. Could you review again?
http://cr.openjdk.java.net/~ysuenaga/JDK-8242428/webrev.03/
src/hotspot/share/prims/jvmtiEnv.cpp
L1542: // Get stack trace with handshake
nit - please add a period at the end.
I will fix it.
L1591: *stack_info_ptr = op.stack_info();
The return parameter should not be touched unless the return
code in 'err' == JVMTI_ERROR_NONE.
old L1582: if (err == JVMTI_ERROR_NONE) {
Please restore this check. The return parameter should not
be touched unless the return code in 'err' == JVMTI_ERROR_NONE.
I will fix it.
L1272: if (!jt->is_exiting() && (thread_oop != NULL)) {
nit - extra parens around the second expression.
I will fix it.
src/hotspot/share/prims/jvmtiEnvBase.cpp
old L1532: _result = JVMTI_ERROR_THREAD_NOT_ALIVE;
This deletion of the _result field threw me for a minute and
then
I figured out that the field is init to
JVMTI_ERROR_THREAD_NOT_ALIVE
in the constructor.
L1553: if (!jt->is_exiting() && (jt->threadObj() != NULL)) {
nit - extra parens around the second expression.
I will fix it.
src/hotspot/share/prims/jvmtiEnvBase.hpp
No comments.
src/hotspot/share/runtime/vmOperations.hpp
No comments.
test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/GetThreadListStackTraces.java
No comments.
test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java
L64: startSignal.countDown();
I was expecting this to be a call to await() instead of
countDown(). What am I missing here?
I think this test might be passing by accident right now,
but...
Main thread (which call JVMTI functions to test) should wait until
test thread is ready.
So main thread would wait startSignal, and test thread would count down.
That's my point. L64 is the main thread so it should be a call to
startSignal.await().
test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/libGetThreadListStackTraces.c
L92: jthreads = (jthread *)malloc(sizeof(jthread) * num_threads);
You don't check for malloc() failure.
'jthreads' is allocated but never freed.
I will fix it.
test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/libOneGetThreadListStackTraces.c
L91: result = (*jvmti)->SuspendThread(jvmti, thread);
Why are you suspending the thread? GetAllStackTraces() and
GetThreadListStackTraces() do not require the target thread(s)
to be suspend.
If you decide not to SuspendThread, then you don't need the
AddCapabilities or the ResumeThread calls.
Test thread might not be entered following code (stopSignal.await()).
We might see deferent call stack between GetAllStackTraces() and
GetThreadListStackTraces(). We cannot control to freeze call stack of
test thread in Java code.
(I didn't use SuspendThread() at first, but I saw some errors which
causes in above.)
So we need to call SuspendThread() to ensure we can see same call stack.
That sounds like a good reason. Please add a comment near the
SuspendThread()
call so that other readers won't wonder...
Dan
Thanks,
Yasumasa
Dan
On 2020/07/02 15:05, David Holmes wrote:
Hi Yasumasa,
On 1/07/2020 11:53 am, Yasumasa Suenaga wrote:
Hi,
I uploaded new webrev. Could review again?
http://cr.openjdk.java.net/~ysuenaga/JDK-8242428/webrev.02/
Updates look fine - thanks.
One minor nit:
1274 _collector.allocate_and_fill_stacks(1);
1275 _collector.set_result(JVMTI_ERROR_NONE);
In the other places where you use _collector you rely on result
being initialized to JVMTI_ERROR_NONE, rather than setting it
directly after allocate_and_fill_stacks().
Fixed.
src/hotspot/share/prims/jvmtiEnvBase.cpp
820 assert(SafepointSynchronize::is_at_safepoint() ||
821 java_thread->is_thread_fully_suspended(false,
&debug_bits) ||
822 current_thread ==
java_thread->active_handshaker(),
823 "at safepoint / handshake or target thread is
suspended");
I don't think the suspension check is necessary, as even if
the target is suspended we must still be at a safepoint or in
a handshake with it. Makes me wonder if we used to allow a
racy stacktrace operation on a suspended thread, assuming it
would remain suspended?
This function (JvmtiEnvBase::get_stack_trace()) can be called to
get own stack trace. For example, we can call GetStackTrace() for
current thread at JVMTI event.
So I changed assert as below:
```
820 assert(current_thread == java_thread ||
821 SafepointSynchronize::is_at_safepoint() ||
822 current_thread == java_thread->active_handshaker(),
823 "call by myself / at safepoint / at handshake");
```
Yep good catch. I hope current tests caught that.
They would be tested in
vmTestbase/nsk/jvmti/GetStackTrace/getstacktr001/ (own call stacks),
and getstacktr003 (call stacks in other thread).
Speaking of tests ...
In the native code I think you need to check the success of all JNI
methods that can throw exceptions - otherwise I believe the tests
may trigger warnings if -Xcheck:jni is used with them. See for
example:
test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.cpp
I updated testcases to check JNI and JVMTI function calls.
In the Java code the target thread:
45 public void run() {
46 try {
47 synchronized (lock) {
48 lock.wait();
49 System.out.println("OK");
50 }
is potentially susceptible to spurious wakeups. Using a
CountDownLatch would be robust.
Fixed.
Thanks,
Yasumasa
Thanks,
David
-----
Thanks,
Yasumasa
On 2020/07/01 8:48, David Holmes wrote:
Hi Yasumasa,
On 1/07/2020 9:05 am, Yasumasa Suenaga wrote:
Hi David,
1271 ResourceMark rm;
IIUC at this point the _calling_thread is the current thread,
so we can use:
ResourceMark rm(_calling_thread);
If so, we can call make_local() in L1272 without JavaThread (or
we can pass current thread to make_local()). Is it right?
```
1271 ResourceMark rm;
1272
_collector.fill_frames((jthread)JNIHandles::make_local(_calling_thread,
thread_oop),
1273 jt, thread_oop);
```
Sorry I got confused, _calling_thread may not be the current
thread as we could be executing the handshake in the target
thread itself. So the ResourceMark is correct as-is (implicitly
for current thread).
The argument to fill_frames will be used in the jvmtiStackInfo
and passed back to the _calling_thread, so it must be created via
make_local(_calling_thread, ...) as you presently have.
Thanks,
David
Thanks,
Yasumasa
On 2020/07/01 7:05, David Holmes wrote:
On 1/07/2020 12:17 am, Yasumasa Suenaga wrote:
Hi David,
Thank you for reviewing! I will update new webrev tomorrow.
466 class MultipleStackTracesCollector : public StackObj {
498 class VM_GetAllStackTraces : public VM_Operation {
499 private:
500 JavaThread *_calling_thread;
501 jint _final_thread_count;
502 MultipleStackTracesCollector _collector;
You can't have a StackObj as a member of another class like
that as it may not be on the stack. I think
MultipleStackTracesCollector should not extend any allocation
class, and should always be embedded directly in another class.
I'm not sure what does mean "embedded".
Is it ok as below?
```
class MultipleStackTracesCollector {
:
}
class GetAllStackTraces : public VM_Operation {
private:
MultipleStackTracesCollector _collector;
}
```
Yes that I what I meant.
Thanks,
David
-----
Thanks,
Yasumasa
On 2020/06/30 22:22, David Holmes wrote:
Hi Yasumasa,
On 30/06/2020 10:05 am, Yasumasa Suenaga wrote:
Hi David, Serguei,
I updated webrev for 8242428. Could you review again?
This change migrate to use direct handshake for
GetStackTrace() and GetThreadListStackTraces() (when
thread_count == 1).
http://cr.openjdk.java.net/~ysuenaga/JDK-8242428/webrev.01/
This looks really good now! I only have a few nits below.
There is one thing I don't like about it but it requires a
change to the main Handshake logic to address - in
JvmtiEnv::GetThreadListStackTraces you have to create a
ThreadsListHandle to convert the jthread to a JavaThread, but
then the Handshake::execute_direct creates another
ThreadsListHandle internally. That's a waste. I will discuss
with Robbin and file a RFE to have an overload of
execute_direct that takes an existing TLH. Actually it's
worse than that because we have another TLH in use at the
entry point for the JVMTI functions, so I think there may be
some scope for simplifying the use of TLH instances - future
RFE.
---
src/hotspot/share/prims/jvmtiEnvBase.hpp
451 GetStackTraceClosure(JvmtiEnv *env, jint start_depth,
jint max_count,
452 jvmtiFrameInfo* frame_buffer,
jint* count_ptr)
453 : HandshakeClosure("GetStackTrace"),
454 _env(env), _start_depth(start_depth),
_max_count(max_count),
455 _frame_buffer(frame_buffer), _count_ptr(count_ptr),
456 _result(JVMTI_ERROR_THREAD_NOT_ALIVE) {
Nit: can you do one initializer per line please.
This looks wrong:
466 class MultipleStackTracesCollector : public StackObj {
498 class VM_GetAllStackTraces : public VM_Operation {
499 private:
500 JavaThread *_calling_thread;
501 jint _final_thread_count;
502 MultipleStackTracesCollector _collector;
You can't have a StackObj as a member of another class like
that as it may not be on the stack. I think
MultipleStackTracesCollector should not extend any allocation
class, and should always be embedded directly in another class.
481 MultipleStackTracesCollector(JvmtiEnv *env, jint
max_frame_count) {
482 _env = env;
483 _max_frame_count = max_frame_count;
484 _frame_count_total = 0;
485 _head = NULL;
486 _stack_info = NULL;
487 _result = JVMTI_ERROR_NONE;
488 }
As you are touching this can you change it to use an
initializer list as you did for the HandshakeClosure, and
please keep one item per line.
---
src/hotspot/share/prims/jvmtiEnvBase.cpp
820 assert(SafepointSynchronize::is_at_safepoint() ||
821 java_thread->is_thread_fully_suspended(false,
&debug_bits) ||
822 current_thread ==
java_thread->active_handshaker(),
823 "at safepoint / handshake or target thread is
suspended");
I don't think the suspension check is necessary, as even if
the target is suspended we must still be at a safepoint or in
a handshake with it. Makes me wonder if we used to allow a
racy stacktrace operation on a suspended thread, assuming it
would remain suspended?
1268 oop thread_oop = jt->threadObj();
1269
1270 if (!jt->is_exiting() && (jt->threadObj() != NULL)) {
You can use thread_oop in line 1270.
1272
_collector.fill_frames((jthread)JNIHandles::make_local(_calling_thread,
thread_oop),
1273 jt, thread_oop);
It is frustrating that this entire call chain started with a
jthread reference, which we converted to a JavaThread, only
to eventually need to convert it back to a jthread! I think
there is some scope for simplification here but not as part
of this change.
1271 ResourceMark rm;
IIUC at this point the _calling_thread is the current thread,
so we can use:
ResourceMark rm(_calling_thread);
---
Please add @bug lines to the tests.
I'm still pondering the test logic but wanted to send this now.
Thanks,
David
-----
VM_GetThreadListStackTrace (for GetThreadListStackTraces)
and VM_GetAllStackTraces (for GetAllStackTraces) have
inherited VM_GetMultipleStackTraces VM operation which
provides the feature to generate jvmtiStackInfo. I modified
VM_GetMultipleStackTraces to a normal C++ class to share
with HandshakeClosure for GetThreadListStackTraces
(GetSingleStackTraceClosure).
Also I added new testcases which test
GetThreadListStackTraces() with thread_count == 1 and with
all threads.
This change has been tested in serviceability/jvmti
serviceability/jdwp vmTestbase/nsk/jvmti vmTestbase/nsk/jdi
vmTestbase/nsk/jdwp.
Thanks,
Yasumasa
On 2020/06/24 15:50, Yasumasa Suenaga wrote:
Hi all,
Please review this change:
JBS: https://bugs.openjdk.java.net/browse/JDK-8242428
webrev:
http://cr.openjdk.java.net/~ysuenaga/JDK-8242428/webrev.00/
This change replace following VM operations to direct
handshake.
- VM_GetFrameCount (GetFrameCount())
- VM_GetFrameLocation (GetFrameLocation())
- VM_GetThreadListStackTraces (GetThreadListStackTrace())
- VM_GetCurrentLocation
GetThreadListStackTrace() uses direct handshake if thread
count == 1. In other case (thread count > 1), it would be
performed as VM operation (VM_GetThreadListStackTraces).
Caller of VM_GetCurrentLocation
(JvmtiEnvThreadState::reset_current_location()) might be
called at safepoint. So I added safepoint check in its caller.
This change has been tested in serviceability/jvmti
serviceability/jdwp vmTestbase/nsk/jvmti vmTestbase/nsk/jdi
vmTestbase/ns
k/jdwp.
Also I tested it on submit repo, then it has execution
error
(mach5-one-ysuenaga-JDK-8242428-20200624-0054-12034717) due
to dependency error. So I think it does not occur by this
change.
Thanks,
Yasumasa